弹性搜索:如何在获得所需结果后终止多搜索查询

elastic search: how to terminate a multi search query once we get desired result

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

我们想编写一个弹性搜索查询,returns 我们最多包含 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 的文档和 30 个类型 Z 的文档,我应该得到 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 等,都在不同的集合中。 (由于这个限制,我们不得不排除无痛脚本选项)

看起来您可以通过 size and a sort, plus optionally using bool 将查询合并为一个搜索来实现您想要的结果。

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

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

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

我能否获得匹配的文档,但顺序是自定义的?

是的,这就是 sort 的用途。要实现原始 post 中描述的行为,使用此调用就足够了:

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"
    }
  }
}

希望对您有所帮助!