1) 概念
* intervals query 允许用户精确控制查询词在文档中出现的先后关系,实现了对terms顺序、terms之间的距离以及它们之间的包含关系的灵活控制
通过intervals query(间隔搜索) 我们可以完成各个terms在于不同位置的灵活搜索
* 下面来举一个例子来说明间隔搜索的适用场景:
我们在某个索引中3个包含my_text字段的文档
文档1: {"my_text":"curry bad shooter.... "}
文档2: {"my_text":"curry good shooter....."}
文档3: {"my_text":"curry best shooter...."}
通过间隔搜索,我可以明确的表示 我不想看到curry和shooter之间存在 bad的文档
我还可以明确的表示,我必须看到curry和shooter之间 存在 某个词 的文档
我也可以明确的表示,curry必须在best之前等等一系列功能
* 例如 我不想看到curry和shooter之间存在bad,DSL如下:
{
"query": {
"intervals": {
"content": {
"match": {
"query": "curry shooter",
"ordered": true,
"filter": {
"not_containing": {
"match": {
"query": "bad"
}
}
}
}
}
}
}
}
2) 参数
* 首先来看一个略复杂的DSL语句并简单理解后学习参数
POST _search
{
"query": {
"intervals" : {
"my_text" : {
"all_of" : {
"ordered" : true,
"intervals" : [
{
"match" : {
"query" : "stephen curry",
"max_gaps" : 0,
"ordered" : true
}
},
{
"any_of" : {
"intervals" : [
{ "match" : { "query" : "best shooter" } },
{ "match" : { "query" : "cute champion" } }
]
}
}
]
},
"boost" : 2.0
}
}
}
}
简单概述上方语句,像包含"stephen curry is best shooter"或者"stephen cuury is cute champion"都会被检索到,但是 "best shooter who is stephen curry" 不会被检索到,因为我们通过ordered参数明确定义了多个intervals的顺序。
你一定看到了all_of并不解,此处简单解释,在某些时候 一个intervals无法满足我们的要求,那么我们可以编写多个intervals,将其放在all_Of内部,表示所有的intervals都要生效,同样内部可以再次嵌套,比如any_of 表示内部的多个intervals只需满足其一即可。
参数 |
描述 |
query |
用户查询的字符串 |
max_gaps |
字符串中多个词之间的的最大词间距,超过最大间距的将不会被检索到;默认值是-1,即无距离限制,设置为0的话,query中的字符串必须彼此相连不能拆分 |
ordered |
query中的字符串是否需要有序显示,默认值是false,即不考虑先后顺序,该参数推荐为true,手动控制词间位置顺序 |
analyzer |
对query参数中的字符串使用什么分词器,默认使用mapping时该field配置的 search_analyzer |
filter |
intervals独有的过滤语法,下方有说明 |
参数 |
描述 |
intervals |
一个interval集合,集合里面的所有match需要同时在一个文档数据上同时满足才行 |
max_gaps |
多个interval查询在一个文档中允许的最大间距,超过最大间距的将不会被检索到;默认值是-1,即不限制,设置为0的话,所有的interval query必须彼此相连不能拆分 |
ordered |
配置 intervals 出现的先后顺序,默认值false |
filter |
intervals独有的过滤语法,下方有说明 |
参数 |
描述 |
intervals |
一个interval集合,集合中只需满足其一即可 |
filter |
intervals独有的过滤语法,下方有说明 |
在例子中我们提到filter,通过filter和intervals设定的规则可以过滤掉一些我们不想要的间隔词汇的文档,当然filter不仅仅只包含not_contaning参数
常用的filter参数,如下:
参数 |
描述 |
containing |
interval query中terms之间需要包含filter中的terms |
contained_by |
interval query中的字符串需要被包含在filter query的terms里 |
not_containing |
containing 对立面 |
not_contained_by |
(比较模糊,有心得的小伙伴可以私信我)contained_by 对立面 |
此处比较建议使用 containing和not_containing,而不建议使用contained_by和not_contained_by
我们更愿意在query中输入想查询的词条 在fitler中过滤。
如果上面filters语句不能满足你的需求,那么可以尝试一下script filter ,它提供了一个interval变量,通过start、end、gaps三个函数更加灵活的控制term在文本中的顺序与距离:
* 例如下方语句简单解释一下:
POST _search
{
"query": {
"intervals": {
"content": {
"match": {
"query": "curry shooter",
"filter": {
"script": {
"source": "interval.start >= 2 && interval.end < 5 && interval.gaps == 1"
}
}
}
}
}
}
}
curry(interval.start)要出现在偏移量>=2的位置,shooter(interval.end)要出现在偏移量<5的位置 并且curry和shooter之间的间距(intercal.gaps)为1 才可以查得到
3) JavaSDK
* 参照下方DSL编写简单Java Api调用
虽然调用方式有所不同,不过最后本质上依然是一个queryBuilder工厂铸造的对象,可以放入bool中配合其他查询一起使用!
{
"query": {
"intervals": {
"content": {
"all_of": {
"max_gaps": 5,
"ordered": true,
"intervals": [
{
"match": {
"query": "Curry shooter",
"max_gaps": 1,
"ordered": "true",
"filter": {
"not_containing": {
"match": {
"query": "bad"
}
}
}
}
}
]
},
"boost": 2
}
}
}
}
public void customerIntervalsQuery() throws IOException {
// 构建intervals数组
List<IntervalsSourceProvider> intervalsSourceProviderList = new ArrayList<>(16);
// 构建内层match
IntervalsSourceProvider.IntervalFilter intervalFilter = new IntervalsSourceProvider.IntervalFilter(new IntervalsSourceProvider.Match("bad", 0, true, null, null, null), "not_containing");
IntervalsSourceProvider.Match mainProvider = new IntervalsSourceProvider.Match("Curry shooter", gaps, true, null, intervalFilter, null);
// 将math加入intervals[]
intervalsSourceProviderList.add(mainProvider);
// 最后放入all of对象中
IntervalsSourceProvider intervalsSourceProvider = new IntervalsSourceProvider.Combine(intervalsSourceProviderList, true, 5, null);
// all of放入最外层的intervals
IntervalQueryBuilder intervalQueryBuilder = new IntervalQueryBuilder("content", intervalsSourceProvider);
SearchRequest request = new SearchRequest("test_index");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(intervalQueryBuilder);
System.out.println(searchSourceBuilder.toString());
// 发送请求
request.source(searchSourceBuilder);
SearchResponse search = restHighLevelClient.search(request, RequestOptions.DEFAULT);
SearchHits hits = search.getHits();
System.out.println(hits);
}
Except for the passage of time and the separation of life and death,I can do all things.
参考资料:
Intervals query | Elasticsearch Guide [7.9] | Elastic
ElasticSearch官方文档
Elasticsearch Intervals query 间隔查询_yuanxun4683的博客-CSDN博客_elasticsearch interval
作者:墨菲灬
9.2.1-elasticsearch全文检索之intervals查询_红笺小字-CSDN博客
作者:hjx
elasticsearch 7.0 新特性之Intervals query - 简书
作者:码到成功_易企秀