本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.
Elasticsearch Mapping字段类型之text 以及term、match和analyzer
一、text场景
text
类型是适合全文搜索
的场景,ES会将文本分析成多个词并索引。
text
类型适合存放易阅读的
(human-readable)非结构化
文本,比如邮件内容、评论、商品介绍等
对于阅读性差的文本,如系统日志、Http请求体这些machine-generated数据,可以用wildcard
类型text
类型不适合排序
和聚合
(虽然可以实现,但是不建议)
如果要进行排序
和聚合
,建议使用keyword
类型
所以可以给text
类型添加keyword子类型
和token_count子类型
,各司其职
PUT pigg_test_text { "mappings": { "properties": { "name": { # 姓名 name "type": "text", "fields": { "keyword": { # 子字段 name.keyword "type": "keyword", "ignore_above" : 256 }, "length": { # 子字段 name.length "type": "token_count", "analyzer": "standard" } } }, "tag": { # 标签 tag "type": "keyword" }, "word": { # 台词 word "type": "text" } } } }
二、term
查询
term
判断某个字段是否包含
某个确定的值。一般用在keyword
、integer
、date
、token_count
、ip
等类型上
避免在text
类型上用term
,在text
上应该用match
、match_phrase
来全文搜索
先插入两条《王者荣耀》里英雄的数据:
PUT pigg_test_text/_doc/1 { "name": "亚瑟王", "tag": ["对抗路", "打野"], "word": [ "王者背负,王者审判,王者不可阻挡" ] } PUT pigg_test_text/_doc/2 { "name": "关羽", "tag": ["对抗路", "辅助"], "word": [ "把眼光从二爷的绿帽子上移开", "聪明的人就应该与我的大刀保持安全距离" ] }
(1)查询name
是亚瑟王
的人
在name.keyword
上用term
查询,返回id=1的文档
注意:term
不是等于的意思,是包含
的意思
GET pigg_test_text/_search { "query": { "term": { "name.keyword": "亚瑟王" } } }
(2)查询可走对抗路的人
在tag
上用term
查询,返回id=1和2的文档,因为他们的tag
都包含
对抗路
GET pigg_test_text/_search { "query": { "term": { "tag": "对抗路" } } }
(3)查询是打野或辅助的人
在tag
上用terms
查询(注意多了个s),返回id=1和2的文档
因为terms
查询只要包含
数组中任意一个就算匹配
GET pigg_test_text/_search { "query": { "terms": { "tag": ["打野", "辅助"] } } }
(4)查询name
是3个字的人
在token_count
类型的name.length
上做精确匹配,返回亚瑟王
的文档
GET pigg_test_text/_search { "query": { "term": { "name.length": 3 } } }
三、match
查询
虽然上面亚瑟王
和关羽
这2个文档内容是中文,而且我也没有配置ik中文分词器
,但是这不影响我们的学习,我们只要知道中文被默认的standard analyzer
切分成独立的汉字就行了。
用match
全文搜索鼓励王
,返回亚瑟王
文档,因为匹配中了王
这个汉字。
GET pigg_test_text/_search { "query": { "match": { "name": "鼓励王" } } }
对上面这条语句不是很理解的话,我从亚瑟王
如何存储?和鼓励王
如何搜索?这2个角度的问题来解释。
1.亚瑟王
如何存储?
_termvectors term
查询id=1的文档的name字段的词条向量 GET pigg_test_text/_doc/1/_termvectors?fields=name
返回亚
、瑟
、王
这3个词,说明在倒排索引
里有类似如下的关系:
词 | 文档ID |
---|---|
亚 | 1 |
瑟 | 1 |
王 | 1 |
2.鼓励王
如何搜索?
第1种方法:使用_analyze
分析standard
这个分析器是如何分割搜索关键字的。这里得指定name
字段上search-time
的analyzer
,即search_analyzer
。
GET /_analyze { "analyzer" : "standard", "text" : "鼓励王" } 返回"鼓"、"励"、"王"这3个token
第2种方法:使用_validate
验证语句是否合法,其参数explain
(默认为true)会解释语句的执行计划
GET pigg_test_text/_validate/query?explain { "query": { "match": { "name": "鼓励王" } } }
返回结果如下,name:鼓 name:励 name:王
说明是把鼓励王
拆成3个汉字分别到name
字段上做匹配的。
"valid" : true, "explanations" : [ { "index" : "pigg_test_text", "valid" : true, "explanation" : "name:鼓 name:励 name:王" } ]
第3种方法:使用_explain
查询鼓励王
是如何匹配到id=1的文档的?这种方式的前提是我们已经知道关键词匹配到哪个文档了,想知道匹配的原因。
解释`鼓励王`为何在name字段上匹配到id=1的文档 GET /pigg_test_text/_explain/1 { "query" : { "match" : { "name" : "鼓励王" } } }
返回内容比较长,也比较复杂,因为涉及到打分机制,这里就贴一个重点:
"description" : "weight(name:王 in 0) [PerFieldSimilarity], result of:",
说明是王
这个字让鼓励王
在name
字段上匹配到id=1的文档的。
3. match的参数
match
还有2个比较重要的参:operator
和minimum_should_match
,他们可以控制match
查询的行为。
3.1 operator
上面match
查询鼓励王
的语句,其实可以写成如下:
GET pigg_test_text/_search { "query": { "match": { "message": { "query": "鼓励王", "operator": "or" } } } }
这个operater
的默认值就是or
,就是只要匹配到任意一个词,就算匹配成功。
如果要”鼓励王”这三个词全部匹配,可以设置"operator": "and"
GET pigg_test_text/_validate/query?explain=true { "query": { "match": { "name": { "query": "鼓励王", "operator": "and" } } } } 返回如下:说明这3个字都得匹配 "explanations" : [ { "index" : "pigg_test_text", "valid" : true, "explanation" : "+name:鼓 +name:励 +name:王" } ]
3.1 minimum_should_match
minimum_should_match
可以设置匹配的最小词数,不要与operator
一起使用,意思会冲突。
它可以赋值正数、负数、百分比等,但是我们常用的是设置一个正数,即指定最小匹配的词数。
指定要至少匹配成功2个字,才算文档匹配成功 GET pigg_test_text/_search { "query": { "match": { "name": { "query": "鼓励王", "minimum_should_match": "2" } } } }
4. 匹配短语 match_phrase
match_phrase
短语查询,这个会将“绿帽子”
作为一个短语整体去匹配,而不会拆成3个字
该语句返回关羽这个文档,因为他的台词包含"绿帽子" GET pigg_test_text/_search { "query": { "match_phrase": { "word": "绿帽子" } } }
查询语句的执行计划:
GET pigg_test_text/_validate/query?explain { "query": { "match_phrase": { "word": "绿帽子" } } } 返回如下: "explanations" : [ { "index" : "pigg_test_text", "valid" : true, "explanation" : "word:\"绿 帽 子\"" } ]
四、分析器 analyzer
text
类型最重要的参数就是analyzer
(分析器),它决定在index-time
(创建或更新文档)和search-time
(搜索文档)如何对文本进行分词。
analyzer
:只配置了analyzer
时,在index-time
和search-time
时,都使用analyzer
配置的分析器search_analyzer
:配置了search_analyzer
时,在search-time
时,使用search_analyzer
配置的分析器
standard
分析器是text
类型的默认分析器,它按照词边界
对文本进行分割(如英语按照空格,中文切成独立汉字)。它删除了大多数标点符号和停止词并进行小写。standard
分析器对英语这样的西方语音是大多适用的。
分析器(analyzer)的配置
包含3个重要部分,依次是character filters
、tokenizer
、token filters
每当一个文档被 ingest 节点纳入,它需要经历如下的步骤,才能最终把文档写入到ES数据库中
英文 | 中文 | analyzer配置项 | 个数 | 说明 |
---|---|---|---|---|
character filters | 字符过滤器 | char_filter | 0~n个 | 剥离html标签,转换特殊字符如& 转 and |
tokenizer | 分词器 | tokenizer | 1个 | 把文本按一定规则分割成一个个词token,比如常见的standard 、 whitespace |
token filters | 词过滤器 | filter | 0~n个 | 对上一步产生的token进行规范化。 比如转小写、删除或新增术语、同义词转换等。 |
举例:tokenizer
用simple_pattern_split
,配置按照下划线_
来分割文本。
PUT my-index-000001 { "settings": { "analysis": { "analyzer": { "my_analyzer": { "tokenizer": "my_tokenizer" } }, "tokenizer": { "my_tokenizer": { "type": "simple_pattern_split", "pattern": "_" } } } } } POST my-index-000001/_analyze { "analyzer": "my_analyzer", "text": "亚瑟王__鼓励王_可丽王" }
按照下划线_
切分后的词就是["亚瑟王", "鼓励王", "可丽王"]
。
其实我们工作中也不用配置很多,这里了解下就行,不用深究每一个选项
因为ES提供了很多开箱即用的内置analyzer
,我们可根据场景来选择
对于中文的分词,出名的有IK分词器
,拼音分词器
,可以参考我之前写的ik中文分词器+pinyin拼音分词器+同义词
Be First to Comment