Elasticsearch详解mapping之nested
1 前言
在工作开发中, 我们常遇到2张表示1对多的关系,这样的父子结构, 如果用MySQL存的话,子表设一个字段parentId存储父表的id,这样就可以用join关联查询.
那么ES作为NoSQL,它有更便捷的存储方式来保存父子结构:
- 第一种:join字段类型,子文档包含父文档ID,可用has_parent和has_child来查询
- 第二种:nested字段类型,子文档就存在父文档某个字段内部,适合子文档数量较少的情况
在上一篇Elasticsearch笔记(二十六) 详解mapping之object中介绍了object存储对象数组的缺陷, 如果要存对象数组, 并且对数组中每一个对象进行单独查询, 用nested类型比较合适.
但是nested类型适合子文档数量较少情况,有es有如下默认设置
- 一个文档最多有50个nested类型的字段
- 一个文档所有nested类型的字段存储文档最大数量是10000条
如果用elasticsearch存树形结构,可以参考Elasticsearch笔记(十三) ES 存储树形结构 整合Spring Data Elasticsearch
更多nested详解参考知名大佬博客干货 | Elasticsearch Nested类型深入详解
2 创建nested字段的mapping
创建一个文档,存储班级, student里存储该班级的学生信息
PUT /pigg_test_nested
PUT /pigg_test_nested/_mapping/
{
"properties":{
"class":{
"type":"keyword"
},
"student":{
"type":"nested",
"properties":{
"name":{
"type":"keyword"
},
"sex":{
"type":"keyword"
},
"age": {
"type":"integer"
}
}
}
}
}
3 插入测试数据
PUT pigg_test_nested/_doc/1
{
"class":"高三(1)班",
"student":[
{
"name":"亚瑟王",
"sex":"男",
"age":18
},
{
"name":"程咬金",
"sex":"男",
"age":18
},
{
"name":"扁鹊",
"sex":"男",
"age":20
},
{
"name":"安其拉",
"sex":"女",
"age":18
}
]
}
PUT pigg_test_nested/_doc/2
{
"class":"高三(2)班",
"student":[
{
"name":"老夫子",
"sex":"男",
"age":20
},
{
"name":"凯爹",
"sex":"男",
"age":19
},
{
"name":"小乔",
"sex":"女",
"age":16
},
{
"name":"大乔",
"sex":"女",
"age":18
}
]
}
4 nested查询
GET /pigg_test_nested/_search
{
"query": {
"nested": {
"path": "student",
"query": {
"bool": {
"must": [
{
"term": {
"student.age": {
"value": "18"
}
}
},
{
"term": {
"student.sex": {
"value": "女"
}
}
}
]
}
}
}
}
}
返回如下:
{
"_index" : "pigg_test_nested",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.5447271,
"_source" : {
"class" : "高三(1)班",
"student" : [
{
"name" : "亚瑟王",
"sex" : "男",
"age" : 18
},
{
"name" : "程咬金",
"sex" : "男",
"age" : 18
},
{
"name" : "扁鹊",
"sex" : "男",
"age" : 20
},
{
"name" : "安其拉",
"sex" : "女",
"age" : 18
}
]
}
}
如果查询女的亚瑟王,则返回没有数据,这个和object类型是有区别的,
GET /pigg_test_nested/_search
{
"query": {
"nested": {
"path": "student",
"query": {
"bool": {
"must": [
{
"term": {
"student.name": {
"value": "亚瑟王"
}
}
},
{
"term": {
"student.sex": {
"value": "女"
}
}
}
]
}
}
}
}
}
5 nested聚合分析
统计每个班级各自的性别数量
GET pigg_test_nested/_search
{
"aggs": {
"group_by_class": {
"terms": {
"field": "class",
"size": 10
},
"aggs": {
"count_by_sex": {
"nested": {
"path": "student"
},
"aggs": {
"group_by_sex": {
"terms": {
"field": "student.sex",
"size": 10
}
}
}
}
}
}
}
}
返回如下:
"aggregations" : {
"group_by_class" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "高三(1)班",
"doc_count" : 1,
"count_by_sex" : {
"doc_count" : 4,
"group_by_sex" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "男",
"doc_count" : 3
},
{
"key" : "女",
"doc_count" : 1
}
]
}
}
},
{
"key" : "高三(2)班",
"doc_count" : 1,
"count_by_sex" : {
"doc_count" : 4,
"group_by_sex" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "女",
"doc_count" : 2
},
{
"key" : "男",
"doc_count" : 2
}
]
}
}
}
]
}
}