《ElasticSearch6.x实战教程》之父-子关系文档
第七章-父-子关系文档
关注公众号:CoderBuff,回复“es”获取《ElasticSearch6.x实战教程》完整版PDF。
打虎亲兄弟,上阵父子兵。
本章作为复杂搜索的铺垫,介绍父子文档是为了更好的介绍复杂场景下的ES操作。
在非关系型数据库数据库中,我们常常会有表与表的关联查询。例如学生表和成绩表的关联查询就能查出学会的信息和成绩信息。在ES中,父子关系文档就类似于表的关联查询。
背景
ES5.x开始借助父子关系文档实现多表关联查询,核心是一个索引Index下可以创建多个类型Type。但ES6.x开始只允许一个索引Index下创建一个类型Type,甚至在未来的版本中将会移除创建类型Type。为了继续支持多表关联查询,ES6.x推出了join新类型来支持父子关系文档的创建。
问题
假设现在有这样的需求场景:一个博客有多篇文章,文章有标题、内容、作者、日期等信息,同时一篇文章中会有评论,评论有评论的内容、作者、日期等信息,通过ES来存储博客的文章及评论信息。
此时文章本身就是"父",而评论就是"子",这类问题也可以通过nested嵌套对象实现,大部分情况下netsted嵌套对象和parent-child父子对象能够互相替代,但他们仍然不同的优缺点。下面将介绍这两种数据结构。
nested嵌套对象
一篇文章的数据结构如下图所示:
{
"title":"ElasticSearch6.x实战教程",
"author":"OKevin",
"content":"这是一篇水文",
"created":1562141626000,
"comments":[{
"name":"张三",
"content":"写的真菜",
"created":1562141689000
},{
"name":"李四",
"content":"辣鸡",
"created":1562141745000
}]
}
通过RESTful API创建索引及定义映射结构:
PUT http://localhost:9200/blog
{
"mappings":{
"article":{
"properties":{
"title":{
"type":"text",
"analyzer":"ik_smart",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"author":{
"type":"text",
"analyzer":"ik_smart",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"content":{
"type":"text",
"analyzer":"ik_smart"
},
"created":{
"type":"date"
},
"comments":{
"type":"nested",
"properties":{
"name":{
"type":"text",
"analyzer":"ik_smart",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"content":{
"type":"text",
"analyzer":"ik_smart",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"created":{
"type":"date"
}
}
}
}
}
}
}
插入数据:
POST http://localhost:9200/blog/article
{
"title":"ElasticSearch6.x实战教程",
"author":"OKevin",
"content":"这是一篇水文",
"created":1562141626000,
"comments":[{
"name":"张三",
"content":"写的真菜",
"created":1562141689000
},{
"name":"李四",
"content":"辣鸡",
"created":1562141745000
}]
}
POST http://localhost:9200/blog/article
{
"title":"ElasticSearch6.x从入门到放弃",
"author":"OKevin",
"content":"这是一篇ES从入门到放弃文章",
"created":1562144089000,
"comments":[{
"name":"张三",
"content":"我已入门",
"created":1562144089000
},{
"name":"李四",
"content":"我已放弃",
"created":1562144089000
}]
}
POST http://localhost:9200/blog/article
{
"title":"ElasticSearch6.x原理解析",
"author":"专家",
"content":"这是一篇ES原理解析的文章",
"created":1562144089000,
"comments":[{
"name":"张三",
"content":"牛逼,专家就是不一样",
"created":1562144089000
},{
"name":"李四",
"content":"大牛",
"created":1562144089000
}]
}
- 查询作者为“OKevin”文章的所有评论(父查子)
GET http://localhost:9200/blog/article/_search
{
"query":{
"bool":{
"must":[{
"match":{
"author.keyword":"OKevin"
}
}]
}
}
}
ES结果返回2条作者为"OKevin"的全部数据。
- 查询评论中含有“辣鸡”的文章(子查父)
GET http://localhost:9200/blog/article/_search
{
"query":{
"bool":{
"must":[{
"match":{
"author.keyword":"OKevin"
}
},{
"nested":{
"path":"comments",
"query":{
"bool":{
"must":[{
"match":{
"comments.content":"辣鸡"
}
}]
}
}
}
}]
}
}
}
ES确实只返回了包含"辣鸡"的数据。
两次查询都直接返回了整个文档数据。
parent-child父子文档
既然父子文档能实现表的关联查询,那它的数据结构就应该是这样:
文章数据结构
{
"title":"ElasticSearch6.x实战教程",
"author":"OKevin",
"content":"这是一篇实战教程",
"created":1562141626000,
"comments":[]
}
评论数据结构
{
"name":"张三",
"content":"写的真菜",
"created":1562141689000
}
ES6.x以前是将这两个结构分别存储在两个类型Type中关联(这看起来更接近关系型数据库表与表的关联查询),但在ES6.x开始一个索引Index只能创建一个类型Type,要再想实现表关联查询,就意味着需要把上述两张表揉在一起,ES6.x由此定义了一个新的数据类型——join。
通过RESTful API创建索引及定义映射结构:
{
"mappings":{
"article":{
"properties":{
"title":{
"type":"text",
"analyzer":"ik_smart",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"author":{
"type":"text",
"analyzer":"ik_smart",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"content":{
"type":"text",
"analyzer":"ik_smart"
},
"created":{
"type":"date"
},
"comments":{
"type":"join",
"relations":{
"article":"comment"
}
}
}
}
}
}
重点关注其中的"comments"字段,可以看到类型定义为join,relations定义了谁是父谁是子,"article":"comment"表示article是父comment是子。
父子文档的插入是父与子分别插入(因为可以理解为把多个表塞到了一张表里)。
插入父文档:
POST http://localhost:9200/blog/article/1
{
"title":"ElasticSearch6.x实战教程",
"author":"OKevin",
"content":"这是一篇水文",
"created":1562141626000,
"comments":"article"
}
POST http://localhost:9200/blog/article/2
{
"title":"ElasticSearch6.x从入门到放弃",
"author":"OKevin",
"content":"这是一篇ES从入门到放弃文章",
"created":1562144089000,
"comments":"article"
}
POST http://localhost:9200/blog/article/3
{
"title":"ElasticSearch6.x原理解析",
"author":"专家",
"content":"这是一篇ES原理解析的文章",
"created":1562144089000,
"comments":"article"
}
插入子文档:
POST http://localhost:9200/blog/article/4?routing=1
{
"name":"张三",
"content":"写的真菜",
"created":1562141689000,
"comments":{
"name":"comment",
"parent":1
}
}
POST http://localhost:9200/blog/article/5?routing=1
{
"name":"李四",
"content":"辣鸡",
"created":1562141745000,
"comments":{
"name":"comment",
"parent":1
}
}
POST http://localhost:9200/blog/article/6?routing=2
{
"name":"张三",
"content":"我已入门",
"created":1562144089000,
"comments":{
"name":"comment",
"parent":2
}
}
POST http://localhost:9200/blog/article/7?routing=2
{
"name":"李四",
"content":"我已放弃",
"created":1562144089000,
"comments":{
"name":"comment",
"parent":2
}
}
POST http://localhost:9200/blog/article/8?routing=3
{
"name":"张三",
"content":"牛逼,专家就是不一样",
"created":1562144089000,
"comments":{
"name":"comment",
"parent":3
}
}
POST http://localhost:9200/blog/article/9?routing=3
{
"name":"李四",
"content":"大牛",
"created":1562144089000,
"comments":{
"name":"comment",
"parent":3
}
}
如果查询索引数据会发现一共有9条数据,并不是nested那样将"评论"嵌套"文章"中的。
- 查询作者为“OKevin”文章的所有评论(父查子)
GET http://localhost:9200/blog/article/_search
{
"query":{
"has_parent":{
"parent_type":"article",
"query":{
"match":{
"author.keyword":"OKevin"
}
}
}
}
}
ES只返回了comment评论结构中的数据,而不是全部包括文章数据也返回。这是嵌套对象查询与父子文档查询的区别之一——子文档可以单独返回。
- 查询评论中含有“辣鸡”的文章(子查父)
GET http://localhost:9200/blog/artice/_search
{
"query":{
"has_child":{
"type":"comment",
"query":{
"match":{
"content":"辣鸡"
}
}
}
}
}
ES同样也只返回了父文档的数据,而没有子文档(评论)的数据。
nested嵌套对象和parent-child父子文档之间最大的区别,嵌套对象中的"父子"是一个文档数据,而父子文档的中的"父子"是两个文档数据。这意味着嵌套对象中如果涉及对嵌套文档的操作会对整个文档造成影响(重新索引,但查询快),包括修改、删除、查询。而父子文档子文档或者父文档本身就是独立的文档,对子文档或者父文档的操作并不会相互影响(不会重新索引,查询相对慢)。
关注公众号:CoderBuff,回复“es”获取《ElasticSearch6.x实战教程》完整版PDF。

《ElasticSearch6.x实战教程》之父-子关系文档的更多相关文章
- 《ElasticSearch6.x实战教程》正式推出(附图书抽奖)
经过接近1个月的时间,ElasticSearch6.x实战教程终于成册.这本实战教程小册有很多不足(甚至可能有错误),也是第一次完整推出一个系列的教程. 1年前,我开始真正接触ES,在此之前仅停留在知 ...
- 《ElasticSearch6.x实战教程》之准备工作、基本术语
第一章-准备工作 工欲善其事必先利其器 ElasticSearch安装 ElasticSearch6.3.2下载地址(Linux.mac OS.Windows通用,下载zip包即可):https:// ...
- 《ElasticSearch6.x实战教程》之简单的API
第三章-简单的API 万丈高楼平地起 ES提供了多种操作数据的方式,其中较为常见的方式就是RESTful风格的API. 简单的体验 利用Postman发起HTTP请求(当然也可以在命令行中使用curl ...
- 《ElasticSearch6.x实战教程》之简单搜索、Java客户端(上)
第五章-简单搜索 众里寻他千百度 搜索是ES的核心,本节讲解一些基本的简单的搜索. 掌握ES搜索查询的RESTful的API犹如掌握关系型数据库的SQL语句,尽管Java客户端API为我们不需要我们去 ...
- 《ElasticSearch6.x实战教程》之复杂搜索、Java客户端(下)
第八章-复杂搜索 黑夜给了我黑色的眼睛,我却用它寻找光明. 经过了解简单的API和简单搜索,已经基本上能应付大部分的使用场景.可是非关系型数据库数据的文档数据往往又多又杂,各种各样冗余的字段,组成了一 ...
- 《ElasticSearch6.x实战教程》之分词
第四章-分词 下雨天留客天留我不留 本打算先介绍"简单搜索",对ES的搜索有一个直观的感受.但在写的过程中发现分词无论如何都绕不过去.term查询,match查询都与分词息息相关, ...
- 《ElasticSearch6.x实战教程》之实战ELK日志分析系统、多数据源同步
第十章-实战:ELK日志分析系统 ElasticSearch.Logstash.Kibana简称ELK系统,主要用于日志的收集与分析. 一个完整的大型分布式系统,会有很多与业务不相关的系统,其中日志系 ...
- iOS Sprite Kit教程之使用帮助文档以及调试程序
iOS Sprite Kit教程之使用帮助文档以及调试程序 IOS中使用帮助文档 在编写代码的时候,可能会遇到很多的方法.如果开发者对这些方法的功能,以及参数不是很了解,就可以使用帮助文档.那么帮助文 ...
- HTML5实战与剖析之跨文档消息传递(iframe传递信息)
在来自不同域名的页面间传递消息一般统称为跨文档消息传送,简称XDM.如,www.leemagnum.com域中的页面与位于一个内嵌框架中的http://blog.csdn.net/lee_magnum ...
随机推荐
- 理解typedef(转)
// 从别人那转的,调整下格式便于阅读. 首先请看看下面这两句: typedef ]; typedef void (*p)(void); 如果你能一眼就看出它们的意思,那请不要再往下看了.如果你不太理 ...
- QML被系统缓存的原理是比较时间戳
Gunnar Roth January 25, 2017 at 17:07 Afaik the cached qml file contains a checksum of the original ...
- ***R(TCP over UDP,UDP over TCP)
https://github.com/breakwa11/shadowsocks-rss
- DataVeryLite入门教程(二) Entity篇
DataVeryLite 是基于.net 4.0的数据库持久化ORM框架. 目前支持的数据库有Sqlserver,Mysql,Oracle,Db2,PostgreSql,Sqlite和Access. ...
- Hexo+NexT(二):Hexo站点配置详解
阅读本篇之前,假定读者已经有了Node.js的基础,如需要补充Node.js知识的,请自行百度. Hexo是在Node.js框架下的一个项目,利用Node.js提供的强大功能,完成从Markdown到 ...
- node.js简单数据接口开发
随着网络时代的快速发展,前端开发不仅仅是做出漂亮的页面就可以了,还要会一点后端语言,那么后端语言有Java,php,node.js最常见,那我们应该学哪一种呢,为了让我们自己更好的学习,我推荐选择no ...
- javaweb中Servlet配置到Tomcat
1.tomcat容器来运行Servlet程序 在javase中,都是在控制台中运行java代码,而且提供了一个main方法,代码运行的入口.在javaee中,想要运行java代码,不是通过控制台程序来 ...
- hdoj1009 FatMouse' Trade——贪心算法
贪心思路:按单位猫粮能兑换到的javaBean从大到小将组合进行排序,总是在当前兑换尽可能多的javabeans 问题描述:点击打开链接 hdoj1009 FatMouse's Trade 源代码: ...
- 建设DevOps统一运维监控平台,全面的系统监控 Zabbix VS Nagios VS Open-Falcon OR Prometheus
前言 随着Devops.云计算.微服务.容器等理念的逐步落地和大力发展,机器越来越多,应用越来越多,服务越来越微,应用运行基础环境越来多样化,容器.虚拟机.物理机不一而足.面对动辄几百上千个虚拟机.容 ...
- 源码阅读 - java.util.concurrent (二)CAS
背景 在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁 锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度延时,引起性能问题. ...