0、概要

在Elasticsearch实战场景中,我们或多或少会遇到嵌套文档的组合形式,反映在ES中称为父子文档。
父子文档的实现,至少包含以下两种方式:
1)父子文档
父子文档在5.X版本中通过parent-child父子type实现,即:1个索引对应多个type;
6.X+版本已经不再支持一个索引多个type,6.X+的父子索引的实现改成Join。
2)Nested嵌套类型

本文通过一个例子将Nested类型适合解决的问题、应用场景、使用方法串起来,
文中所有的DSL都在Elasticsearch6.X+验证通过。

1、Elasticsearch 数据类型全景概览

2、从一个例子说起吧

2.1 问题背景

在elasticsearch中,我们可以将密切相关的实体存储在单个文档中。 例如,我们可以通过传递一系列评论来存储博客文章及其所有评论。
举例:

{"title": "Invest Money","body": "Please start investing money as soon...","tags": ["money", "invest"],"published_on": "18 Oct 2017","comments": [{"name": "William","age": 34,"rating": 8,"comment": "Nice article..","commented_on": "30 Nov 2017"},{"name": "John","age": 38,"rating": 9,"comment": "I started investing after reading this.","commented_on": "25 Nov 2017"},{"name": "Smith","age": 33,"rating": 7,"comment": "Very good post","commented_on": "20 Nov 2017"}]
}

如上所示,所以我们有一个文档描述了一个帖子和一个包含帖子上所有评论的内部对象评论。
但是Elasticsearch搜索中的内部对象并不像我们期望的那样工作。

2.2 问题出现

现在假设我们想查找用户{name:john,age:34}评论过的所有博客帖子。 让我们再看一下上面的示例文档,找到评论过的用户。

name age
William 34
John 38
Smith 33

从列表中我们可以清楚地看到,没有34岁的用户John。
为简单起见,我们在elasticsearch索引中只有1个文档。
让我们通过查询索引来验证它:

GET /blog/_search?pretty
{"query": {"bool": {"must": [{"match": {"comments.name": "John"}},{"match": {"comments.age": 34}}]}}
}

我们的示例文档作为回复返回。 很惊讶,这是为什么呢?

2.3 原因分析

这就是为什么我说:
elasticsearch中的内部对象无法按预期工作
这里的问题是elasticsearch(lucene)使用的库没有内部对象的概念,因此内部对象被扁平化为一个简单的字段名称和值列表。
我们的文档内部存储为:

{"title":                    [ invest, money ],"body":                     [ as, investing, money, please, soon, start ],"tags":                     [ invest, money ],"published_on":             [ 18 Oct 2017 ]"comments.name":            [ smith, john, william ],"comments.comment":         [ after, article, good, i, investing, nice, post, reading, started, this, very ],"comments.age":             [ 33, 34, 38 ],"comments.rating":          [ 7, 8, 9 ],"comments.commented_on":    [ 20 Nov 2017, 25 Nov 2017, 30 Nov 2017 ]
}

如上,您可以清楚地看到,comments.name和comments.age之间的关系已丢失。
这就是为什么我们的文档匹配john和34的查询。

2.4 如何解决呢?

要解决这个问题,我们只需要对elasticsearch的映射进行一些小改动。
如果您查看索引的映射,您会发现comments字段的类型是object。
我们需要更新它的类型为nested。
我们可以通过运行以下查询来简单地更新索引的映射:

PUT /blog_new
{"mappings": {"blog": {"properties": {"title": {"type": "text"},"body": {"type": "text"},"tags": {"type": "keyword"},"published_on": {"type": "keyword"},"comments": {"type": "nested","properties": {"name": {"type": "text"},"comment": {"type": "text"},"age": {"type": "short"},"rating": {"type": "short"},"commented_on": {"type": "text"}}}}}}
}

将映射更改为Nested类型后,我们可以查询索引的方式略有变化。 我们需要使用Nested查询。
下面给出了Nested查询示例:

GET /blog_new/_search?pretty
{"query": {"bool": {"must": [{"nested": {"path": "comments","query": {"bool": {"must": [{"match": {"comments.name": "john"}},{"match": {"comments.age": 34}}]}}}}]}}
}

由于用户{name:john,age:34}没有匹配,上面的查询将不返回任何文档。

