elasticsearch的执行顺序是什么?

1qczuiv0  于 2021-06-14  发布在  ElasticSearch
关注(0)|答案(1)|浏览(536)

下面的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使用了反直觉的执行顺序,但是我在它的文档中找不到解释。
有人能帮我吗?提前谢谢!

wj8zmpe1

wj8zmpe11#

执行查询并匹配n个文档。
在这n个文档中,只返回一个,即得分最高的文档(因为它是一个 match 查询,所以排名第一)。
然后,在查询和 tags 从所有这些文件中汇总。
在索引的每个片段上,标签都是按这样的方式排列的,即那些包含具有最高优先级的文档的标签 doc.score 先来。对于每个bucket,最上面的文档都出现在 top-questions 子聚合。最后,将每个shard的前10个bucket返回给协调节点。但是,由于只包含7个标记(python列出了两次),因此每个shard可能只有7个bucket。
协调节点然后将它们组合在一起,并根据需要对所有碎片中的所有标记桶进行重新排序 max_score 只拿前10桶。
假设您的索引有2个碎片和以下文档(为了更简单,我将采用 size: 5 而不是10,因为你的 include 条款与尺寸10冲突):
碎片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个将返回到协调节点,协调节点将重新组合所有bucket并再次对它们进行排序,并且只获取前5个bucket,这将生成这些最终bucket:

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

所以,正如你所看到的,执行顺序是相互交织的。bucketing和排序在每个shard上发生一次,然后在协调节点上再次发生。但这不像是先计算桶的顺序,然后再计算桶,等等。。。这几乎是同时发生的,bucketing/ordering也首先以分布式的方式执行,最后一切都是集中的,类似于map/reduce所做的,在es中称为scatter/gather。

相关问题