第七章-父-子关系文档

关注公众号: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
}]
}
  1. 查询作者为“OKevin”文章的所有评论(父查子)
GET http://localhost:9200/blog/article/_search
{
"query":{
"bool":{
"must":[{
"match":{
"author.keyword":"OKevin"
}
}]
}
}
}

ES结果返回2条作者为"OKevin"的全部数据。

  1. 查询评论中含有“辣鸡”的文章(子查父)
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那样将"评论"嵌套"文章"中的。

  1. 查询作者为“OKevin”文章的所有评论(父查子)
GET http://localhost:9200/blog/article/_search
{
"query":{
"has_parent":{
"parent_type":"article",
"query":{
"match":{
"author.keyword":"OKevin"
}
}
}
}
}

ES只返回了comment评论结构中的数据,而不是全部包括文章数据也返回。这是嵌套对象查询与父子文档查询的区别之一——子文档可以单独返回

  1. 查询评论中含有“辣鸡”的文章(子查父)
GET http://localhost:9200/blog/artice/_search
{
"query":{
"has_child":{
"type":"comment",
"query":{
"match":{
"content":"辣鸡"
}
}
}
}
}

ES同样也只返回了父文档的数据,而没有子文档(评论)的数据。

nested嵌套对象和parent-child父子文档之间最大的区别,嵌套对象中的"父子"是一个文档数据,而父子文档的中的"父子"是两个文档数据。这意味着嵌套对象中如果涉及对嵌套文档的操作会对整个文档造成影响(重新索引,但查询快),包括修改、删除、查询。而父子文档子文档或者父文档本身就是独立的文档,对子文档或者父文档的操作并不会相互影响(不会重新索引,查询相对慢)。

关注公众号:CoderBuff,回复“es”获取《ElasticSearch6.x实战教程》完整版PDF。

这是一个能给程序员加buff的公众号 (CoderBuff)

《ElasticSearch6.x实战教程》之父-子关系文档的更多相关文章

  1. 《ElasticSearch6.x实战教程》正式推出(附图书抽奖)

    经过接近1个月的时间,ElasticSearch6.x实战教程终于成册.这本实战教程小册有很多不足(甚至可能有错误),也是第一次完整推出一个系列的教程. 1年前,我开始真正接触ES,在此之前仅停留在知 ...

  2. 《ElasticSearch6.x实战教程》之准备工作、基本术语

    第一章-准备工作 工欲善其事必先利其器 ElasticSearch安装 ElasticSearch6.3.2下载地址(Linux.mac OS.Windows通用,下载zip包即可):https:// ...

  3. 《ElasticSearch6.x实战教程》之简单的API

    第三章-简单的API 万丈高楼平地起 ES提供了多种操作数据的方式,其中较为常见的方式就是RESTful风格的API. 简单的体验 利用Postman发起HTTP请求(当然也可以在命令行中使用curl ...

  4. 《ElasticSearch6.x实战教程》之简单搜索、Java客户端(上)

    第五章-简单搜索 众里寻他千百度 搜索是ES的核心,本节讲解一些基本的简单的搜索. 掌握ES搜索查询的RESTful的API犹如掌握关系型数据库的SQL语句,尽管Java客户端API为我们不需要我们去 ...

  5. 《ElasticSearch6.x实战教程》之复杂搜索、Java客户端(下)

    第八章-复杂搜索 黑夜给了我黑色的眼睛,我却用它寻找光明. 经过了解简单的API和简单搜索,已经基本上能应付大部分的使用场景.可是非关系型数据库数据的文档数据往往又多又杂,各种各样冗余的字段,组成了一 ...

  6. 《ElasticSearch6.x实战教程》之分词

    第四章-分词 下雨天留客天留我不留 本打算先介绍"简单搜索",对ES的搜索有一个直观的感受.但在写的过程中发现分词无论如何都绕不过去.term查询,match查询都与分词息息相关, ...

  7. 《ElasticSearch6.x实战教程》之实战ELK日志分析系统、多数据源同步

    第十章-实战:ELK日志分析系统 ElasticSearch.Logstash.Kibana简称ELK系统,主要用于日志的收集与分析. 一个完整的大型分布式系统,会有很多与业务不相关的系统,其中日志系 ...

  8. iOS Sprite Kit教程之使用帮助文档以及调试程序

    iOS Sprite Kit教程之使用帮助文档以及调试程序 IOS中使用帮助文档 在编写代码的时候,可能会遇到很多的方法.如果开发者对这些方法的功能,以及参数不是很了解,就可以使用帮助文档.那么帮助文 ...

  9. HTML5实战与剖析之跨文档消息传递(iframe传递信息)

    在来自不同域名的页面间传递消息一般统称为跨文档消息传送,简称XDM.如,www.leemagnum.com域中的页面与位于一个内嵌框架中的http://blog.csdn.net/lee_magnum ...

随机推荐

  1. UWP-HttpClient

    原文:UWP-HttpClient 基本格式: HttpClient client = new HttpClient(); Uri uri = new Uri(url); HttpResponseMe ...

  2. 自己总结OpenSSL的变化

    经过查看openssl源码自带的Makefile,发现: 1) 从0.9.7开始 https://www.openssl.org/source/old/0.9.x/openssl-0.9.7k.tar ...

  3. delphi 在多线程中使用 CreateOleObject 导致失败(一定要使用CoInitialize和CoUninitialize,举例查询WMI)

    原帖地址 http://bbs.csdn.net/topics/390481350 解决办法 procedure DisplayVideoInfo; var wmi, objs, obj : OleV ...

  4. How Qt Signals and Slots Work(感觉是通过Meta根据名字来调用)

    Qt is well known for its signals and slots mechanism. But how does it work? In this blog post, we wi ...

  5. js&jq遇到的问题(不断更新中)

    1.普通事件和事件绑定: 代码: 普通事件: var btn=document.getElementById('btn'); btn.onclick=function(){ alert("c ...

  6. 使用 Cake 推送 NuGet 包到 AzureDevops 的 Artifacts 上

    前言 大家好,我最近在想如何提交代码的时候自动的打包 NuGet 然后发布到 AzureDevOps 中的 Artifacts,在这个过程中踩了很多坑,也走了很多弯路,所以这次篇文章就是将我探索的结果 ...

  7. vue 左右滑动效果

    个人实际开发中用到的效果问题总结出来便于自己以后开发查看调用,如果也适用其他人请随意拿走勿喷就行! vue.js是现在流行的js框架之一,vue 是一套用于构建用户界面的渐进式javascript框架 ...

  8. Appium+python自动化(十一)- 元素定位秘籍助你打通任督二脉 - 下卷(超详解)

    简介 宏哥看你骨骼惊奇,印堂发亮,必是练武之奇才! 按照上一篇的节目预告,这一篇还是继续由宏哥给小伙伴们分享元素定位,是不是按照上一篇的秘籍修炼,是不是感觉到头顶盖好像被掀开,内气从头上冒出去,顿时觉 ...

  9. 惊:FastThreadLocal吞吐量居然是ThreadLocal的3倍!!!

    说明 接着上次手撕面试题ThreadLocal!!!面试官一听,哎呦不错哦!本文将继续上文的话题,来聊聊FastThreadLocal,目前关于FastThreadLocal的很多文章都有点老有点过时 ...

  10. ZooKeeper学习之路(一)—— ZooKeeper简介及核心概念

    一.Zookeeper简介 Zookeeper是一个开源的分布式协调服务,目前由Apache进行维护.Zookeeper可以用于实现分布式系统中常见的发布/订阅.负载均衡.命令服务.分布式协调/通知. ...