上一篇文章中,我们学习了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就是嵌套对象数组,那么userElasticsearch中是怎么存储的呢?如果我们要对嵌套的子对象进行检索,怎么才能检索出我们所需要的数据呢,下面我们就一起来研究下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转换成上面的这种数据结构之后,我们的搜索结果是会被影响的,假如我们使用如下这个语句进行查询,我们想搜索namehonghongsexmale,预期结果是没有匹配的文档,但是因为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=malenumberOfLikes最小值

    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、在聚合统计usernamecomment最多的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),还支持 falsestrict
  • 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嵌套对象类型还挺实用相关推荐

  1. 第十章 PL/SQL对象类型

    第十章 PL/SQL对象类型 一.抽象的角色 抽象是对一个真实世界实体的高级描述或建模.它能排除掉无关的细节内容,使我们的日常生活更有条理.例如,驾驶一辆汽车时,我们是不需要知道它的发 动机是如何工作 ...

  2. 第十章 PL/SQL对象类型 ( 1 )

    第十章 PL/SQL对象类型 一.抽象的角色 抽象是对一个真实世界实体的高级描述或建模.它能排除掉无关的细节内容,使我们的日常生活更有条理.例如,驾驶一辆汽车时,我们是不需要知道它的发动机是如何工作的 ...

  3. 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 /* 对象类型属于用户自定义的一种复合类型,它封装了数据结构和拥 ...

  4. php instanceof 基类,PHP强制对象类型之instanceof操作符

    一.简介 在php(做为现在的主流开发语言)中实现强制对象类型有时可能非常重要.如果缺少了它,或是因为缺乏这方面的知识--基于不正确的编程假设,或者仅仅是由于懒惰,那么你会在特定的Web应用程序中看到 ...

  5. “ Value of nested property ‘teacher‘ is null”内部嵌套对象为空的问题

    " Invalid property 'teacher' of bean class [com.deserts.spring.mod.Student]: Value of nested pr ...

  6. html5怎么改为vue_是否还在疑惑Vue.js中组件的data为什么是函数类型而不是对象类型...

    点击上方"前端印象",选择"设为星标"第一时间关注技术干货! 引言 要理解本篇文章,必须具备JavaScript中基本数据类型和引用数据类型的概念,大家可以花两 ...

  7. el-form表单对象内还嵌套对象,绑定的prop规则校验会失效

    继续踩坑~.因为受限于后端返回的数据格式,整个表单是个对象,但是里面还会嵌套对象. 而我们在绑定字段时,自然而然是去绑定最里层的字段. el-form的model是去绑定大的表单对象. 而我这里的表单 ...

  8. 第4章 介绍Python对象类型

    看前须知 这里对本书中提到的不常见的内容进行了查证,举例,所以大家可以不用再费神去搜索相关内容 在Python中,我们运用"材料"来处理"事务". 材料:操作对 ...

  9. python映射类型是什么意思_Python对象类型

    Python对象类型 2019-02-04 蘭喆 蘭喆的生活 问题1:Python知识结构? 答:1.程序由模块构成:2.模块包含语句:3.语句包含表达式:4.表达式创建并处理对象. 问题2:Pyth ...

最新文章

  1. Spring Boot——Druid在application.yml文件中配置【spring.datasource.druid.aop-patterns】无效解决方案
  2. 8000字 | Python数据可视化,完整版实操指南 !
  3. 2020CCPC(长春) - Strange Memory(树上启发式合并+位运算)
  4. 高效、稳定开发功能的一些心得
  5. web.xml 配置
  6. php案例之后台数据显示-- mysqli面向过程版(procedure oriented programming = POP)
  7. MATLAB获取字符串中两个特定字符之间的内容
  8. 在windows10上安装texlive的参考文档
  9. vue单页面怎么做SEO优化
  10. vitrualbox虚拟机64位安装报错解决
  11. 大聪明教你学Java | EasyExcel - 用更简单的方式操作Excel
  12. 苹果要和 ARM 在 WWDC 举办「婚礼」,定义下一个 10 年
  13. 各种风格登录页响应式html5模板 Admin后台管理系统模板手机wap登录页html模板html会员登录页面模板源码70多套高大尚响应式网站模板html5网页静态模板Bootstrap扁平化网站源码
  14. iOS 15个人热点无法连接?10个修复技巧分享
  15. spark:Action算子:show()
  16. 如何截取第一个括号_王者荣耀如何取空白名和重复名
  17. 设备Kingston DataTraveler 3.0无法连接到理想的主机控制器。将尝试将该设备连接到可用的最佳主机控制器......
  18. 最详解消息队列以及RabbbitMQ之HelloWorld
  19. JavaScript sort 方法 默认排序顺序为按字母升序-数组常用方法
  20. 利用LSTM+CNN+glove词向量预训练模型进行微博评论情感分析(二分类)

热门文章

  1. cent7卸载linux桌面,CentOS7卸载KDE桌面
  2. 有道高调进入在线教育,要怎么做?
  3. 打游戏的蓝牙耳机推荐哪一款?打游戏比较好的蓝牙耳机推荐
  4. 读《三体——地球往事》
  5. note3版本介绍,优劣总结
  6. python输入年月日输出年月日_Python编程基础04:输入与输出
  7. Eclipse+Maven+Struts2+Spring+Mybatis完整搭建
  8. mysql学习笔记(六)
  9. 如何修改sql服务器名,修改SQL Server数据库服务器名字
  10. 各种装逼,我痛苦的捂住脸扭向一边!