参考:https://www.phpmianshi.com/?id=163
概念
分析(analysis)机制用于进行全文文本(Full Text)的分词,以建立供搜索用的反向索引。
原理
分析器的工作过程大概分成两步:
-
分词(Tokenization):根据停止词把文本分割成很多的小的token,比如
the quick fox
会被分成the
、quick
、fox
,其中的停止词就是空格,还有很多其他的停止词比如&
或者#
,大多数的标点符号都是停止词 -
归一化(Normalization):把分隔的token变成统一的形式方便匹配,比如下面几种
-
把单词变成小写,
Quick
会变成quick
-
提取词干,
foxes
变成fox
-
合并同义词,
jump
和leap
是同义词,会被统一索引成jump
-
Elasticsearch自带了一个分析器,是系统默认的标准分析器,只对英文语句做分词,中文不支持,每个中文字都会被拆分为独立的个体。
示例
想要知道某个解析器的分析结果,可以直接在ES里面进行分析,执行下面的语句就行了:
POST /_analyze { "analyzer": "standard", "text": "1 Fire's foxes" }
返回的结果是:
{ "tokens" : [ { "token" : "1", "start_offset" : 0, "end_offset" : 1, "type" : "<NUM>", "position" : 0 }, { "token" : "fire's", "start_offset" : 2, "end_offset" : 8, "type" : "<ALPHANUM>", "position" : 1 }, { "token" : "foxes", "start_offset" : 9, "end_offset" : 14, "type" : "<ALPHANUM>", "position" : 2 } ] }
返回的tokens
内部就是所有的解析结果,token
表示解析的词语部分,start_offset
和end_offset
分别表示token在原text内的起始和终止位置,type
表示类型,position
表示这个token在整个tokens列表里面的位置。
如果想在某个索引下进行分词
POST /my_index/_analyze { "analyzer": "standard", "field": "name", "text": "text文本" }
es内置分词器
-
standard:默认分词,单词会被拆分,大小会转换为小写。
-
simple:按照非字母分词。大写转为小写。
-
whitespace:按照空格分词。忽略大小写。
-
stop:去除无意义单词,比如the/a/an/is…
-
keyword:不做分词。把整个文本作为一个单独的关键词
如何让ES的某个字段既能支持精确匹配查找,也能支持模糊检索
将字段的mapping设置为如下这种即可
"properties": { "name": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }
ElasticSearch 5.0以后,string字段被拆分成两种新的数据类型:
Text:会分词,然后根据分词后的内容建立倒排索引(反向索引)
不支持聚合
keyword:不进行分词,直接直接根据字符串内容建立倒排索引(反向索引)
支持聚合
ElasticSearch字符串将默认被同时映射成text和keyword类型,将会自动创建上面的动态映射(dynamic mappings),比如上面的name字段,不做任何配置ES就会默认给他映射成两个类型。
text
格式的数据和keyword
格式的数据在存储和索引的时候差别比较大。keyword
会直接被当成整个字符串保存在文档里面,而text
格式数据,需要经过分析器解析之后,转化成结构化的文档再保存起来。比如对于the quick fox
字符串,如果使用keyword
类型,保存直接就是the quick fox
,使用the quick fox
作为关键词可以直接匹配,但是使用the
或者quick
就不能匹配;但是如果使用text
保存,那么分析器会把这句话解析成the
、quick
、fox
三个token进行保存,使用the quick fox
就无法匹配,但是单独用the
、quick
、fox
三个字符串就可以匹配。所以对于text
类型的数据的搜索需要格外注意,如果你的搜索词得不到想要的结果,很有可能是你的搜索语句有问题。
analyzer 分词器(重点)和 search_analyzer
analyzer: 插入文档时,将text类型的字段做分词然后插入倒排索引
search_analyzer:在查询时,先对要查询的text类型的输入做分词,再去倒排索引搜索
在索引时,只会去看字段有没有定义analyzer,有定义的话就用定义的,没定义就用ES预设的
在查询时,会先去看字段有没有定义search_analyzer,如果没有定义,就去看有没有analyzer,再没有定义,才会去使用ES预设的
PUT /my_index { "mappings": { "properties": { "text": { "type": "text", "fields": { "english": { "type": "text", "analyzer": "english", "search_analyzer": "english" } } } } } } #使用_analyze 测试分词器 GET my_index/_analyze { "field": "text", "text": "The quick Brown Foxes." } GET my_index/_analyze { "field": "text.english", "text": "The quick Brown Foxes." }
中文分词
下载:Github:https://github.com/medcl/elasticsearch-analysis-ik
这里需要选择和你的es版本一致的ik。我的是7.5.1
解压安装:
unzip elasticsearch-analysis-ik-7.5.1.zip -d /usr/local/elasticsearch-7.5.1/plugins/ik
重启生效
ik_max_word 和 ik_smart 什么区别?
-
ik_max_word: 会将文本做最细粒度的拆分,比如会将“*国歌”拆分为“*,中华人民,中华,华人,人民*,人民,人,民,*,共和,和,国国,国歌”,会穷尽各种可能的组合,适合 Term Query;
-
ik_smart: 会做最粗粒度的拆分,比如会将“*国歌”拆分为“*,国歌”,适合 Phrase 查询。
自定义中文词库
1.进入IKAnalyzer.cfg.xml 配置如下
<!--用户可以在这里配置自己的扩展字典 --> <entry key="ext_dict">custom.dic</entry>
2.保存后 再同级目录下建立custom.dic
[esuser@localhost config]$ cat custom.dic 6神 牛皮
3.重启es
4.测试
POST /_analyze { "analyzer": "ik_smart", "text": "6神牛皮" } # 返回 { "tokens": [{ "token": "6神", "start_offset": 0, "end_offset": 2, "type": "CN_WORD", "position": 0 }, { "token": "牛皮", "start_offset": 2, "end_offset": 4, "type": "CN_WORD", "position": 1 } ] }