1、基本概念
连接数据类型是一个特殊字段,它在同一索引的文档中创建父/子关系。关系部分在文档中定义了一组可能的关系,每个关系是一个父名和一个子名。父/子关系可以定义如下
PUT <index_name> { "mappings": { "properties": { "<join_field_name>": { "type": "join", "relations": { "<parent_name>": "<child_name>" } } } } }
2、使用场景
join
类型不能像关系数据库中的表链接那样去用,不论是has_child
或者是has_parent
查询都会对索引的查询性能有严重的负面影响。并且会触发global ordinals
join
唯一合适应用场景是:当索引数据包含一对多的关系,并且其中一个实体的数量远远超过另一个的时候。比如:老师
有一万个学生
3、注意事项
注意
在索引父子级关系数据的时候必须传入routing参数,即指定把数据存入哪个分片,因为父文档和子文档必须在同一个分片上,因此,在获取、删除或更新子文档时需要提供相同的路由值。
每个索引只允许有一个join类型的字段映射
一个元素可以有多个子元素但只有一个父元素
可以向现有连接字段添加新关系
也可以向现有元素添加子元素,但前提是该元素已经是父元素
4、案例
数据
# 部门 PUT depart { "mappings": { "properties": { "msb_join_field": { "type": "join", "relations": { "depart": "employee" } }, "my_id": { "type": "keyword" } } } } PUT depart/_doc/1 { "my_id": 1, "name":"教学部", "msb_join_field":{ "name":"depart" } } PUT depart/_doc/2 { "my_id": 2, "name":"咨询部", "msb_join_field":{ "name":"depart" } } # 老师 # 路由值是强制性的,因为父文档和子文档必须在同一个分片上建立索引 PUT depart/_doc/3?routing=1&refresh { "my_id": 3, "name":"吴老师", "msb_join_field":{ "name":"employee", "parent":1 } } PUT depart/_doc/4?routing=1&refresh { "my_id": 4, "name":"周老师", "msb_join_field":{ "name":"employee", "parent":1 } } # 咨询 PUT depart/_doc/5?routing=1&refresh { "my_id": 5, "name":"依依老师", "msb_join_field":{ "name":"employee", "parent":2 } } PUT depart/_doc/6?routing=1&refresh { "my_id": 6, "name":"球球老师", "msb_join_field":{ "name":"employee", "parent":2 } } PUT depart/_doc/7?routing=1&refresh { "my_id": 7, "name":"琪琪老师", "msb_join_field":{ "name":"employee", "parent":2 } }
搜索所有部门
GET depart/_search { "query": { "has_child": { "type": "employee", "query": { "match_all": {} } } } }
搜索周老师所在部门
GET depart/_search { "query": { "has_child": { "type": "employee", "query": { "match": { "name.keyword": "周老师" } } } } }
搜索咨询部所有老师
GET depart/_search { "query": { "has_parent": { "parent_type": "depart", "query": { "match": { "name.keyword": "咨询部" } } } } }
搜索部门id为 2 的部门员工:
GET depart/_search { "query": { "parent_id":{ "type":"employee", "id":2 } } }