Elasticsearch 父子关系
Elasticsearch的Parent和Child非常有利于我们进行关联查询,父子关系的查询在一定的场合下使用能加快我们的索引速度。由于ElasticSearch不是关系数据库,它只与搜索效率有关,与存储效率无关。存储的数据已被非规范化。这意味着联接不能跨索引,子文档和父文档必须位于相同的索引和相同的分片中。
父子关系图
对于Elasticsearch的 Parent and Child:
家庭关系:
学校关系:
等等关系我们都可以用 Parent and Child 来表示,非常有利于我们进行父子关系的查询。
Parent and Child 有如下特点:
父子关系
每个父母有多个孩子
多个层次的亲子关系
创建 “Family_Tree” 索引
这里我们使用汽车关系来进行相关展示:
创建相关索引
1 | PUT family_tree |
注意:Parent-child uses the "eager_global_ordinals"
to speed up joins.
父子关系需要在统一分片中:我们在插入数据的时候,一般通过固定值来路由(routing)到同一个分片中。
分片规则:shard = hash(routing_value) % number_of_primary_shards
开始相关操作
父节点插入数据
1 | PUT family_tree/_doc/1?routing=Car |
子节点插入数据
1 | PUT family_tree/_doc/2?routing=Car |
注意:子文档和父文档必须位于同一分片上的限制。
查询数据
搜索和过滤指定的父节点
获取Car的所有子级:parent_id查询可用于查找属于特定父级的子级文档。
1 | GET /family_tree/_search?pretty=true |
结果:以查找出属于parent_id
为 1 的所有子级文档。
在这之前我们先为 Car 添加一个不再销售的汽车类型:
1 | PUT family_tree/_doc/5?routing=Car |
- 通过bool与must结合获取所有未售的 Car 的孩子:
1 | GET /family_tree/_search |
结果:从查询到的结果中可以看到:只有”Sports car”符合我们查询的条件。
- 我们也可以通过
has_child
查询拥有子节点未销售状态的父节点信息:
1 | GET /family_tree/_search?pretty |
提示:has_parent关键字可帮助我们获取所有有父母且符合过滤条件的孩子信息。
通过has_parent来查询父节点状态为在售的所有子节点信息:
1 | GET /family_tree/_search?pretty |
小建议:
每个关系级别都会在查询时增加内存和计算方面的开销,不是很建议使用多个级别的关系模型。
小收获:
父子文档必须索引到同一个分片中。
每个索引仅允许一个连接字段映射。
一个元素可以有多个子级,但只能有一个父级。
可以向已存在的联接字段添加新关系。
也可以将子元素添加到现有元素中,但前提是该元素已经是父元素。
本次总结
当索引时间性能比搜索时间性能更重要时,父子联接可能是管理关系的有用技术,但代价是很高的。必须意识到这种权衡,例如父子文档的物理存储约束和增加的复杂性。另一个预防措施是避免多层父子关系,因为这将消耗更多的内存和计算量。这些都是我们在使用父子关系的时候必须要考虑到的相关内容,避免造成不必要的损失。