再次感到惊讶? 只需一个小小的改变即可解决问题。
这可能是我们理解的一个较小的变化,但是在elasticsearch存储我们的文档的方式上有很多变化。
在内部,嵌套对象将数组中的每个对象索引为单独的隐藏文档,这意味着可以独立于其他对象查询每个嵌套对象。
下面给出了更改映射后样本文档的内部表示:

{{"comments.name":    [ john ],"comments.comment": [ after i investing started reading this ],"comments.age":     [ 38 ],"comments.rating":  [ 9 ],"comments.date":    [ 25 Nov 2017 ]},{"comments.name":    [ william ],"comments.comment": [ article, nice ],"comments.age":     [ 34 ],"comments.rating":   [ 8 ],"comments.date":    [ 30 Nov 2017 ]},{"comments.name":    [ smith ],"comments.comment": [ good, post, very],"comments.age":     [ 33 ],"comments.rating":   [ 7 ],"comments.date":    [ 20 Nov 2017 ]},{"title":            [ invest, money ],"body":             [ as, investing, money, please, soon, start ],"tags":             [ invest, money ],"published_on":     [ 18 Oct 2017 ]}
}

如您所见,每个内部对象都在内部存储为单独的隐藏文档。 这保持了他们的领域之间的关系。

3、Nested类型的作用?

从上一小节,可以清晰的看出nested类型的特别之处。
nested类型是对象数据类型的专用版本,它允许对象数组以可以彼此独立查询的方式进行索引。

4、Nested类型的适用场景


——图片来自:rockybean教程

5、Nested类型的增、删、改、查、聚合操作详解

还是以第2节的blog_new索引示例,Nested类型的增、删、改、查操作。

5.1 Nested类型——增

新增blog和评论

POST blog_new/blog/2
{"title": "Hero","body": "Hero test body...","tags": ["Heros", "happy"],"published_on": "6 Oct 2018","comments": [{"name": "steve","age": 24,"rating": 18,"comment": "Nice article..","commented_on": "3 Nov 2018"}]
}

5.2 Nested类型——删

序号为1的评论原来有三条,现在删除John的评论数据,删除后评论数为2条。

POST  blog_new/blog/1/_update
{"script": {"lang": "painless","source": "ctx._source.comments.removeIf(it -> it.name == 'John');"}
}

5.3 Nested类型——改

将steve评论内容中的age值调整为25,同时调整了评论内容。

POST blog_new/blog/2/_update
{"script": {"source": "for(e in ctx._source.comments){if (e.name == 'steve') {e.age = 25; e.comment= 'very very good article...';}}" }
}

5.4 Nested类型——查

如前所述,查询评论字段中评论姓名=William并且评论age=34的blog信息。

GET /blog_new/_search?pretty
{"query": {"bool": {"must": [{"nested": {"path": "comments","query": {"bool": {"must": [{"match": {"comments.name": "William"}},{"match": {"comments.age": 34}}]}}}}]}}
}

5.5 Nested类型——聚合

认知前提:nested聚合隶属于聚合分类中的Bucket聚合分类。
聚合blog_new 中评论者年龄最小的值。

GET blog_new/_search
{"size": 0,"aggs": {"comm_aggs": {"nested": {"path": "comments"},"aggs": {"min_age": {"min": {"field": "comments.age"}}}}}
}

6、小结

如果您在索引中使用内部对象并做查询操作,请验证内部对象的类型是否为nested类型。 否则查询可能会返回无效的结果文档。
更新认知是非常痛苦的,不确定的问题只有亲手实践才能检验真知。

参考:
[1]http://t.cn/Evwh0uW
[2]官网6.x+:http://t.cn/Ehltakr

