对于复杂的嵌套字段处理使用nested来避免数据扁平化处理,使用数据如下:

PUT /user_index
{"mappings": {"properties": {"user_name": {"type": "keyword"},"age ": {"type": "short"},"address": {"properties": {"province": {"type": "keyword"},"city": {"type": "keyword"},"street": {"type": "keyword"}}}}}
}

插入数据


POST _bulk
{"create":{"_index":"user_index", "_type":"_doc", "_id":1}}
{"id":1,"user_name":"jack","age":"25","address":[{"province":"北京","city": "北京","street": "枫林三路"},{"province":"天津","city": "天津","street": "华夏路"}]}
{"create":{"_index":"user_index", "_type":"_doc", "_id":2}}
{"id":2,"user_name":"rose","age":"23","address":[{"province":"河北","city": "廊坊","street": "燕郊经济开发区"},{"province":"天津","city": "天津","street": "华夏路"}]}
{"create":{"_index":"user_index", "_type":"_doc", "_id":3}}
{"id":3,"user_name":"libai","age":"21","address":[{"province":"上海","city": "上海","street": "淞虹路"},{"province":"河南","city": "郑州","street": "莲花路"}]}```

如下根据省份城市查询

GET /user_index/_search
{"query": {"bool": {"must": [{"match": {"address.province": "北京"}},{"match": {"address.city": "天津"}}]}}
}

查询结果:

{"took" : 0,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 1,"relation" : "eq"},"max_score" : 1.8239043,"hits" : [{"_index" : "user_index","_type" : "_doc","_id" : "1","_score" : 1.8239043,"_source" : {"id" : 1,"user_name" : "jack","age" : "25","address" : [{"province" : "北京","city" : "北京","street" : "枫林三路"},{"province" : "天津","city" : "天津","street" : "华夏路"}]}}]}
}

nested 查询

但是得到的结果并不准确,这个时候就需要使用nested object来定义数据建模。

DELETE /user_index
PUT /user_index
{"mappings": {"properties": {"user_name": {"type": "keyword"},"age ": {"type": "short"},"address": {"type": "nested", "properties": {"province": {"type": "keyword"},"city": {"type": "keyword"},"street": {"type": "keyword"}}}}}
}

这个时候使用nested查询

GET /user_index/_search
{"query": {"bool": {"must": [{"nested": {"path": "address","query": {"bool": {"must": [{"match": {"address.province": "北京"}},{"match": {"address.city": "天津"}}]}}}}]}}
}

查询结果如下:

{"took" : 0,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 0,"relation" : "eq"},"max_score" : null,"hits" : [ ]}
}

虽然语法变的复杂了,但是在数据的读写操作上都不会有错误发生,是推荐的设计方式。

其原因是:
普通的数组数据在ES中会被扁平化处理,处理方式如下:(如果字段需要分词,会将分词数据保存在对应的字段位置,当然应该是一个倒排索引,这里只是一个直观的案例)

{"user_name" : "jack","address.province" : [ "北京", "天津" ],"address.city" : [ "北京", "天津" ]"address.street" : [ "枫林三路", "华夏路" ]
}

那么nested object数据类型ES在保存的时候不会有扁平化处理,保存方式如下:所以在搜索的时候一定会有需要的搜索结果。

{"user_name" : "jack"
}
{"address.province" : "北京","address.city" : "北京","address.street" : "枫林三路"
}
{"address.province" : "天津","address.city" : "天津","address.street" : "华夏路",
}

nested Object建模的优缺点:
缺点:
1:数据冗余 将多个数据都放在一起了,维护成本就比较高
2:每次更新,需要重新索引整个对象(包括跟对象和嵌套对象)
优点:
1:文档存储在一起,读取效率性能高
适用于查询频繁 更新较少的场景

父子文档

ES 提供了类似关系型数据库中 Join 的实现。使用 Join 数据类型实现,可以通过 Parent / Child 的关系,从而分离两个对象

父文档和子文档是两个独立的文档,更新父文档无需重新索引整个子文档。子文档被新增,更改和删除也不会影响到父文档和其他子文档。
要点:父子关系元数据映射,用于确保查询时候的高性能,但是有一个限制,就是父子数据必须存在于一个shard中

父子关系

DELETE user_addressPUT user_address
{"mappings": {"properties": {"user_address_relation": {"type": "join","relations": {"user": "address"}},"user_name": {"type": "keyword"},"age ": {"type": "short"}}}
}

插入user父文档

PUT user_address/_doc/user1
{"user_name": "jack","age": "25","user_address_relation": {"name": "user"}
}PUT user_address/_doc/user2
{"user_name": "rose","age": "23","user_address_relation": {"name": "user"}
}

索引子文档

父文档和子文档必须存在相同的分片上,确保查询 join 的性能
当指定文档时候,必须指定它的父文档 ID ,使用 route 参数来保证,分配到相同的分片

PUT user_address/_doc/address1?routing=user1
{"province": "北京","city": "北京","street": "枫林三路","user_address_relation": {"name": "address","parent": "user1"}
}PUT user_address/_doc/address2?routing=user1
{"province": "天津","city": "天津","street": "华夏路","user_address_relation": {"name": "address","parent": "user1"}
}PUT user_address/_doc/address3?routing=user2
{"province": "河北","city": "廊坊","street": "燕郊经济开发区","user_address_relation": {"name": "address","parent": "user2"}
}PUT user_address/_doc/address4?routing=user2
{"province": "天津","city": "天津","street": "华夏路","user_address_relation": {"name": "address","parent": "user2"}
}

Parent / Child 所支持的查询

查询所有文档

POST user_address/_search
{}
{"took" : 372,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 6,"relation" : "eq"},"max_score" : 1.0,"hits" : [{"_index" : "user_address","_type" : "_doc","_id" : "user1","_score" : 1.0,"_source" : {"user_name" : "jack","age" : "25","user_address_relation" : {"name" : "user"}}},{"_index" : "user_address","_type" : "_doc","_id" : "user2","_score" : 1.0,"_source" : {"user_name" : "rose","age" : "23","user_address_relation" : {"name" : "user"}}},{"_index" : "user_address","_type" : "_doc","_id" : "address1","_score" : 1.0,"_routing" : "user1","_source" : {"province" : "北京","city" : "北京","street" : "枫林三路","user_address_relation" : {"name" : "address","parent" : "user1"}}},{"_index" : "user_address","_type" : "_doc","_id" : "address2","_score" : 1.0,"_routing" : "user1","_source" : {"province" : "天津","city" : "天津","street" : "华夏路","user_address_relation" : {"name" : "address","parent" : "user1"}}},{"_index" : "user_address","_type" : "_doc","_id" : "address3","_score" : 1.0,"_routing" : "user2","_source" : {"province" : "河北","city" : "廊坊","street" : "燕郊经济开发区","user_address_relation" : {"name" : "address","parent" : "user2"}}},{"_index" : "user_address","_type" : "_doc","_id" : "address4","_score" : 1.0,"_routing" : "user2","_source" : {"province" : "天津","city" : "天津","street" : "华夏路","user_address_relation" : {"name" : "address","parent" : "user2"}}}]}
}

根据父文档ID查看

GET user_address/_doc/user1

查询结果:

{"_index" : "user_address","_type" : "_doc","_id" : "user1","_version" : 1,"_seq_no" : 0,"_primary_term" : 1,"found" : true,"_source" : {"user_name" : "jack","age" : "25","user_address_relation" : {"name" : "user"}}
}

Parent Id 查询

返回所有相关子文档
通过对付文档 Id 进行查询,返回所有相关的子文档

POST user_address/_search
{"query": {"parent_id": {"type": "address","id": "user2"}}
}

查询结果:

{"took" : 1,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 0.6931471,"hits" : [{"_index" : "user_address","_type" : "_doc","_id" : "address3","_score" : 0.6931471,"_routing" : "user2","_source" : {"province" : "河北","city" : "廊坊","street" : "燕郊经济开发区","user_address_relation" : {"name" : "address","parent" : "user2"}}},{"_index" : "user_address","_type" : "_doc","_id" : "address4","_score" : 0.6931471,"_routing" : "user2","_source" : {"province" : "天津","city" : "天津","street" : "华夏路","user_address_relation" : {"name" : "address","parent" : "user2"}}}]}
}

Has Child 查询

返回父文档
通过对子文档进行查询,返回具体相关子文档的父文档
父子文档在相同的分片上,因此 Join 效率高


POST user_address/_search
{"query": {"has_child": {"type": "address","query": {"match": {"province": "北京"}}}}
}

查询结果:

{"took" : 2,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 1.0,"hits" : [{"_index" : "user_address","_type" : "_doc","_id" : "user1","_score" : 1.0,"_source" : {"user_name" : "jack","age" : "25","user_address_relation" : {"name" : "user"}}},{"_index" : "user_address","_type" : "_doc","_id" : "user2","_score" : 1.0,"_source" : {"user_name" : "rose","age" : "23","user_address_relation" : {"name" : "user"}}}]}
}

Has Parent 查询

返回相关性的子文档
通过对父文档进行查询,返回相关的子文档

POST user_address/_search
{"query": {"has_parent": {"parent_type": "user","query": {"match": {"user_name": "jack"}}}}
}

查询结果

{"took" : 3,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 1.0,"hits" : [{"_index" : "user_address","_type" : "_doc","_id" : "address1","_score" : 1.0,"_routing" : "user1","_source" : {"province" : "北京","city" : "北京","street" : "枫林三路","user_address_relation" : {"name" : "address","parent" : "user1"}}},{"_index" : "user_address","_type" : "_doc","_id" : "address2","_score" : 1.0,"_routing" : "user1","_source" : {"province" : "天津","city" : "天津","street" : "华夏路","user_address_relation" : {"name" : "address","parent" : "user1"}}}]}
}

访问子文档

需指定父文档 routing 参数

GET user_address/_doc/address2

查询结果:

{"_index" : "user_address","_type" : "_doc","_id" : "address2","_version" : 1,"_seq_no" : 7,"_primary_term" : 1,"_routing" : "user1","found" : true,"_source" : {"province" : "天津","city" : "天津","street" : "华夏路","user_address_relation" : {"name" : "address","parent" : "user1"}}
}
#通过ID和routing ,访问子文档
GET user_address/_doc/address2?routing=user2

查询结果:

{"_index" : "user_address","_type" : "_doc","_id" : "address2","_version" : 1,"_seq_no" : 7,"_primary_term" : 1,"_routing" : "user1","found" : true,"_source" : {"province" : "天津","city" : "天津","street" : "华夏路","user_address_relation" : {"name" : "address","parent" : "user1"}}
}

更新子文档

更新子文档不会影响到父文档

PUT user_address/_doc/address2?routing=user2
{"province": "上海","city": "上海","street": "南京西路","user_address_relation": {"name": "address","parent": "user2"}
}
再次查询子文档
GET user_address/_doc/address2?routing=user2

查询结果如下:

{"_index" : "user_address","_type" : "_doc","_id" : "address2","_version" : 2,"_seq_no" : 10,"_primary_term" : 1,"_routing" : "user2","found" : true,"_source" : {"province" : "上海","city" : "上海","street" : "南京西路","user_address_relation" : {"name" : "address","parent" : "user2"}}
}

优点:
1:父子文档 独立更新 互不影响
2:父子关系数据存在一个shard中,而且还有映射其关联关系的元数据,那么搜索父子关系数据的时候,不用跨分片,一个分片本地自己就搞定了,性能当然高
缺点:
1:需要额外的内存去维护关系。读取性能相对差
适合更新频繁的操作

创作不易,如果对你有帮助,帮忙点个赞呗

ElasticSearch(四):ES nested嵌套文档与父子文档处理相关推荐

  1. Word长文档编辑技巧:主控文档和子文档

    在编辑一个长文档时,如果将所有的内容都放在一个文档中,那么工作起来会非常慢,因为文档太大,会占用很大的资源.用户在翻动文档时,速度就会变得非常慢.如果将文档的各个部分分别作为独立的文档,又无法对整篇文 ...

  2. 手机摇身一变,一键将纸质文档变电子文档,这一招在微信上火了!

    在日常工作中,经常需要把纸质文档整理成电子档,自己动手一个字的录入,既耽搁时间, 效率又低下,对于少许的纸质文档还好,要是数量过多,还用老办法,那就是太难受了,那该怎么办了?别急,今天小编来教你一个又 ...

  3. word主控文档计算机二级,2017高会《职称计算机》Word 2003:主控文档和子文档

    2017年高级会计师 考试评审依然有部分地区需要考生通过职称计算机的考试,东奥小编为大家整理高级会计职称计算机知识点,希望能够帮助大家轻松过关! 主控文档和子文档 如果要编辑的文档长达数百页,最好使用 ...

  4. 【Elasticsearch】ES正确查询文档数不要使用_search的hit而是使用_count

    hit 使用hit作为查询的计数是错误的. 当我们执行一个查询,比如下面的查询 GET /my-index-000001/_search {"query": {"term ...

  5. 【Elasticsearch】 es nested 嵌套类型 详解

    1.概述 数据类型,大合集参考 [Elasticsearch]Elasticsearch的数据类型 (text.keyword.date.object.geo等) 2 嵌套类型 - nested 嵌套 ...

  6. es内嵌文档查询_Elasticsearch 7.x Nested 嵌套类型查询 | ES 干货

    一.什么是 ES Nested 嵌套 Elasticsearch 有很多数据类型,大致如下: 基本数据类型: string 类型.ES 7.x 中,string 类型会升级为:text 和 keywo ...

  7. Elasticsearch中如何进行排序(中文+父子文档+嵌套文档)

    Elasticsearch中如何进行排序 背景 最近去兄弟部门的新自定义查询项目组搬砖,项目使用Elasticsearch进行数据的检索和查询.每一个查询页面都需要根据选择的字段进行排序,以为是一个比 ...

  8. kibana创建es索引_es 索引数据创建mapping 普通内部对象 嵌套文档 父子文档创建和查询...

    普通内部对象 "kibana_sample_data_ecommerce" : { "mappings" : { "properties" ...

  9. Elasticsearch(es) 查询语句语法详解

    Elasticsearch 查询语句采用基于 RESTful 风格的接口封装成 JSON 格式的对象,称之为 Query DSL.Elasticsearch 查询分类大致分为全文查询.词项查询.复合查 ...

最新文章

  1. 【TX2】TX2开发板系统默认串口有ttyS0(调试口)、ttyTHS1、ttyTHS2、ttyTHS3,通过修改设备树文件,可以新增三个串口
  2. linux下重命名脚本推荐
  3. Pat乙级1084 外观数列
  4. Java多线程详解[狂神说Java]
  5. mysql创建反弹函数,MySql创建函数
  6. java 中的内省 introspector
  7. (15)HTML面试题集锦
  8. SQLite数据库的特性
  9. (转)OpenLayers3基础教程——OL3之Popup
  10. H.264文件解析与码流分析
  11. Multisim14.0详细安装教程图文
  12. python 问卷调查系统_GitHub - JukieChen/surveySystem-1: 问卷调查系统
  13. Dirt Ratio HDU - 6070
  14. POJ3658Matrix( 双重二分+负数+死循环)
  15. 两个质数互质是_科学网—理解黎曼猜想(二)两个自然数互质的概率是多少? - 袁岚峰的博文...
  16. 年底买基金的六大建议!
  17. python winform开发框架_winform引用网络上的图
  18. Web24——Ajax
  19. [文档] 软件测试说明书
  20. 【Matlab】Matlab作图的一些小知识

热门文章

  1. 中地恒达振弦信号采集仪MCU采集模块
  2. ai描边工具怎么打开_AI描边工具命令讲解,教你ai描边功能实用技巧
  3. mysql 金额_Mysql中金额使用DECIMAL类型
  4. 平行四边形符号怎么打?
  5. 变频器LED显示灯闪烁_东莞变频器常见故障维修华中伺服驱动器维修
  6. BeautifulSoup4 模块中文文档
  7. 历经5年,一次业余网页游戏项目惨痛的失败经历
  8. matlab 风资源,自己开发的风资源分析工具包WindAnalysis
  9. 基于单片机的危险气体泄露报警器设计
  10. 甲方乙方 (1997)