Nested嵌套对象类型还挺实用
上一篇文章中,我们学习了Join
类型的父子文档,今天继续学习一下嵌套文档,毕竟嵌套文档也是Elasticsearch
推荐的,首先我们看下面这条语句
PUT word_document/_doc/1
{"title" : "up","user" : [ {"name" : "honghong","sex" : "female","numberOfLikes":500},{"name" : "mingming","sex" : "male","numberOfLikes":50},{"name" : "lanlan","sex" : "male","numberOfLikes":100}]
}
对于上面这种格式的数据,user
就是嵌套对象数组,那么user
在Elasticsearch
中是怎么存储的呢?如果我们要对嵌套的子对象进行检索,怎么才能检索出我们所需要的数据呢,下面我们就一起来研究下Nested
数据类型
环境
macos 10.14.6
Elasticsearch 8.1
Kibana 8.1
Nested
开头我们还是先了解一下,什么是Nested
类型,其实就是字面意思,Nested
就是嵌套,也就是文章开头user
数据类型那种,所以可以看为是一种特殊的Object
类型。还是以文章开头的数据为例
PUT word_document/_doc/1
{"title" : "up","user" : [ {"name" : "honghong","sex" : "female","numberOfLikes":500},{"name" : "mingming","sex" : "male","numberOfLikes":50},{"name" : "lanlan","sex" : "male","numberOfLikes":100}]
}
如果我们没有对word_document
索引进行显示设置数据类型,在上面这个语句执行之后,Elasticsearch会默认推断数据类型,在Elasticsearch中内容会转换为可能如下的形式,扁平化的处理数据
{ "title":"up", "user.name":["honghong","mingming","lanlan"], "user.sex":["male","male","female"], "user.numberOfLikes":[500,50,100]}
相信大家也看出来了,如果被Elasticsearch
转换成上面的这种数据结构之后,我们的搜索结果是会被影响的,假如我们使用如下这个语句进行查询,我们想搜索name
是honghong
,sex
是male
,预期结果是没有匹配的文档,但是因为Elasticsearch
对上述的结果进行了扁平化的处理,造成了错误的匹配
GET word_document/_search
{"query": {"bool": {"must": [{ "match": { "user.name": "honghong" }},{ "match": { "user.sex": "male" }}]}}
}
如何避免上述情况的发生呢,那就是使用Elasticsearch
提供的Nested
数据类型,Nested
数据类型保证了嵌套对象的独立性,也就是让我们可以对嵌套对象的内容进行检索,从而不会发生上述的这种情况
首先我们还是以上面文档为例,不过是这次我们优先创建索引,并指定
user
字段为nested
PUT word_document {"mappings": {"properties": {"title":{"type": "keyword"},"user": {"type": "nested" },"numberOfLikes":{"type": "integer"}}} }
下面加入我们的测试数据,来验证我们的搜索语句
PUT word_document/_doc/1 {"title" : "up","user" : [ {"name" : "honghong","sex" : "female","numberOfLikes":500},{"name" : "mingming","sex" : "male","numberOfLikes":50},{"name" : "lanlan","sex" : "male","numberOfLikes":100}] } PUT word_document/_doc/2 {"title" : "up","user" : [ {"name" : "honghong","sex" : "female","numberOfLikes":20},{"name" : "mingming","sex" : "male","numberOfLikes":30},{"name" : "lanlan","sex" : "male","numberOfLikes":50}] } PUT word_document/_doc/3 {"title" : "up","user" : [ {"name" : "honghong","sex" : "female","numberOfLikes":50},{"name" : "mingming","sex" : "male","numberOfLikes":50},{"name" : "lanlan","sex" : "male","numberOfLikes":50}] }
下面还是刚才那个搜索语句,此时就不会有匹配的文档返回,返回结果为空
GET word_document/_search {"query": {"nested": {"path": "user","query": {"bool": {"must": [{ "match": { "user.name": "honghong" }},{ "match": { "user.sex": "male" }} ]}}}} }
那么对于嵌套文档我们可以怎么查询呢,那就是指定
nested
查询类型,使用普通的查询是查询不到的哦,nested
查询语句如下所示,此时返回的就是我们GET word_document/_search {"query": {"nested": {"path": "user","query": {"bool": {"must": [{ "match": { "user.name": "honghong" }},{ "match": { "user.sex": "female" }} ]}},"inner_hits": { "highlight": {"fields": {"user.name": {}}}}}} }
此外我们还可以根据嵌套对象中的字段进行排序,升序时获取嵌套对象中最小的值最为比较值,降序时获取嵌套对象最大的值作为比较值
GET word_document/_search {"query": {"nested": {"path": "user","query": {"match": {"user.sex": "male"}}}},"sort":[{"user.numberOfLikes": {"order": "asc", "nested": {"path":"user"}}}] }
返回如下
{"took" : 101,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 3,"relation" : "eq"},"max_score" : null,"hits" : [{"_index" : "word_document","_id" : "2","_score" : null,"_source" : {"title" : "up","user" : [{"name" : "honghong","sex" : "female","numberOfLikes" : 20},{"name" : "mingming","sex" : "male","numberOfLikes" : 30},{"name" : "lanlan","sex" : "male","numberOfLikes" : 50}]},"sort" : [20]},{"_index" : "word_document","_id" : "1","_score" : null,"_source" : {"title" : "up","user" : [{"name" : "honghong","sex" : "female","numberOfLikes" : 500},{"name" : "mingming","sex" : "male","numberOfLikes" : 50},{"name" : "lanlan","sex" : "male","numberOfLikes" : 100}]},"sort" : [50]},{"_index" : "word_document","_id" : "3","_score" : null,"_source" : {"title" : "up","user" : [{"name" : "honghong","sex" : "female","numberOfLikes" : 50},{"name" : "mingming","sex" : "male","numberOfLikes" : 50},{"name" : "lanlan","sex" : "male","numberOfLikes" : 50}]},"sort" : [50]}]} }
我们也可以对嵌套对象进行聚合操作,如下我们获取索引中
user.name=honghong
,user.sex=female
的所有文档,聚合统计numberOfLikes
的最小值GET word_document/_search {"query": {"nested": {"path": "user","query": {"bool": {"must": [{"match": {"user.name": "honghong"}},{"match": {"user.sex": "female"}}]}}}},"aggs": {"my_min_value": {"nested": {"path": "user"}, "aggs": {"min_value": {"min": {"field": "user.numberOfLikes"}}}}} }
上面的聚合统计只是对外部的文档过滤,那如果我们有这么一个需求,聚合统计嵌套对象
user
内容sex=male
的最小值,那么我们可以使用如下filter,下面这个语句优先过滤title=up
的文档,聚合统计user.sex=male
的numberOfLikes
最小值GET /word_document/_search?size=0 {"query": {"match": {"title": "up"}},"aggs": {"my_user": {"nested": {"path": "user"},"aggs": {"filter_my_user": {"filter": {"bool": {"filter": [{"match": {"user.sex": "male"}}]}},"aggs": {"min_price": {"min": {"field": "user.numberOfLikes"}}}},"no_filter_my_user":{"min": {"field": "user.numberOfLikes"}}}}} }
最后还有一种就是反向嵌套聚合,通过嵌套对象聚合父文档,返回父文档信息
首先我们还是先创建一个索引添加几条数据用来测试
PUT /issues {"mappings": {"properties": {"tags": { "type": "keyword" },"comments": { "type": "nested","properties": {"username": { "type": "keyword" },"comment": { "type": "text" }}}}} } PUT /issues/_doc/1 {"tags":"跳舞","comments":[{"username":"小李","comment":"小李想学跳舞"},{"username":"小红","comment":"小红跳舞很有天赋"}] } PUT /issues/_doc/2 {"tags":"唱歌","comments":[{"username":"小李","comment":"小李会唱歌"},{"username":"小李","comment":"小李唱歌有天赋"},{"username":"小红","comment":"小红是歌手"}] } PUT /issues/_doc/3 {"tags":"跳舞","comments":[{"username":"小红","comment":"小红会跳舞"},{"username":"小红","comment":"小红是舞神"}] } PUT /issues/_doc/4 {"tags":"唱歌","comments":[{"username":"小李","comment":"小李简直就是天生歌手"}] } PUT /issues/_doc/5 {"tags":"跳舞","comments":[{"username":"小红","comment":"小红舞姿很美"}] }
issues 问题;tags 标签;username 名字;comment 评论;
下面我们使用反向嵌套聚合父文档,需求如下:
1、先聚合统计出评论最多的
username
2、在聚合统计
username
中comment
最多的tag
GET /issues/_search?size=0 {"query": {"match_all": {}},"aggs": {"comments": {"nested": {"path": "comments"},"aggs": {"top_usernames": {"terms": {"field": "comments.username"},"aggs": {"comment_to_issue": {"reverse_nested": {}, "aggs": {"top_tags_per_comment": {"terms": {"field": "tags"}}}}}}}}} }
结果如下,得出结论:
小红
评论次数最多,评论了5次
,小红评论最多的标签是跳舞
,有3次
{"aggregations" : {"comments" : {"doc_count" : 9,"top_usernames" : {"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [{"key" : "小红","doc_count" : 5,"comment_to_issue" : {"doc_count" : 4,"top_tags_per_comment" : {"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [{"key" : "跳舞","doc_count" : 3},{"key" : "唱歌","doc_count" : 1}]}}},{"key" : "小李","doc_count" : 4,"comment_to_issue" : {"doc_count" : 3,"top_tags_per_comment" : {"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [{"key" : "唱歌","doc_count" : 2},{"key" : "跳舞","doc_count" : 1}]}}}]}}} }
Nested 支持的参数有哪些
Nested
也只是特殊的Object
的一种,也是有支持的几种参数
dynamic
: (可选参数) 是否允许在索引mapping
文件未定义字段的情况下对新字段的处理,默认是加入到现有的嵌套对象中(true
),还支持false
,strict
properties
: (可选参数) 嵌套对象字段内容属性设置
include_in_parent
:(可选参数) 默认false
,如果为true
,嵌套对象的字段也会作为普通字段的形式(flat
)添加到父文档
include_in_root
:(可选参数) 默认false
,如果为true
,嵌套对象的字段也会作为普通字段的形式(flat
)添加到根文档
Nested 类型的约束
通过前面的学习,我们也知道了nested类型可以作为一个单独的Lucene
文档进行所有,当我们有100
个嵌套对象的时候我们需要101
个文档来存储映射关系,一个用于父文档,一个用于嵌套文档,所以这一部分的开销,ELasticsearch
来通过一下设置进行了约束
index.mapping.nested_fields.limit
一个索引中,嵌套类型字段(nested)最多存在多个限制,默认
50个
,如我们上面的例子中,也就是只占用了一个index.mapping.nested_objects.limit
一个索引中,单个嵌套类型字段包含的嵌套
JSON
对象的最大数量,默认10000
总结
通过上面的学习实践,我们可以知道Nested
嵌套类型是Elasticsearch
推荐的相对于Join
类型,并且Nested
可以实现查询,聚合,排序等,基本满足了工作的需要。好了,到这就结束吧,有什么需要深入了解的,留言哦,也可以去官网查看,毕竟官网还是一手资料,博主的也只能算是入门启蒙笔记,实践起来吧,加油!
Join 字段的详解可以参考博主的这一篇文章哦
本文由 mdnice 多平台发布
Nested嵌套对象类型还挺实用相关推荐
- 第十章 PL/SQL对象类型
第十章 PL/SQL对象类型 一.抽象的角色 抽象是对一个真实世界实体的高级描述或建模.它能排除掉无关的细节内容,使我们的日常生活更有条理.例如,驾驶一辆汽车时,我们是不需要知道它的发 动机是如何工作 ...
- 第十章 PL/SQL对象类型 ( 1 )
第十章 PL/SQL对象类型 一.抽象的角色 抽象是对一个真实世界实体的高级描述或建模.它能排除掉无关的细节内容,使我们的日常生活更有条理.例如,驾驶一辆汽车时,我们是不需要知道它的发动机是如何工作的 ...
- Oracle PL/SQL存储过程对象类型Object type详解 create type obj_type as object, create table tab_name of obj_type
原 oracle 对象类型 object type 置顶 2011年06月13日 18:00:00 oypj2010 阅读数:3453 /* 对象类型属于用户自定义的一种复合类型,它封装了数据结构和拥 ...
- php instanceof 基类,PHP强制对象类型之instanceof操作符
一.简介 在php(做为现在的主流开发语言)中实现强制对象类型有时可能非常重要.如果缺少了它,或是因为缺乏这方面的知识--基于不正确的编程假设,或者仅仅是由于懒惰,那么你会在特定的Web应用程序中看到 ...
- “ Value of nested property ‘teacher‘ is null”内部嵌套对象为空的问题
" Invalid property 'teacher' of bean class [com.deserts.spring.mod.Student]: Value of nested pr ...
- html5怎么改为vue_是否还在疑惑Vue.js中组件的data为什么是函数类型而不是对象类型...
点击上方"前端印象",选择"设为星标"第一时间关注技术干货! 引言 要理解本篇文章,必须具备JavaScript中基本数据类型和引用数据类型的概念,大家可以花两 ...
- el-form表单对象内还嵌套对象,绑定的prop规则校验会失效
继续踩坑~.因为受限于后端返回的数据格式,整个表单是个对象,但是里面还会嵌套对象. 而我们在绑定字段时,自然而然是去绑定最里层的字段. el-form的model是去绑定大的表单对象. 而我这里的表单 ...
- 第4章 介绍Python对象类型
看前须知 这里对本书中提到的不常见的内容进行了查证,举例,所以大家可以不用再费神去搜索相关内容 在Python中,我们运用"材料"来处理"事务". 材料:操作对 ...
- python映射类型是什么意思_Python对象类型
Python对象类型 2019-02-04 蘭喆 蘭喆的生活 问题1:Python知识结构? 答:1.程序由模块构成:2.模块包含语句:3.语句包含表达式:4.表达式创建并处理对象. 问题2:Pyth ...
最新文章
- Spring Boot——Druid在application.yml文件中配置【spring.datasource.druid.aop-patterns】无效解决方案
- 8000字 | Python数据可视化,完整版实操指南 !
- 2020CCPC(长春) - Strange Memory(树上启发式合并+位运算)
- 高效、稳定开发功能的一些心得
- web.xml 配置
- php案例之后台数据显示-- mysqli面向过程版(procedure oriented programming = POP)
- MATLAB获取字符串中两个特定字符之间的内容
- 在windows10上安装texlive的参考文档
- vue单页面怎么做SEO优化
- vitrualbox虚拟机64位安装报错解决
- 大聪明教你学Java | EasyExcel - 用更简单的方式操作Excel
- 苹果要和 ARM 在 WWDC 举办「婚礼」,定义下一个 10 年
- 各种风格登录页响应式html5模板 Admin后台管理系统模板手机wap登录页html模板html会员登录页面模板源码70多套高大尚响应式网站模板html5网页静态模板Bootstrap扁平化网站源码
- iOS 15个人热点无法连接?10个修复技巧分享
- spark:Action算子:show()
- 如何截取第一个括号_王者荣耀如何取空白名和重复名
- 设备Kingston DataTraveler 3.0无法连接到理想的主机控制器。将尝试将该设备连接到可用的最佳主机控制器......
- 最详解消息队列以及RabbbitMQ之HelloWorld
- JavaScript sort 方法 默认排序顺序为按字母升序-数组常用方法
- 利用LSTM+CNN+glove词向量预训练模型进行微博评论情感分析(二分类)
热门文章
- cent7卸载linux桌面,CentOS7卸载KDE桌面
- 有道高调进入在线教育,要怎么做?
- 打游戏的蓝牙耳机推荐哪一款?打游戏比较好的蓝牙耳机推荐
- 读《三体——地球往事》
- note3版本介绍,优劣总结
- python输入年月日输出年月日_Python编程基础04:输入与输出
- Eclipse+Maven+Struts2+Spring+Mybatis完整搭建
- mysql学习笔记(六)
- 如何修改sql服务器名,修改SQL Server数据库服务器名字
- 各种装逼,我痛苦的捂住脸扭向一边!