广电智能推荐点播系统实践5-ElasticSearch实践

广电智能推荐点播系统实践5-ElasticSearch实践

ElasticSearch有很多优点,比如分布式支持海量数据,同时响应超快,自动索引功能免去了很多数据库维护工作,还有全文搜索、自然语言处理等等。 非常完美的满足了推荐系统的搜索、存储和匹配分析功能。

ElasticSearch有完善的文档,2.x版本还有官方中文版本权威指南
最新的5.6版本也有相应的英文文档reference

本文不对ES介绍,只列出本人实践问题

index type id 和传统sql库如何对应?

传统sql结构是 库、表、条目三级,ES也正好有index type id 三级,是否能一一对应呢?

实践以后发现,完全不是那么回事。原因在于index对于同一个field,只能拥有唯一的mapping,相当于同一个index下面,条目的字段名称只能有一种类型。
另一个原因在于index的维护,配置mapping需要所有的field,如果把index当成一个库来看,type是表,配置文件将是超级大的,上千行是小意思。

最终我选择做这样的对应 sql表:index ,sql条目:id 。
这样同样带来两个问题:
1.那ES如何分库?我的做法是讲index名加库名前缀。
2.ES的type做什么用? 举个例子,用户点播历史记录是一个index:log,前端需要显示用户点播记录,同时点播资源必须可用。 如果使用log索引,聚合(类似分类)点播资源名称,然后查询聚合后的点播资源是否可用,只将可用的返回给前端。 这样做会带来诸多问题,首先cpu负载上升,其次聚合后删除条目,带来分页问题。
比较好的做法是,起一个服务,定时生成log_valid 索引。log_valid和log在字段上又基本一致。所以我只建一个log,用total和valid两种type进行区分。 看起来type总算有用了。
其实index和type设计,用的最多的是用时间后缀进行分表和分类,特别是做日志收集工作的ES。

index不做mapping设计可以吗?

答案当然是否定的。虽然ES的文档里特别炫耀了直接PUT数据,就能创建index的神技。你如果真这么做,就等着炸吧。
自动index特别不适合中日韩语系数据,文本直接被mapping成如下类型:

"title" : {
        "type" : "text",
        "fields" : {
          "simple" : {
            "type" : "text",
            "analyzer" : "keyword"
          }
        }
      }

看到text类型,同时没指定分析器的时候要小心了,这时候使用的是默认分析器,汉字直接按字分词,然后创建ES索引,遇到文字比较多的,比如评论、简介,硬盘消耗非常快,CPU负载也会很高。

index 一定要用别名

ES文档里说到,再完美的库也会有修改的那天。 而ES直接修改已经建立的库,会导致很多问题。一句话别想了。那又想不暂停服务,怎么整?用别名吧。
步骤如下

#log1索引取一个别名
curl -XPUT 'localhost:9200/log1/_alias/log?pretty'
#TODO 创建新的log2索引
#把log1的数据导入到log2中
curl -XPOST 'localhost:9200/_reindex?pretty' -H 'Content-Type: application/json' -d'
{
  "source": {
    "index": "log1"
  },
  "dest": {
    "index": "log2"
  }
}'
#删除log1别名,增加log2别名到log
curl -XPOST 'localhost:9200/_aliases?pretty' -H 'Content-Type: application/json' -d'
{
    "actions": [
        { "remove": { "index": "log1", "alias": "log" }},
        { "add":    { "index": "log2", "alias": "log" }}
    ]
}'
#最后删除log1索引
curl -XDELETE 'localhost:9200/log1?pretty'

python接口实例

本人基于5.5版本开发,所以使用了官方基础库,5.6版本开始支持官方高级库。

from elasticsearch import Elasticsearch
def getright(request):
    search_json = {
        "size": 1,
        "from": 0,
        "query": {
            "constant_score": {
                "filter": {
                    "bool": {
                        "should": [
                            {"match": {"title1.simple": "国民大生活"}},
                            {"match": {"title2.simple": "国民大生活"}}
                        ]
                    }
                }
            }
        }
    }
    es = Elasticsearch('172.19.0.1:9200')
        search_json['query']['constant_score']['filter']['bool']['should'][0]['match']['title1.simple'] = title
        search_json['query']['constant_score']['filter']['bool']['should'][1]['match']['title1.simple'] = title
        res = es.search(index="medialib", doc_type="total", body=search_json)
        # if hits ,update current movie with xx informations of first hits documents
        if res['hits']['total'] > 0:

基础的python接口不好的一点,就是太基础了,查询语句完全需要自己写,非常容易出错。
替换参数的时候,json层级很深,也非常容易出错。

其他需要注意的就是,es连接不是curl,是长连接。 千万不要sleep以后再调用es链接变量。

mapping备份

没什么好的方法,直接存成文件,下次创建的时候copy一下即可。如下:

curl -XPUT 'localhost:9200/manual1?pretty' -H 'Content-Type: application/json' -d'
{
"mappings" : {
  "channel" : {
    "properties" : {
      "channel_id" : {
        "type" : "keyword"
      },
      "channel_name" : {
        "type" : "keyword"
      },
      "desc" : {
        "type" : "keyword"
      },
      "title" : {
        "type" : "text",
        "fields" : {
          "simple" : {
            "type" : "text",
            "analyzer" : "simple"
          }
        }
      },
      "type" : {
        "type" : "keyword",
        "fields" : {
          "simple" : {
            "type" : "text",
            "analyzer" : "simple"
          }
        }
      }
    }
  }
}
}
'

分析器选哪个?

最基本的根据语言来选择分析器,还要看具体应用,比如,推荐系统中对title的分析器,就不能使用ik中文分析器,不然它把影视作品的名字分的乱七八糟。 不过这也不是绝对的。 后期,我可能通过扩展ik的方式,回归到ik分词,毕竟自己写一个合适的太耗费精力。

docker化

刚开始用docker-es的时候,听到最多的就是 ,天啊,你竟然用docker。 绝大部分人认为es不适合跑在docker里。 从各种资讯来看,甚至是官方,也是推荐物理机。
不过我的任务轻,无所谓啦。用了下,还是不错的,记得存储要挂载哦 ,方便备份。
官方文档有version 2的yml版本,新版本的docker只能用version 3 的,这个要注意一下。

备份

目前都是文件拷贝,什么snapshot 第三方统统没用。 遗憾的是,文件拷贝需要停机,不然考出来的数据不能用了,具体为什么,就不深究了。
上面说了要停机才能备份存储文件。 所以,ES工作的时候,直接复制虚拟机也是不行的,复制以后还是起不来。
后面还是要不停机备份,待系统上线再说吧。大家有什么好的方法也可以告诉我。

先写到这里,后面想到什么 遇到什么,会再来补充。

你可能感兴趣的:(智能推荐)