Elasticsearch Nested类型深入详解相关推荐

  1. Elasticsearch搜索类型(SearchType)详解

    SearchType详解 es在查询时,可以指定搜索类型为 QUERY_THEN_FETCH,QUERY_AND_FEATCH,DFS_QUERY_THEN_FEATCH和DFS_QUERY_AND_ ...

  2. ElasticSearch预警服务-Watcher详解-Schedule配置

    介绍 Watcher服务详解-定时器的设定 关于Schedule配置选择,Watcher提供了丰富的时间语法支持,采用UTC时间,来我们一起看下如何设置: 支持的设置方式: hourly:按小时周期设 ...

  3. Elasticsearch实战——function_score 查询详解

    Elasticsearch实战--function_score 查询详解 文章目录 Elasticsearch实战--function_score 查询详解 1. function_score简介 2 ...

  4. python序列类型-python序列类型种类详解

    python序列类型包括哪三种 python序列类型包括:列表.元组.字典 列表:有序可变序列 创建:userlist = [1,2,3,4,5,6] 修改:userlist[5] = 999 添加: ...

  5. python编程序列类型_python序列类型种类详解

    python序列类型包括哪三种 python序列类型包括:列表.元组.字典 列表:有序可变序列 创建:userlist = [1,2,3,4,5,6] 修改:userlist[5] = 999 添加: ...

  6. (17)System Verilog枚举类型enum详解

    (17)System Verilog枚举类型enum详解 1.1 目录 1)目录 2)FPGA简介 3)System Verilog简介 4)System Verilog枚举类型enum详解 5)结语 ...

  7. 【Redis之ZSet类型的详解ZSet类型中常用命令的实践】

    Redis之ZSet类型的详解&ZSet类型中常用命令的实践 知识回顾: 通过对Redis中的String的命令做了充分的讲解以及实践学习 通过对Redis中String类型之Bit命令的详解 ...

  8. Spring和Elasticsearch全文搜索整合详解

    Spring和Elasticsearch全文搜索整合详解 一.概述 ElasticSearch是一个基于Lucene的搜索服务器.它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web ...

  9. php 打开jnlp,PHP获取文件mimes类型步骤详解

    这次给大家带来PHP获取文件mimes类型步骤详解,PHP获取文件mimes类型的注意事项有哪些,下面就是实战案例,一起来看一下.<?php /* * Copyright 2010-2013 A ...

  10. Plotly中4种文本类型设置详解

    作者:Lemon 来源:Python数据之道 Plotly中4种文本类型设置详解 大家好,我是 Lemon . 在过去的一段时间里,我写了几篇用 Python 的交互式可视化工具 Plotly 来演示 ...

最新文章

  1. 维基链Defi时代,生态完善,持续输出
  2. matlab中reshape和repmat函数的用法
  3. iOS-高仿通讯录之商品索引排序搜索
  4. 面试题之wait()和sleep()方法区别
  5. ubuntu下opencv3和opencv2共存
  6. AD域验证DirectoryEntry用法
  7. html caption 靠左,HTML caption align 属性 | Paoo教程
  8. 寒假2019培训:跳楼机(洛谷P3403)
  9. 阿里云oss使用cdn,节省oss下行流量
  10. html鼠标滚轮监听,javascript监听鼠标滚轮事件浅析
  11. TR069在家庭网络中的应用
  12. 最新天龙八部环境-GS环境教程-【长期稳定版本】+ 视频教程
  13. 【源码开发分享】计算机毕业设计之Python+Spark+Scrapy新闻推荐系统 新闻大数据 新闻情感分析 新闻文本分类 新闻数据分析 新闻爬虫可视化 大数据毕业设计
  14. modbus slave和modbus poll
  15. Unity3D笔记十八 GL图像库
  16. 本地启动wss服务链接不成功原因
  17. 在c语言中我叫做符号变量,问渠网-C语言基础-第一节 关键字符号与变量
  18. 合伙创业人力股的具体计算方法
  19. 3D成像方法 汇总(原理解析)--- 双目视觉、激光三角、结构光、ToF、光场、全息...
  20. 【MySQL-函数】MySQL常用数学函数:round,ceil,floor,truncate,mod

热门文章

  1. 网络安全 01 - Session Fixation
  2. Win10卸载KB5014699补丁教程
  3. Springboot毕业设计毕设作品,网上图书商城系统 开题报告
  4. 为什么相机模型假设成像平面位于焦平面?
  5. linux运维的名言,Linux之父十大名言 你曾听说过几句?
  6. EfficientNET_V1
  7. windows c语言新建dos,dos命令怎么用_DOS下创建文件、文件夹
  8. 论文翻译--毫米波三维全息摄影的轻量级FMIST启发稀疏重建网络(1)
  9. 使用AutoHotKey将多行内容转成单行并翻译或获取中文拼音
  10. javaScript 琐碎