Elasticsearch的执行顺序是什么?

时间:2020-10-23 16:59:26

标签: elasticsearch

下面的json是https://www.elastic.co/blog/top-hits-aggregation/

中的示例
{
   "query":{
      "match":{
         "body":"web"
      }
   },
   "size":1,
   "aggs":{
      "top-programming-languages":{
         "terms":{
            "field":"tags",
            "include":"java|javascript|python|php|python|ruby|perl|c#",
            "size":10,
            "order":{
               "max_score":"desc"
            }
         },
         "aggs":{
            "top-questions":{
               "top_hits":{
                  "size":1
               }
            },
            "max_score":{
               "max":{
                  "lang":"expression",
                  "script":"doc.score"
               }
            }
         }
      }
   }
}

我只是不明白这里的逻辑。

首先执行以下查询,并且仅返回一个结果。

   "query":{
      "match":{
         "body":"web"
      }
   },
   "size":1,

然后接下来的top-programming-languages聚合仅对这一条记录起作用吗?

top-programming-languages -> term -> order中,max_score是必需的,但在top-programming-languages -> aggs -> max_score聚合完成之前它不存在。那么怎么可能执行top-programming-languages -> term

似乎ES使用了反直觉的执行顺序,但我未能在其文档中找到解释。

有人可以帮我吗? 预先感谢!

1 个答案:

答案 0 :(得分:0)

执行查询并匹配N个文档。

从这N个文档中,仅返回一个文档,即得分最高的文档(因为它是一个match查询,因此排名最高)。

然后,对查询匹配的所有N个文档(即不仅在返回的文档上)运行汇总,并且从所有这些文档汇总tags

在索引的每个分片上,对标签进行存储和排序,使得包含最高doc.score文档的标签排在第一位。对于每个存储段,最上面的文档位于top-questions子聚合中。最后,每个分片的前10个存储桶将返回到协调节点。但是,由于您仅包含7个标记(python被列出两次),因此每个分片可能只有7个存储桶。

然后,协调节点将它们组合在一起,并根据max_score对所有分片中的所有标签桶进行重新排序,并且仅获取前10个桶。

假设您的索引包含2个分片和以下文档(为了简化起见,我将使用size: 5而不是10,因为您的include子句与大小10冲突):< / p>

分片1:

{"body":"web", "score": 1, "tags": "java"}
{"body":"web", "score": 2, "tags": "c#"}
{"body":"web", "score": 10, "tags": "javascript"}
{"body":"web", "score": 3, "tags": "python"}
{"body":"web", "score": 2, "tags": "php"}
{"body":"web", "score": 4, "tags": "java"}
{"body":"web", "score": 6, "tags": "java"}
{"body":"web", "score": 10, "tags": "php"}
{"body":"web", "score": 15, "tags": "ruby"}
{"body":"web", "score": 8, "tags": "php"}

分片2:

{"body":"web", "score": 4, "tags": "php"}
{"body":"web", "score": 6, "tags": "php"}
{"body":"web", "score": 3, "tags": "python"}
{"body":"web", "score": 9, "tags": "c#"}
{"body":"web", "score": 10, "tags": "python"}
{"body":"web", "score": 3, "tags": "php"}
{"body":"web", "score": 5, "tags": "ruby"}
{"body":"web", "score": 12, "tags": "javascript"}
{"body":"web", "score": 1, "tags": "python"}
{"body":"web", "score": 3, "tags": "java"}

在每个分片上,标记存储桶将如下所示(按max(doc.score)排序):

分片1:

ruby: 1 doc, max(doc.score) = 15
javascript: 1 doc, max(doc.score) = 10
php: 3 docs, max(doc.score) = 8
java: 3 docs, max(doc.score) = 6
python: 1 doc, max(doc.score) = 3
c#: 1 doc, max(doc.score) = 2

分片2:

javascript: 1 doc, max(doc.score) = 12
python: 3 docs, max(doc.score) = 10
c#: 1 doc, max(doc.score) = 9
php: 3 docs, max(doc.score) = 6
ruby: 1 doc, max(doc.score) = 5
java: 1 doc, max(doc.score) = 3

只有前5个将返回到协调节点,它将重新组合所有存储桶,并再次对其重新排序,并且仅取前5个,这将产生以下最终存储桶:

ruby: 2 docs, max(doc.score) = 15
javascript: 2 doc, max(doc.score) = 12
python: 4 docs, max(doc.score) = 10
php: 6 docs, max(doc.score) = 8
java: 3 docs, max(doc.score) = 6

因此,如您所见,执行顺序是交织在一起的。存储和排序在每个分片上发生一次,然后在协调节点上再次发生。但这并不是像先计算存储桶的顺序,然后计算存储桶等……这几乎是同时发生的,并且存储/排序也首先以分布式方式执行,最后所有内容都被集中化,类似于map / reduce的作用是什么,在ES中称为散点图/聚集。