内容为个人学习心得,不能对准确性做过多保证,错误之处还望指点。
以下演示内容基于elasticsearch6.3.1
首先,我们需要知道term和token的区别:
token:
使用 _analyse
API对字符串进行拆词解析时,会得到包含start_offset、position等字段的token信息,在我理解中,所谓token,就是拆出的一个个词条记录,并且包含了其在对应字段中的位置、长度等信息
term:
使用_search
API执行查询操作时,可在query节点中指定term内容,此处的term,包含了字段名称和对应的查询字符串,在lucene-core.jar包中可以查到,对应的Term类注释如下:
即“单个词条”的查询单元,虽然要求传入的是字符串,但是可用在查询dates、email、url等字段上。
注意:此处的“单个”很重要,代表了传入的内容不会经过analyzer的拆分,而是作为一个完整的词条去做查询匹配,哪怕你传入的是包含了空格的多个词
接着看看在
_search
API中的效果比较,此处只分析字段类型为text的情况;
为了方便,我们准备一个测试索引做分析,使用了english的analyzer:
//首先创建测试索引,指定其中text类型字段的analyzer为english
PUT /test/
{
"mappings": {
"_doc":{
"properties":{
"name":{
"type": "text",
"analyzer": "english"
}
}}
}
}
//测试一下拆词效果
GET test/_analyze
{
"field": "name",
"text": "eating a apple a day"
}
//可以看到拆成了eat appl dai 三个词条
//插入一条数据
PUT /test/_doc/1
{
"name":"eating a apple a day"
}
term、match和match_phrase比较
注意:在上面的拆词测试结果中,我们得到了
eat
appl
dai
三个词条
- term
//查询语法
get test/_search
{
"query":{
"term": {
"name": "xxx"
}
}
}
由于term查询时传入的内容不会被拆词处理,所以它会被当成一个完成的词条去跟对应字段已经拆分出的词条去做比较,所以如果我们做如下尝试,分别得到的结果是:
- eats : 0匹配
- ea : 0匹配
- eat : 1匹配
- apple : 0匹配
- appl : 1匹配
- eat appl : 0匹配
以上结果很好的证明了上述对term的观点,即两个重点:1. 不拆词 2. 与字段拆词结果词条(token)作equal比对
- match
match就不用说了,先拆词,后比对,es核心功能 - match_phrase
该查询条件期待传入一组词条,因为是phrase嘛,因此肯定会先经过analyzer拆词,它与match的区别在于,它会严格按传入内容拆出词条结果的内容+顺序,与源字段词条比对,完全一致才会匹配成功,因此:
- eats apples : 0匹配
- eats the apples : 1匹配
- eat appl : 0匹配 (少了a,所以词条的顺序就对不上了)
- match_phrase_prefix
顺便提下match_phrase_prefix,理解了match_phrase,它就不难了,其他处理过程都一样,带个_prefix的意思是,传入的查询内容拆得的词条,在顺序与源字段词条一致的情况下,只要词条内容前缀匹配成功就算ok,因此:
- eats apples : 0匹配
- eats the apples : 1匹配
- eat appl : 0匹配
- e a a : 1匹配(有点过分了,但因为e和eat匹配,第二个a和appl匹配,所以就成功了)