只说关于termAgg相关的东东,
termAgg是最基础的,明白了这个,可以更好的理解其它的。
各种类型的聚合,尽管结构上五花八门,
但是执行逻辑上是一样的(pipeline类型的除外)
如果你对一个比如name字段做term聚合,缺省用的就是这个类
(会有优化变种,不谈)
它以GlobalOrdinals开头,就说明这个GlobalOrdinals是灵魂,就说说它是怎么来的
就是说如果对姓名做term聚合,它并不是直接统计张三有几个,李四有几个,
而是用这个ordinal号代表每个姓名,对这个号进行统计的
10 个回复
Charele - Cisco4321
赞同来自: liaosy
加载fieldData的流程流程如下:
Index级FD ---> 叶(或段)级FD ---> 产生每个段的FieldData ===> 形成全局FD
其中红色子类就是带GlobalOrdinals号的,用来像term聚合。
那那些不带GlobalOrdinals号的,有啥用呢?也用来聚合的马?
Charele - Cisco4321
赞同来自:
GlobalOrdinals,就是全局的编号,你公司有张三是0号,而我公司张三是10号,这就不行了,得形成共识。
这个"Global",是相对局部的(Lucene)段来说的。
如果你的name字段是keyword类型的,它低层用的是docValue,每个词写的时候天生就带唯一编号,
直接用一个Lucene方法取出来就可以了。
现在这个号只是每个段内部的,不是全局的,
比如你段,bbb:0, ccc:1, ddd:2,,,
我段:aaa:0, bbb:1,,, xxx:21
因为每个段拥的词都不一样,所以bbb,在每个段里的号不一样。
后面会说如何形成全局的号。
Charele - Cisco4321
赞同来自:
在做聚合的时候,它是在查询临时生成的
绿色就是取出一个词,红色就是为这个词按序编一个号,0,1,2,3,,
紫色处,就是把这个词保存下来
配合黄色的记录的偏移量,到时候就可以很方便的取出词来。
蓝色处,会记录文档号。这几个,一个都不能少,过程比慢麻烦。
因为text类型会分词,所以量比较大,在这个过程中会有熔断机制。
Charele - Cisco4321
赞同来自:
首先如果只有一个段,那就是全局的,因为没人和你争论什么
如果有多个段,会在红色处生成一个全局的ordinals列表,
这个列表是个大杂烩,很大。
显然,如果我这个段很小,只有几个词,显然用不到这么大的一张表,
所以会为每个段形成一个“lazy加载”的形表,紫色处
当然,它直接返回这个大杂烩也是可以的,这么做只是优化性能
Charele - Cisco4321
赞同来自:
因为大杂烩中有所有的词和编号,aaa:0, bbb:1, ccc:2,,,,
比如,如果我的段中只有一个词bbb,那我只要"bbb:1"这一段就行了
汪意:现在这个"bbb:1"是全局的,就是说在所有的段现在的视角来看,bbb的号都是1
(尽管你段里存的是bbb的编号是0)
红色,就是说如果你段里的词数量和大杂烩里的词数量一样,
显然你就需要这个大表,直接返回。
绿色和紫色是针对你段中,name这个字段是单值和多值的情况返回不同的对像
Charele - Cisco4321
赞同来自:
这是在term聚合中实际动作,
黄色,就表示这个文档里没有这个字段,不管它了。
红色就是得到这个文档中词的ord,绿色里面,实际上的就是这个ord的 count+1 处理
这里并不需要知道是什么词,ord就唯一代表了一个词。
最后返回结果时会找出ord对应的词,把<词,count>返回
最后多个分片的结果会做合并,就是最终的查询结果了
另外,这是单值的情况,
多值会不一样。因为多值情况下,一个文档里会有多个不同的词
Charele - Cisco4321
赞同来自:
但如果有子聚合,还是不够的。
因为如果像"count by 公司,姓名“这样的聚合查询,
”张三“只有一个唯一的全局ord,
你公司有两个叫张三的,这是同一个
但你不能把你公司的张三和我公司的张三看成一样的
所以在有子聚合的情况下,它会做remap。
就是把这个桶号 + ord,形成一个新的叫"bucketOrd",来做统计
类似于:
a公司:张三 ---> 0
b公司:张三 ---> 1
a 公司:李四 ---> 2,,,,
Charele - Cisco4321
赞同来自:
还有另外一种"map"方式的聚合方式,
map方式中,并不是不需ord而直接对词进行统计,
它也需要ord,只是取得方式不同而已
Charele - Cisco4321
赞同来自:
会进cache的。
就是说,找的时候先去cache看下,如果有就从cache直接取来。
没有就生成,然后放进cache以供后续查询读取
Charele - Cisco4321
赞同来自:
相关的,ES里面有个warm机制,预热,
下面那个:
如果你的字段设置有"eager_global_ordinals": true,
每次有新段生成时,它都会把这个字段的fieldData预先加载进缓存。
查询要用时就不必再生成了
上面那个BitSetProducerWarmer,
是为Nested文档而作用的,
为什么要预热Nested文档,是为了加快Nested查询。
至于怎么个原理,要看Lucene代码才能明白。
warm执行时用的是“WARMER”线程(这个线程池只用在这里)
这两个,是针对不同的字段类型进行处理,
一个是预热"eager_global_ordinals"字段,一个是预热nested字段。
那如果我一个字段,既是nested,又是"eager_global_ordinals=true",会不会两头预热呢?
不会的,因为nested字段设置不了"eager_global_ordinals"这个属性。