其他网址
笔记四十三:文档的父子关系 | Elasticsearch 技术论坛
ElasticSearch7.2 父子文档 | 紫夜の博客
简介
嵌套与父子的区别
项 嵌套(nested) 父子 优点 读取性能高。
(据官方:比父子快5-10倍)
父子文档可以独立更新 缺点 更新子文档时,需更新整个文档。 读取性能差。(需额外的内存去维护关系)
CPU占用率很高。
使用场景 查询为主,子文档偶尔更新。 子文档更新频繁
子文档经常查询
注意事项
- 父子文档需要在同一分片上
- 每个索引只能有一个join字段
- 每个元素可以有多个子,但只有一个父
- 可以为一个已存在的join字段添加新的关联关系
- 可以在一个元素已经是父的情况下添加一个子
实例
需求
一篇博客,对应多个评论。 (本处以6.x示例,7.x基本一样的。)
设置Mapping
PUT my_blogs
{
"settings": {
"number_of_shards": 2
},
"mappings": {
"blog": {
"properties": {
"blog_comments_relation": {
"type": "join",
"relations": {
"blog": "comment"
}
},
"content": {
"type": "text"
},
"title": {
"type": "keyword"
}
}
}
}
}
索引文档
索引父文档
PUT my_blogs/blog/blog1 { "title":"Learning Elasticsearch", "content":"learning ELK @ geektime", "blog_comments_relation":{ "name":"blog" } }
PUT my_blogs/blog/blog2 { "title":"Learning Hadoop", "content":"learning Hadoop", "blog_comments_relation":{ "name":"blog" } }
索引子文档
父文档和子文档必须存在相同的分片上。(确保查询 join 的性能)
当指定文档时候,必须指定它的父文档 ID。(使用 route 参数来保证,分配到相同的分片)
PUT my_blogs/blog/comment1?routing=blog1 { "comment":"I am learning ELK", "username":"Jack", "blog_comments_relation":{ "name":"comment", "parent":"blog1" } }
PUT my_blogs/blog/comment2?routing=blog2 { "comment":"I like Hadoop!!!!!", "username":"Jack", "blog_comments_relation":{ "name":"comment", "parent":"blog2" } }
PUT my_blogs/blog/comment3?routing=blog2 { "comment":"Hello Hadoop", "username":"Bob", "blog_comments_relation":{ "name":"comment", "parent":"blog2" } }
查询(通过parent_id)
通过对父文档 Id 进行查询,返回所有相关的子文档。
POST my_blogs/_search { "query": { "parent_id": { "type": "comment", "id": "blog2" } } }
结果
查询(通过has_child)
通过对子文档进行查询,返回具体相关子文档的父文档。父子文档在相同的分片上,因此 Join 效率高。
本处查询“Jack”评论过的博客。
POST my_blogs/_search { "query": { "has_child": { "type": "comment", "query": { "match": { "username": "Jack" } } } } }
结果
查询(通过has_parent)
通过对父文档进行查询,返回相关的子文档。
本处查询名字为“Learning Hadoop”的博客的评论。
POST my_blogs/_search { "query": { "has_parent": { "parent_type": "blog", "query": { "match": { "title": "Learning Hadoop" } } } } }
执行结果
访问子文档
通过ID访问子文档
访问comment1
GET my_blogs/blog/comment1?routing=blog1
结果(有数据)
本处用下边语句会得到同样的结果,原因待查证。
GET my_blogs/blog/comment1
访问comment2
GET my_blogs/blog/comment2
结果(没有数据)
指定routing
GET my_blogs/blog/comment2?routing=blog2
结果(有数据)
访问comment3
GET my_blogs/blog/comment3?routing=blog2
结果(有数据)
本处使用下边语句得到同样结果,原因待查证。
GET my_blogs/blog/comment3
更新子文档
更新子文档不会影响到父文档。
法1:POST _update
POST my_blogs/blog/comment3/_update?routing=blog2 { "doc": { "comment": "Hello Hadoop??" } }
结果
法2:PUT
PUT my_blogs/blog/comment3?routing=blog2 { "comment": "Hello Hadoop..", "blog_comments_relation": { "name": "comment", "parent": "blog2" } }
结果