绊脚石乃是进身之阶。

关于ES里的深度/广度 优先的问题

Elasticsearch | 作者 Charele | 发布于2022年05月05日 | 阅读数:1372

前一阵子,看到了这个问题,
https://elasticsearch.cn/question/12557

我来谈谈我的观点。
 
已邀请:

Charele - Cisco4321

赞同来自:

1 Lucene中里,查询是由收集器来完成的。
由“收集器”产生“叶子收集器”,由叶子收集器完成一个段里的文档的查询(有几个段,就有几个叶子收集器)
 
ES里的聚合,也是这个做法,

111.png

 
ES里面,Aggregator类就是这个BucketCollector的子类,
也是Lucene中的org.apache.lucene.search.Collector的孙子类

Charele - Cisco4321

赞同来自:

2 上面说到“收集器产生叶子收集器,叶子收集器来完成文档查询”
在ES聚合时,产生叶子收集器时,是把子聚合的“叶子收集器”传进去的。

222.png

 
所以在深度优先下,
父聚合在执行的时候,就一并执行了子聚合,
(同理,子聚合执行时,一并执行了孙子聚合,,,)
这没啥好说的。

Charele - Cisco4321

赞同来自:

3 上面提到,父聚合执行时,会把子聚合传进去。
这是在深度优先的情况,在广度优先的情况下,不是这样的。
那个"sub"并不是真正的子聚合,可以叫做“delay聚合“
(delay聚合里包含了真正的子聚合!)
 
这个delay聚合做了什么工作呢?网上文章的说法是把文档缓存下来,供后面用。
大致可以这样理解,但不完全正确。

333.png

它存的是:
文档号(文档号是差值储存的,从名字上可看出来)
和桶号(精确地说是ordinal号)
 

Charele - Cisco4321

赞同来自:

4 最后,在组建结果时,才会执行真正的子聚合

444.png

 
这个deferringCollector(就是上面说的delay聚合器)
在深度优先时,是null,所以无意义,不执行什么
在广度优先时,才有实际效果。
 
另外,那个long[] bucketOrdsToCollect参数,
就是裁剪后的桶号。
另外说一下,(比如你有一万个桶)
你执行top 10时,这里并不仅仅是10个,
缺省情况下:它应该是1.5 * topN + 10,也就是要收集25个桶

Charele - Cisco4321

赞同来自:

5
上面3里面说了,delay聚合里面,包括了真正的子聚合!
在收集结果时,
会把原先缓存的"Entry"取出来,用真正的子聚合执行它。

555.png

 
 

Charele - Cisco4321

赞同来自:

6 一般都认为,缺省情况是深度优先,
其实不是的。
如果不显式指定,它自己有一个选择过程。
666.png

 

Charele - Cisco4321

赞同来自:

7
ES聚合,一般是这样生成的,
根据你的执行的聚合类型不同而不同,大致是这样子的
 
XXXAggregationBuilder -> XXXAggregatorFactory -> XXXAggregator
 
XXXAggregator就是上面1里面说的,Aggregator的实际子类
 
比如你对一个keyword做terms聚合时,(对long类型聚合时,会不一样)
产生的就是GlobalOrdinalsStringTermsAggregator
 
(另外还有变种,LowCardinality, StringTermsAggregatorFromFilters,
这些都是为了性能而优化而来的,在研究时,可以忽略)
777.png

  
 

Charele - Cisco4321

赞同来自:

8
感觉要深入理解ES,要看代码。
看文档,看网上大神的视频,是没用的。那些都是极其肤浅的东西。
一本很不错的入门书

888.png

 
 

要回复问题请先登录注册