ES - 中文分词及高亮搜索
包括内容:
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 配置文件中提到的如下配置
其中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在索引时, 添加了"小鱼易连"这个分词, 关于这个评分, 因为会做一个站内搜索功能, 以后会单独分享一次, 包括高亮的介绍.