intervals query 允许用户精确控制查询词在文档中出现的先后关系,实现了对terms顺序、terms之间的距离以及它们之间的包含关系的灵活控制
1、介绍
为了更加简单灵活的控制查询时字符串在文本中匹配的距离与先后顺序,官方在es7.0引入了intervals query,用户可单一或者组合多个规则集合在某一个特定的text field上进行操作。
例如,我们用“my favourite food”这样一个字符串在my_text field里进行intervals查询,查询规则是该字符串出现在"hot water"或者“cold porridge”字符串的前面,那么query语句可以这样来写:
POST _search
{
"query": {
"intervals" : {
"my_text" : {
"all_of" : {
"ordered" : true,
"intervals" : [
{
"match" : {
"query" : "my favourite food",
"max_gaps" : 0,
"ordered" : true
}
},
{
"any_of" : {
"intervals" : [
{ "match" : { "query" : "hot water" } },
{ "match" : { "query" : "cold porridge" } }
]
}
}
]
},
"boost" : 2.0,
"_name" : "favourite_food"
}
}
}
}
简要概述上面语句,像包含“my favourite food is cold porridge”这样字符串的文档就会被检索到,因为“my favourite food ”出现在“cold porridge”前面,满足intervals query语法规则;另一个只包含了“when it's cold my favourite food is porridge ”字符串的文档就不会被匹配到,因为“cold” 和“porridge”出现在了“my favourite food”两边,不符合我们配置的intervals query语法规则。
2、参数
- match
参数 | 描述 |
---|---|
query | 用户查询的字符串 |
max_gaps | 字符串中每个词在text field中出现的最大词间距,超过最大间距的将不会被检索到;默认值是-1,即不限制,设置为0的话,query中的字符串必须彼此相连不能拆分 |
ordered | query中的字符串是否需要有序显示,默认值是false,即不考虑先后顺序 |
analyzer | 对query参数中的字符串使用什么分词器,默认使用mapping时该field配置的 search analyzer |
filter | 可以为query搭配一个intervals filter,该filter不同于Boolean filter 有自己的语法结构 |
- all_of
参数 | 描述 |
---|---|
intervals | 一个interval集合,集合里面的所有match需要同时在一个文档数据上同时满足才行 |
max_gaps | 多个interval查询在一个文档中允许的最大间距,超过最大间距的将不会被检索到;默认值是-1,即不限制,设置为0的话,所有的interval query必须彼此相连不能拆分 |
ordered | 配置 intervals 出现的先后顺序,默认值false |
filter | 可以为query搭配一个intervals filter,该filter不同于Boolean filter 有自己的语法结构 |
- any_of
参数 | 描述 |
---|---|
intervals | 一个interval集合,集合里面的所有match不需要同时在一个文档数据上同时满足 |
filter | 可以为query搭配一个intervals filter |
-
filters
match query filter,不是严格的查询过滤器,不同于Boolean filter ,有自己的语法结构.我们先看一个例子,假设我们要在my_text field上查询包含“hot”和“porridge”的文档,要求这两个词的词距不超过10个字符,且文档中不包含“ salty”,以下是查询语句:
POST _search
{
"query": {
"intervals" : {
"my_text" : {
"match" : {
"query" : "hot porridge",
"max_gaps" : 10,
"filter" : {
"not_containing" : {
"match" : {
"query" : "salty"
}
}
}
}
}
}
}
}
参数说明:
参数 | 描述 |
---|---|
containing | interval query中terms之间需要包含filter中的terms |
contained_by | interval query中的字符串需要被包含在filter query的terms里 |
not_containing | containing 对立面 |
not_contained_by | contained_by 对立面包 |
not_overlapping | query 与filter 词距不重叠 |
-
script filters
如果上面filters语句不能满足你的需求,那么可以尝试一下script filter ,它提供了一个interval变量,通过start、end、gaps三个函数更加灵活的控制term在文本中的顺序与距离:
POST _search
{
"query": {
"intervals" : {
"my_text" : {
"match" : {
"query" : "hot porridge",
"filter" : {
"script" : {
"source" : "interval.start > 10 && interval.end < 20 && interval.gaps == 0"
}
}
}
}
}
}
}
3、Minimization
itervals query 会优化最小化间距,使得查询性能保持在一个线性可控的范围内;itervals query有时候会出现意想不到的查询结果,尤其是在使用了max_gaps来限制查询间距,例如查询包含salty 但必须出现在hot porridge词间:
POST _search
{
"query": {
"intervals" : {
"my_text" : {
"match" : {
"query" : "salty",
"filter" : {
"contained_by" : {
"match" : {
"query" : "hot porridge"
}
}
}
}
}
}
}
}
上面的查询不会匹配“hot porridge is salty porridge”,因为这两个term只是在文档中出现而没有覆盖salty。
还有另外一种情况,是在使用 any_of 时,如果包含了多个interval,且其中一个短语是另一个的前缀,那么较长的哪个interval将不会工作,例如查询“the”,后面需要紧跟“big”或“big dad”,最后紧跟“wolf”:
POST _search
{
"query": {
"intervals" : {
"my_text" : {
"all_of" : {
"intervals" : [
{ "match" : { "query" : "the" } },
{ "any_of" : {
"intervals" : [
{ "match" : { "query" : "big" } },
{ "match" : { "query" : "big bad" } }
] } },
{ "match" : { "query" : "wolf" } }
],
"max_gaps" : 0,
"ordered" : true
}
}
}
}
}
这个查询不会匹配到包含“the big bad wolf”内容的文档,在一个intervals组合规则里“big”是“big bad”的前缀,所以“big bad”被最小化了,如果想实现该效果,需要进行query重写,如:
POST _search
{
"query": {
"intervals" : {
"my_text" : {
"any_of" : {
"intervals" : [
{ "match" : {
"query" : "the big bad wolf",
"ordered" : true,
"max_gaps" : 0 } },
{ "match" : {
"query" : "the big wolf",
"ordered" : true,
"max_gaps" : 0 } }
]
}
}
}
}
}