ES - 中文分词及高亮搜索

2017-09-05  本文已影响776人  君剑

包括内容:

IK分词组件的添加和配置

索引建立及高亮搜索示例

添加自定义分词的测试

版本: 

ES - 2.4.5, IK - 1.10.5 
ps: 5.0的版本, 配置和验证代码都不是太一样, 以下应该只适用于2.x版本

IK Analyzer是一个开源的, 基于java语言开发的轻量级的中文分词工具包, 应该是目前比较公认的适合ES的中文分词方案, 因为它默认实现了针对luence的优化. 下面会先介绍安装配置方法, 再介绍应用. 

Analyzer:ik_smart,ik_max_word, Tokenizer:ik_smart,ik_max_word

这里假设我们已经配置好了ES集群 [这个确实很简单, 因为es的默认配置就已经很好]

推荐使用rpm的安装方式:

一 下载对应的IK版本
https://github.com/medcl/elasticsearch-analysis-ik

二 下载pre-build, 或者自行编译

工程是pom, 需要安装maven,
git clone https://github.com/medcl/elasticsearch-analysis-ik
cd elasticsearch-analysis-ik
git checkout tags/{version}
mvn clean
mvn compile
mvn package

我其实是直接下载的pre-build, elasticsearch-analysis-ik-1.10.5.zip

三 配置

First, 解压elasticsearch-analysis-ik-1.10.5.zip, 拷贝到plugins/analysis-ik下, 如果是rpm安装的, 则对应的目录为/usr/share/elasticsearch/plugins/analysis-ik

Second, 修改elasticsearch的配置文件,指定IK为分词工具。打开/etc/elasticsearch/elasticsearch.yml, 最后添加 [这不应该也不用做, 我有两个节点没做也是没问题的, 所以官方文档是对的]:

    index.analysis.analyzer.default.type: ik

Last, 词典. 看到很多人写的安装引导都提到了将词典拷贝到es的config目录, 亲测这一步是不需要的. 

验证: 最好还是用浏览器直接验证, 命令行的话还需要处理编码问题

(虽然, 官方说明说在某个索引下调用接口测试, 如果是单点测试的话, 其实没什么差异, 但是要是集群的话指定的index决定了在哪个节点执行)

http://localhost:9200/ik_index/_analyze?text=我是中国人&tokenizer=ik&pretty=true
http://localhost:9200/_analyze?analyzer=ik&pretty=true&text=我是中国人

analyzer目前支持两种, ik_max_word和ik_smart, 他们的区别在于分词的粒度

ik_max_word: "我是中国人" --> "我, 中国人, 中国, 国人"

ik_smart: "我是中国人" --> "我, 中国人"

官方文档分词测试验证: 

PS: 个人比较喜欢kopf这个插件, 简洁, 清晰, 

1 创建ik_index

PUT http://localhost:9200/ik_index

2 创建mapping

POST http://localhost:9200/ik_index/fulltext/_mapping -d'
{
"fulltext":
      {"_all": {
         "analyzer": "ik_max_word",
         "search_analyzer": "ik_max_word",
         "term_vector": "no","store": "false"
      },
        "properties": {
               "content": {
                    "type": "string",
                    "store": "no",
                    "term_vector": "with_positions_offsets",
                    "analyzer": "ik_max_word",
                    "search_analyzer": "ik_max_word",
                    "include_in_all": "true",
                    "boost": 8}}
}}'

3 index some docs

curl -XPOST http://localhost:9200/ik_index/fulltext/1 -d'{"content":"美国留给伊拉克的是个烂摊子吗"}'

curl -XPOST http://localhost:9200/ik_index/fulltext/2 -d'{"content":"公安部:各地校车将享最高路权"}'

curl -XPOST http://localhost:9200/ik_index/fulltext/3 -d'{"content":"中韩渔警冲突调查:韩警平均每天扣1艘中国渔船"}'

curl -XPOST http://localhost:9200/ik_index/fulltext/4 -d'{"content":"中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"}'

4 query with highlighting

curl -XPOST http://localhost:9200/ik_index/fulltext/_search  -d'
{
"query" :{ "term" : { "content" : "中国" }},
"highlight" : {"pre_tags" : ["", ""],
"post_tags" : ["", ""],
"fields" : {"content" : {}}}
}'

result:

Dictionary Configuration:

IKAnalyzer.cfg.xml can be located at{conf}/analysis-ik/config/IKAnalyzer.cfg.xml or {plugins}/elasticsearch-analysis-ik-*/config/IKAnalyzer.cfg.xml

热更新 IK 分词使用方法

目前该插件支持热更新 IK 分词,通过上文在 IK 配置文件中提到的如下配置

其中location是指一个 url,比如http://yoursite.com/getCustomDict,该请求只需满足以下两点即可完成分词热更新。

1. 该 http 请求需要返回两个头部(header),一个是Last-Modified,一个是ETag,这两者都是字符串类型,只要有一个发生变化,该插件就会去抓取新的分词进而更新词库。

2. 该 http 请求返回的内容格式是一行一个分词,换行符用\n即可。

满足上面两点要求就可以实现热更新分词了,不需要重启 ES 实例。

可以将需自动更新的热词放在一个 UTF-8 编码的 .txt 文件里,放在 nginx 或其他简易 http server 下,当 .txt 文件修改时,http server 会在客户端请求该文件时自动返回相应的 Last-Modified 和 ETag。可以另外做一个工具来从业务系统提取相关词汇,并更新这个 .txt 文件。

添加分词测试:

公司名称叫小鱼易连, 小鱼是可以被识别成一个词的, 但是易连就不认了, 效果如下

localhost:9200/_analyze?analyzer=ik&pretty=true&text=小鱼易连

这可不是我期望的, 用户在搜产品文档的时候输入"易连"找不到结果可不行, 其实很简单, 有两种方法:

一个是根据上面提到的热更新方法, 通过插件自动抓取扩展词典的变化更新词库. 

另外一个, 我们可以快速验证, 通过更改config/custom下的mydict.dic, 在文件结尾添加"易连"即可, 不过需要重启服务加载词库.效果如下:

可以看到, 文档6的得分明显高于文档5, 您可以用5秒钟思考一下为什么.

及时只搜索"易连", 文档6同样相关度更高

答案是, 文档6在索引时, 添加了"小鱼易连"这个分词, 关于这个评分, 因为会做一个站内搜索功能, 以后会单独分享一次, 包括高亮的介绍.

上一篇下一篇

猜你喜欢

热点阅读