《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 ...
随机推荐
- Android零基础入门第84节:引入Fragment原来是这么回事
随着大众生活水平的提高,再加上移动互联网的迅速发展,几乎每个人都至少拥有一台搭载Android系统的移动设备.Android设备的多样性给我们带来了很大的便捷,各Android设备拥有不同分辨率和不同 ...
- 海康sdk
package com.hikvision.artemis.sdk.util; import java.util.Collections; import java.util.Iterator; imp ...
- 多玩YY语音的面试题:C++中如何在main()函数之前执行操作?
多玩YY语音的面试题:C++中如何在main()函数之前执行操作? 第一反应main()函数是所有函数执行的开始.但是问题是main()函数执行之前如何执行呢? 联想到MFC里面的 C**App类的t ...
- HTTP.SYS 详解 (网络转载)
http.sys 是一个位于Win2003和WinXP SP2中的操作系统核心组件, 能够让任何应用程序通过它提供的接口,以http协议进行信息通讯. 温馨提示:如果用户不慎删除了该驱动文件,不用担心 ...
- pycharm窗口选项卡管理
1.主题 我们已经注意到Pycharm的主编辑框是基于窗口选项卡机制显示的,Pycharm选项卡多种多样,这里我们将详细介绍这种选项卡机制. 2.激活的选项卡 每当我们打开一个Python文件时op ...
- Qemu搭建ARM vexpress开发环境(二)----通过u-boot启动Linux内核
Qemu搭建ARM vexpress开发环境(二)----通过u-boot启动Linux内核 标签(空格分隔): Qemu ARM Linux 在上文<Qemu搭建ARM vexpress开发环 ...
- java关键字-final
final特点: 1:这个关键字是一个修饰符,可以修饰类,方法,变量. 2:被final修饰的类是一个最终类,不可以被继承. 3:被final修饰的方法是一个最终方法,不可以被覆盖. 4:被final ...
- YARN分析系列之三 -- 从脚本入口分析 ResourceManager的初始化过程
1. 由脚本找到 RM 主类 这部分,我们从脚本作为入口去逐步深入ResourceManager源码. 从 Hadoop 官方文档 中可以看到 ResourceManager 的启动命令为: Usag ...
- phpstorm+xdebug手机app调试
1.安装过程网上搜一下全都是,这里省略. 2.由于debug调试需要去判断cookie中XDEBUG_SESSION,然后去调试.由于app接口请求没法去传,而且就算去传递也很麻烦,还要让app去改动 ...
- 44 | 测试先行:测试驱动开发(TDD)