要不要也来分享分享一下啊

如何深入理解fieldData

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

这个主题,也许你会说,就是为了聚合一个text类型的字段,
加上"fielddata": true参数,就可以了。
是这样子的。
 
不过我说的不是那个,我说的是keyword类型的fieldData数据的加载过程,
因为我们通常用keyword这种来做聚合的。(text类型的加载,大同小异)
 
也许这个主题,有点难理解。
不过这是理解桶聚合的关键,这样你才会晓得“桶”是怎么来的。
 
虽然这里说的,好像跟聚合没关系,但这里的加载数据,和你在执行桶聚合时的加载,是一样的。
执行的是同一个方法。
以这儿为切入点,可能比较容易一点。 
首先新建这么一个简单索引,
111.png

这两个参数,是我特意设定的,上面这么一个参数呢,就是为了让它显式加载。
(如果不显式加载,在你执行桶聚合的时候,它也会加载)
 
下面这个参数,一般没人会去特定设置它。
缓不缓存,对我们讨论的没关系。这里不缓存,可以大大简化我们的问题。
已邀请:

Charele - Cisco4321

赞同来自:

1
这个截图,是warm时,会执行的
warmer机制,就不多说了,关键一点:它只对两种类型的数据起作用
1是加了"eager_global_ordinals": true参数的
2是nested类型的
是不是还有其它,我没看到,也许会有。
 
111.png

注意:这个方法,是每增加一个新段,就会执行一次的。
比如你插入一条数据(因为有1秒1次的refresh),就会增加一个新段。
 
  绿色的,就是为什么只有加了"eager_global_ordinals": true参数的字段会在这儿起作用
紫色的,代码里面写错了,应该是field名,而不是索引名,这个没啥
红色的三个方法,是本文的重点。尤其是第二个。
 
 

Charele - Cisco4321

赞同来自:

2
先说上楼红1处

111.png

1> 它由fieldType的实际子类产生了一个builder
2> 然后取一个cache,取不到则新建一个
注意:在每个索引里,会对每个(需要处理的)字段,都有这么一个cache对像,用来缓存数据
由于我们的设置,这里是一个不缓存的类型,黄框里的。由于不缓存,所以这个cache对象,只是个形式。
 
 3> 然后用上面的builder,产生一个IndexFieldData具体子类

Charele - Cisco4321

赞同来自:

3
上面说道 “由fieldType的实际子类产生了一个builder”,
如果你的字段是keyword类型,很简单:(它最后build()),
产生的是一个"SortedSetOrdinalsIndexFieldData"对像,记住这个就行了。
 
下面我提一下如果字段是text,会是什么情况:
(text类型并不是我们关注的,这里只是顺便提一下)
222.png

 
是的,也许你看见过这个报错。这就是你在用一个text执行聚合时发生的现像
在执行聚合时,也会执行同样的方法。这说明了我们的方向并没有错!
555.png


  
 

Charele - Cisco4321

赞同来自:

4

1楼红方法1说完了,现在说红方法2。
开始说过,每次插入一条数据时,都会执行。

111.png

这个ElasticsearchDirectoryReader类是Lucene DirectoryReader的子类,里面包括了段。用过Lucene的就晓得。
 
每次执行时,这个reader对像都是不一样的,
(假定:每插入一条就会产生一个新段,且没有merge过程)
第一次执行,reader会包括一个段,第二次执行,reader里就会有两个段,,,,,, 

因为有许多段,段有段自己的fieldData,都是各自为政的,并不统一。
loadGlobal()方法,目的就是找到一个统一的,全局的fieldData
 
执行时,就是传入的这个reader对像

Charele - Cisco4321

赞同来自:

5
开始看那个loadGlobal方法,这图,后面还会返回来看
111.png

紫框里的,只有你是一个段的时候才会发生。
因为只有一个段,所以这个段里的就是全局的。
很少有这种情况,除非你只有一个文档,或者你做过forceMerge合并成一个,然后也没加新数据。
注意:这里的这个this,是指SortedSetOrdinalsIndexFieldData 这个类对像! (见上文)
 

Charele - Cisco4321

赞同来自:

6 接上楼
由于我们开始选择了“不缓存”,
所以没有缓存那一些额外的步骤(否则会很麻烦),直接到了这里:
222.png

 
首先说一个概念,fieldData,分为索引的,和叶子的,即段内的,(就是大的和小的的关系)
分别用IndexFieldData, LeafFieldData 类来表示。
 
由于有多个段,我们需要把各个段里的小的,整合成一个大的,就是这么个意思。
红色处,就是取得每个段里的小的fieldData,
 
蓝色处,就是取得每个段里的ordinals值
这个ordinals如何得来的,就是Lucene的方法了。
 
  绿色处,就是把多个ordinals值合并成一个globalOrdinals(这就是我们聚合所需要的东西!!!)
看下这个Lucene类OrdinalMap的注释:
777.png

它就是有这么一个功能。提供了方法,至于它如何实现的,这就要看Lucene代码了。
有兴趣的同学可以研究下下。
 
  最后返回一个GlobalOrdinalsIndexFieldData对像(看名字就知道这是啥了),返回
注意:这个对像,里面有红色和绿色的东西。蓝色的就不需要了,因为已经合并成绿色的了。
 

Charele - Cisco4321

赞同来自:

7
接上楼,我们得到了个GlobalOrdinalsIndexFieldData对像,
看5楼黄框处,判断为真,下面来分析这个东东

要回复问题请先登录注册