简介
嵌套与父子的区别
项 | 嵌套(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"
}
}
结果
其他网址
笔记四十三:文档的父子关系 | Elasticsearch 技术论坛
ElasticSearch7.2 父子文档 | 紫夜の博客
join类型--英文官网