嵌套结构
普通数据结构
Elasticsearch没有内部对象的概念,因此,ES在存储复杂类型的时候会把对象的复杂层次结果扁平化为一个键值对列表。
例子
插入记录
POST nested_test/_doc
{
"camera":{
"type":"canon",
"photo":[
{
"image":"yyy1",
"score":6
},
{
"image":"yyy2",
"score":5
}
]
}
}
处理后的结果
{
"camera.type":"canon",
"camera.photo.image":["yyy1","yyyy2"],
"camera.photo.score":[6,5]
}
photo中的image与score对应关系被破坏,image字段与score字段被扁平化为多值字段.
验证搜索
GET nested_test/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"camera.photo.image.keyword": {
"value": "yyy1"
}
}
},
{
"term": {
"camera.photo.score": {
"value": 5
}
}
}
]
}
}
}
结果
按照sql写的条件,如果结构正确,则无法搜索出记录.但结果将记录搜索出来了.
Nested 数据结构
nested属于object类型的一种,是Elasticsearch中用于复杂类型对象数组的索引操作。可以保留层次结构,从而满足一定的查询需求.
结构
索引
PUT <index_name>
{
"mappings": {
"properties": {
"<nested_field_name>": {
"type": "nested"
}
}
}
}
搜索
GET <index_name>/_search
{
"query": {
"nested": {
"path": "<nested_field_name>",
"query": {
...
}
}
}
}
值得注意的是.若nested结构中若还是存在复杂结构需要保留结构的.也需要转换成nested结构.
例子
插入nested结构的索引.
PUT nest_test2
{
"mappings": {
"properties": {
"camera": {
"type": "nested",
"properties": {
"photo": {
"type":"nested",
"properties": {
"image": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"score": {
"type": "long"
}
}
},
"type": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
}
索引中插入记录
POST nest_test2/_doc
{
"camera": {
"type": "canon",
"photo": [
{
"image": "yyy1",
"score": 6
},
{
"image": "yyy2",
"score": 5
}
]
}
}
查询索引记录.
GET nest_test2/_search
{
"query": {
"nested": {
"path": "camera",
"query": {
"bool": {
"must": [
{
"term": {
"camera.photo.image": {
"value": "yyy1"
}
}
},
{
"term": {
"camera.photo.score": {
"value": 5
}
}
}
]
}
}
}
}
}
查询无结果.
join 数据结构
连接数据类型是一个特殊字段,它在同一索引的文档中创建父/子关系。关系部分在文档中定义了一组可能的关系,每个关系是一个父名和一个子名。
结构
索引
PUT <index_name>
{
"mappings": {
"properties": {
"<join_field_name>": {
"type": "join",
"relations": {
"<parent_name>": "<child_name>"
}
}
}
}
}
查询
通过子元素条件查询出父元素数据.
GET <index_name>/_search
{
"query": {
"has_child": {
"type": "<child_name>",
"query": {
"match_all": {}
}
}
}
}
通过父元素条件查询子元素数据
GET <index_name>/_search
{
"query": {
"has_parent": {
"parent_type": "<parent_name>",
"query": {}
}
}
}
通过父元素id查询子元素数据
GET <index_name>/_search
{
"query": {
"parent_id": {
"type": "<child_name>",
"id": 0
}
}
}
注意:
join类型不能像关系数据库中的表链接那样去用,不论是has_child或者是has_parent查询都会对索引的查询性能有严重的负面影响。并且会触发global ordinals- 在索引父子级关系数据的时候必须传入routing参数,即指定把数据存入哪个分片,因为父文档和子文档必须在同一个分片上,因此,在获取、删除或更新子文档时需要提供相同的路由值。
- 每个索引只允许有一个
join类型的字段映射 - 一个元素可以有多个子元素但只有一个父元素
- 可以向现有连接字段添加新关系
- 也可以向现有元素添加子元素,但前提是该元素已经是父元素
例子
添加索引
es中的join是关联两个元素.而非两张表.所以,多结构的元素都在同一个索引中,只是增加了一个关联关系字段来维护join.
PUT depart
{
"mappings": {
"properties": {
"join_field": {
"type": "join",
"relations": {
"depart": "employee"
}
},
"my_id": {
"type": "keyword"
}
}
}
}
添加数据
POST depart/_doc?refresh&routing=1
{
"my_id":"1",
"name": "技术部",
"join_field":{
"name":"depart"
}
}
POST depart/_doc?refresh&routing=1
{
"my_id":"3",
"name":"张三",
"join_field":{
"name":"employee",
"parent":"1"
}
}
验证查询
查询张三所在的部门
GET depart/_search
{
"query": {
"has_child": {
"type": "employee",
"query": {
"term": {
"name.keyword": {
"value": "张三"
}
}
}
}
}
}
查询张三所在部门的人
GET depart/_search
{
"query": {
"has_parent": {
"parent_type": "depart",
"query": {
"has_child": {
"type": "employee",
"query": {
"term": {
"name.keyword": {
"value": "张三"
}
}
}
}
}
}
}
}