你不会是程序猿吧?

了解下下ES中的父子文档

Elasticsearch | 作者 Charele | 发布于2023年09月18日 | 阅读数:2552

这里说的父子文档,指的是Parent Join文档,
 Nested文档,好像差不多(我容易搞混)
两个都有“父子”的理念在里面,都是实现join功能的。

 
父子文档,它之所以能够执行join,
肯定父和他的儿子们,之间,肯定存在某种联系。
就像数据库里的主键和外键一样。
 
尽管这种联系只存在一个索引里面,不过逻辑上你可以把它看成两个索引。
(所有父文档在一个索引,所有子文档在另外一个索引里)
依靠这个联系,实现join
111.png
已邀请:

Charele - Cisco4321

赞同来自:

111.png

说明下(你对这个DSL已经很熟悉了)
 
1 yellow部分,是为了让父子在同个分片上,没有其他作用
如果你的索引只有一个分片,写啥都无所谓
 
2 red部分,就是建立父子联系的关键
那这种联系是什么呢

Charele - Cisco4321

赞同来自:

假设我搞了一个父子类型,其中字段定义如下:
111.png

 
现在已经正确插入了父子文档,父文档的id值是"c1"
 
其中父文档中,除了有你自己的字段,
ES会额外加上两个字段(字段名和值,和图上对应)
 
1 "fuzi#dad" :   "c1"
2 "fuzi"  :  "dad"
跟keyword类型一样(就是说他们能查询,也有DocValue值来进行聚合排序啥的!)
 
同样,子文档里,也会有两个
1 "fuzi#dad" :   "c1"
这个,一家人的话值是一样的。就是在插入子文档时指定的父文档的id
 2 "fuzi"  :  "son"

Charele - Cisco4321

赞同来自:

建立父子文档,无非就是为了查询,
有3个普通查询和2个聚合查询。
 
先看下最简单的,Parent ID query,就是给一个父文档id,查出它的所有儿子
222.png

对照上面的说明,应该明白它的意思,
他就是一个bool,里面装了两个term查询 
上面的查出这个父亲和他的儿子们,
(因为只有这一家人的这个值是"c1",其它人就不是了)
 
下面的过滤出儿子

Charele - Cisco4321

赞同来自:

下面说说另外一个查询:Has parent query,
就是根据父亲的条件(某个查询)来找他的儿子们,这个稍微复杂一些
 
比如我要找叫“张三”的人的儿子(DSL就不放了,都知道)
假设有如下文档:(有两个叫张三的)
 
name              ES文档号               Lucene文档号
 
张三                 c1                        1  
   子aaa            c11                      2  
   子bbb           c12                      3
 李四                 c2                        4
   子ccc            c21                       5
 张三                 c3                        6
  子ddd            c31                       7
111.png

 1 红色的,就是join字段
这里首先会根据这个字段会生成一个表X:
["c1" -> 1,2,3    "c2" -> 4,5   "c3" -> 6,7]
 说明一下:
I 因为一家人的话,这个值一样,见楼上说明
II 就跟在ES聚合中一样,实际上并不是"c1""c2""c3",而是他们ordina值。这里只是为了表述方便。
(所以那个绿色的ordinalMap就是这个作用,起到"c1" ---> 全局ordinal值的对应)
 
2 这里有两个查询,蓝和紫(from和to查询)
 它会先执行蓝查询
(蓝查询是一个bool查询,里有两个子查询,第一个就是爸爸的要求,第二个由系统生成)
很直观,它会查到文档1, 6,所以他会形成表Y:
["c1", "c3]
(同样是ordinal值,同上)
 
3 再执行紫查询,就是找出所有儿子辈。
很直观,它会找到文档2,3,5,7
 
找到后,会执行两个规则匹配,这两个匹配都满了,就是本查询最终的结果
A 看看这个文档号,在表X中有没有对应。如果有取出来
B 上面取出来的,在表Y中看看有没有
 
解释下:
文档2,在表X中有,取出"c1",然后看看表Y中,有,okay
文档3,同上
文档5,在表X中有,取出"c2",看看表Y,没有,所以文档5不行
文档7,同文档2
 
所以本次“叫张三的人的儿子”,结果就是2,3,7
 
你会发现,紫查询找出来儿子辈,肯定都会符合规则A。因为它们里面肯定会有红色字段。
而有红色字段的,肯定会出现在表X里面。好像规则A没啥用。
 
注意:我这个解释是在Lucene里面,
ES父子文档中,ES自动帮你生成了这个字段(和值),
Lucene里面,文档可能没有红色字段,所以规则A是需要的。

Charele - Cisco4321

赞同来自:

大概认识下上面所说的两个规则匹配(高亮处)
111.png

 红色说明,它执行的是“两阶段遍历”
两阶段遍历,是Lucene查询中的一个概念,这里有说明
https://www.amazingkoala.com.c ... .html
 
父子文档中另外一个查询,Has child query,
找爸爸,和上面说的找儿子差不多流程。
 
https://www.gxlsystem.com/webhome-855258.html
这里说了,Lucene里面有两种Join方式,
query time join和index time join
前一种性能较差,后一种性能好(但对文档有要求)。
 
父子文档中用了前一种。我开始没明白ES里为什么不用后一种性能好的,
后来发现用在Nested文档查询里面。
所有有人说父子文档的性能比Nested查询差,原因就在这里
 
 下面说说父子文档中的聚合查询,,,
 
 

Charele - Cisco4321

赞同来自:

Test

要回复问题请先登录注册