弹性搜索:一旦获得所需结果,如何终止多重搜索查询

时间:2018-07-04 14:32:10

标签: elasticsearch elasticsearch-5 elasticsearch-painless

我们有一个弹性搜索文档,其中包含一个名为“ Type”的字符串字段。此字段的值可以从“ A”到“ Z”不同。多个文档可以具有相同的类型,即多个文档可以具有“ A”类型

我们要编写一个弹性搜索查询,最多返回30个这些文档。我们希望根据类型将输出分成不同的组。例如:

  1. 如果我们有10个类型为A的文档,15个类型为B的文档,20个类型为C的文档,我应该得到所有10个类型为A的文档,所有15个类型为B的文档和5个类型为C的文档。
  2. 如果我们有0个类型A的文档,10个类型B的文档​​,15个类型C的文档,20个类型D的文档,那么我应该得到所有10个类型B的文档​​,15个类型C的文档和5个类型D的文档。
  3. 最坏的情况:如果我们没有A ... Y类型的文档和Z类型的30个文档,我应该得到30个Z类型的文档。

为此,我写了一个非常基本的多搜索查询(总共26个查询)

    POST _msearch/
    {"index":"<index_name>","type":"<type>"}
    {"from":0,"size":30,"query":{"bool":{"must":[{"terms":{"type":["A"]}}]}}}
    {"index":"<index_name>","type":"<type>"}
    {"from":0,"size":30,"query":{"bool":{"must":[{"terms":{"type":["B"]}}]}}}
    ...
    {"index":"<index_name>","type":"<type>"}
    {"from":0,"size":30,"query":{"bool":{"must":[{"terms":{"type":["Z"]}}]}}}

我担心多搜索查询的执行,即对于案例1和案例2,我们得到了足够的输出,即前几个查询有30个文档,那么为什么还要执行其余的多搜索查询呢?一旦获得所需的结果数,是否有任何方法可以停止多重搜索查询操作,即一旦获得30个或更多结果,就终止多重搜索。

请注意:

  1. 我在这里给出了非常简单的条件,即,不同的多重搜索的条件比仅基于类型的条件更为复杂。
  2. 我们希望在输出中有多个集合,即类型A,类型B等,都在不同的集合中。 (由于这种限制,我们不得不排除无痛脚本选项)

1 个答案:

答案 0 :(得分:2)

使用sizesort进行一次搜索,加上使用bool将查询合并为一个查询,看来您可以达到所需的目的。

我可以提前终止多搜索查询吗?

不。从Multi Search的文档中我们可以得出结论。它执行多个具有一定并发级别的搜索请求,并仅在所有查询完成后才发回结果。

它很像Bulk API,是一种轻松执行并行请求的方法。

我可以按自定义定义的顺序获取匹配的文档吗?

是的,这就是sort的目的。要实现原始帖子中描述的行为,使用此调用实际上就足够了:

POST /<index_name>/<index_type>/_search?sort=type:asc&size=30

我可以对多个索引发出一个搜索请求,但仍使用sort吗?

是的,您只需要定义索引列表:

POST /multisearch1,mutlisearch2/<index_type>/_search?sort=type:asc&size=30

或通配符表达式:

POST /multisearch*/<index_type>/_search?sort=type:asc&size=30

我可以按任意顺序排序吗?

是,例如使用Script Based Sorting。例如,如果您希望按以下顺序在结果中看到typeXCA,则可以编写如下脚本:

POST /<index_name>/<type>/_search
{
  "size": 30,
  "sort": {
    "_script": {
      "type": "number",
      "script": {
        "lang": "painless",
        "source": """
int r = 1;
if(doc['type'].value  == 'X') { 
  r = 100;
} else if(doc['type'].value  == 'C') { 
  r = 10;
} else if(doc['type'].value  == 'A') { 
  r = 5;
}
  r;
"""
      },
      "order": "desc"
    }
  }
}

这也可以用于多个集合(如上面的查询)。

如果我有一个取决于type的值的复杂查询,可以这样做吗?

是的,没问题,例如使用bool查询:

POST /<index_name>/<type>/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "bool": {
            "must": [
              {
                "term": {
                  "type": "A"
                }
              },
              {
                "match": {
                  "description": "Quick fox"
                }
              }
            ]
          }
        },
        {
          "bool": {
            "must": [
              {
                "term": {
                  "type": "X"
                }
              },
              {
                "match": {
                  "description": "Quick bear"
                }
              }
            ]
          }
        }
      ]
    }
  },
  "size": 30,
  "sort": {
    "_script": {
      "type": "number",
      "script": {
        "lang": "painless",
        "source": """
int r = 1;
if(doc['type'].value  == 'X') { 
  r = 100;
} else if(doc['type'].value  == 'C') { 
  r = 10;
} else if(doc['type'].value  == 'A') { 
  r = 5;
}
  r;
"""
      },
      "order": "desc"
    }
  }
}

希望有帮助!