一、背景

在我们工作的过程中,有些时候我们需要用到父子文档的关系映射。**比如:**一个问题有多个答案、一本书籍有多个评论等等。此处我们可以使用 es 的 jion数据类型或 nested来实现。此处我们使用join来建立es中的父子文档关系。

二、需求

我们需要创建一个计划(plan),计划下存在活动(activity)和书籍(book),书籍下存在评论(comments)。

即层级结构为:

     plan
/ \
/ \
activity book
|
|
comments

三、前置知识

  1. 每一个mapping下只能有一个join类型的字段。
  2. 父文档和子文档必须在同一个分片(shard)上。即: 增删改查一个子文档都必须和父文档使用相同的 routing key。
  3. 每个元素只能有一个父,但是可以存在多个子。
  4. 可以为一个已经存在的 join 字段增加新的关联关系。
  5. 可以为一个已经是父的元素增加一个子元素。

join数据类型在elasticsearch中不应该像关系型数据库那种使用。而且has_childhas_parent都是比较消耗性能的。

只有当 子的数据 远远大于 父的数据时,使用join才是有意义的。比如:一个博客下,有多个评论。

四、实现步骤

1、创建 mapping

PUT /plan_index
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"plan_id":{
"type": "keyword"
},
"plan_name":{
"type": "text",
"fields": {
"keyword":{
"type" : "keyword",
"ignore_above" : 256
}
}
},
"act_id":{
"type": "keyword"
},
"act_name":{
"type": "text",
"fields": {
"keyword":{
"type" : "keyword",
"ignore_above" : 256
}
}
},
"comment_id":{
"type": "keyword"
},
"comment_name":{
"type": "text",
"fields": {
"keyword":{
"type" : "keyword",
"ignore_above" : 256
}
}
},
"creator":{
"type": "keyword"
},
"create_time":{
"type": "date",
"format": "yyyy-MM-dd||yyyy-MM-dd HH:mm:ss"
},
"plan_join": {
"type": "join",
"relations": {
"plan": ["activity", "book"],
"book": "comments"
}
}
}
}
}

注意️

2、添加父文档数据

此处添加的是 (plan) 数据。

PUT /plan_index/_doc/plan-001
{
"plan_id": "plan-001",
"plan_name": "四月计划",
"creator": "huan",
"create_time": "2021-04-07 16:27:30",
"plan_join": {
"name": "plan"
}
} PUT /plan_index/_doc/plan-002
{
"plan_id": "plan-002",
"plan_name": "五月计划",
"creator": "huan",
"create_time": "2021-05-07 16:27:30",
"plan_join": "plan"
}

注意️:

1、如果是创建父文档,则需要使用 plan_join 指定父文档的关系的名字(此处为plan)。

2、plan_join为创建索引的 mapping时指定join的字段的名字。

3、指定父文档时,plan_join的这2种写法都可以。

3、添加子文档

PUT /plan_index/_doc/act-001?routing=plan-001
{
"act_id":"act-001",
"act_name":"四月第一个活动",
"creator":"huan.fu",
"plan_join":{
"name":"activity",
"parent":"plan-001"
}
} PUT /plan_index/_doc/book-001?routing=plan-001
{
"book_id":"book-001",
"book_name":"四月读取的第一本书",
"creator":"huan.fu",
"plan_join":{
"name":"book",
"parent":"plan-001"
}
} PUT /plan_index/_doc/book-002?routing=plan-001
{
"book_id":"book-002",
"book_name":"编程珠玑",
"creator":"huan.fu",
"plan_join":{
"name":"book",
"parent":"plan-001"
}
} PUT /plan_index/_doc/book-003?routing=plan-002
{
"book_id":"book-003",
"book_name":"java编程思想",
"creator":"huan.fu",
"plan_join":{
"name":"book",
"parent":"plan-002"
}
} # 理论上 comment 的父文档是 book ,但是此处routing使用 plan 也是可以的。
PUT /plan_index/_doc/comment-001?routing=plan-001
{
"comment_id":"comment-001",
"comment_name":"这本书还可以",
"creator":"huan.fu",
"plan_join":{
"name":"comments",
"parent":"book-001"
}
} PUT /plan_index/_doc/comment-002?routing=plan-001
{
"comment_id":"comment-002",
"comment_name":"值得一读,棒。",
"creator":"huan.fu",
"plan_join":{
"name":"comments",
"parent":"book-001"
}
}

注意️:

1、子文档(子孙文档等)需要和父文档使用相同的路由键。

2、需要指定父文档的id。

3、需要指定join的名字。

4、查询文档

1、根据父文档id查询它下方的子文档

**需求:**返回父文档id是plan-001下的类型为book的所有子文档。

GET /plan_index/_search
{
"query":{
"parent_id": {
"type":"book",
"id":"plan-001"
}
}
}

2、has_child返回满足条件的父文档

**需求:**返回创建者(creator)是huan.fu,并且子文档最少有2个的父文档。

GET /plan_index/_search
{
"query": {
"has_child": {
"type": "book",
"min_children": 2,
"query": {
"match": {
"creator": "huan.fu"
}
}
}
}
}

3、has_parent返回满足父文档的子文档

**需求:**返回父文档(book)的创建者是huan.fu的所有子文档

GET /plan_index/_search
{
"query": {
"has_parent": {
"parent_type": "book",
"query": {
"match": {
"creator":"huan.fu"
}
}
}
}
}

五、Nested Object 和 join 对比

Nested Object join (Parent/Child)
1、文档存储在一起,读取性能高 1、父子文档单独存储,互不影响。但是为了维护join的关系,需要占用额外的内容,读取性能略差。
2、更新父文档或子文档时,需要更新整个文档。 2、父文档和子文档可以单独更新。
3、适用于查询频繁,子文档偶尔更新的情况。 3、适用于更新频繁的情况,且子文档的数量远远超过父文档的数量。

六、参考文档

1、join数据类型

2、has child查询

3、has parent查询

4、parent id查询

elasticsearch父子文档处理(join)的更多相关文章

  1. elasticsearch 父子文档(十一)

    说明 需求 一个产品多个区域销售 每个区域有自己的价格, 方式1冗余行,a 产品分别在  area1 area2 area3区域销售 a产品就会生成3条产品数据 搜索id去重就行了,但是问题就是 聚合 ...

  2. elasticsearch——海量文档高性能索引系统

    elasticsearch elasticsearch是一个高性能高扩展性的索引系统,底层基于apache lucene. 可结合kibana工具进行可视化. 概念: index 索引: 类似SQL中 ...

  3. ES 父子文档查询

    父子文档的特点 1. 父/子文档是完全独立的. 2. 父文档更新不会影响子文档. 3. 子文档更新不会影响父文档或者其它子文档. 父子文档的映射与索引 1. 父子关系 type 的建立必须在索引新建或 ...

  4. elasticsearch 路由文档到分片

    路由文档到分片 当你索引一个文档,它被存储在单独一个主分片上.Elasticsearch是如何知道文档属于哪个分片的呢?当你创建一个新文档,它是如何知道是应该存储在分片1还是分片2上的呢? 进程不能是 ...

  5. ElasticSearch部署文档(Ubuntu 14.04)

    ElasticSearch部署文档(Ubuntu 14.04) 参考链接 https://www.elastic.co/guide/en/elasticsearch/guide/current/hea ...

  6. ElasticSearch——原始文档和倒排索引

    一.原始文档 如上图所示, 第二象限是一份原始文档,有title和content2个字段,字段取值分别为”我是中国人”和” 热爱共X产党”,这一点没什么可解释的.我们把原始文档写入Elasticsea ...

  7. 007-elasticsearch5.4.3【一】概述、Elasticsearch 访问方式、Elasticsearch 面向文档、常用概念

    一.概述 Elasticsearch 是一个开源的搜索引擎,建立在一个全文搜索引擎库 Apache Lucene™ 基础之上. Elasticsearch 也是使用 Java 编写的,它的内部使用 L ...

  8. Elasticsearch 删除文档

    章节 Elasticsearch 基本概念 Elasticsearch 安装 Elasticsearch 使用集群 Elasticsearch 健康检查 Elasticsearch 列出索引 Elas ...

  9. Elasticsearch 更新文档

    章节 Elasticsearch 基本概念 Elasticsearch 安装 Elasticsearch 使用集群 Elasticsearch 健康检查 Elasticsearch 列出索引 Elas ...

随机推荐

  1. Tars | 第6篇 基于TarsGo Subset路由规则的Java JDK实现方式(下)

    目录 前言 1. 修改.tars协议文件 1.1 Java源码位置及逻辑分析 1.2 Java语言实现方式 1.3 通过协议文件自动生成代码 1.4 变更代码的路径 2. [核心]增添Subset核心 ...

  2. npm配置镜像及nrm使用

    ​ 淘宝npm镜像 搜索地址:http://npm.taobao.org/ registry地址:http://registry.npm.taobao.org/ cnpmjs镜像 搜索地址:http: ...

  3. 三剑客之awk 逐行读取

    目录: 一.awk工作原理 二.按行输出文本 三.按字段输出文本 四.通过管道,双引号调用shall命令 五.CPU使用率 六.使用awk 统计 httpd 访问日志中每个客户端IP的出现次数 一.a ...

  4. tar解压缩问题

    gzip: stdin: unexpected end of filetar: 归档文件中异常的 EOFtar: 归档文件中异常的 EOFtar: Error is not recoverable: ...

  5. HCNP Routing&Switching之路由策略工具Route-Policy

    前文我们了解了路由过滤和路由过滤工具Filter-Policy使用相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/15316188.html:今天我们来 ...

  6. PHP没有定时器?

    确实,PHP没有类似于JS中的setInterval或者setTimeout这样的原生定时器相关的函数.但是我们可以通过其他方式来实现,比如使用declare. 先来看看是如何实现的,然后我们再好好学 ...

  7. Jmeter系列(15)- 常用断言之大小断言

    大小断言 大小断言验证响应数据size大小,它的作用范围有主Sample与子Sample:适用场景,判断附件下载的大小,比如项目安装包 完整响应:全部响应信息 响应头:响应头信息,比如http协议的头 ...

  8. CF19E-Fairy【树形结构,差分】

    正题 题目链接:https://www.luogu.com.cn/problem/CF19E 题目大意 给出\(n\)个点\(m\)条边的一张无向图,求有多少条边去掉后可以使得图变成一张二分图. \( ...

  9. kafka高可用探究

    kafka高可用探究 众所周知 kafka 的 topic 可以使用 --replication-factor 数和 partitions 数来保证服务的高可用性 问题发现 但在最近的运维过程中,3台 ...

  10. IO之字节流

    什么是字节流 像操作 图片 视频 mp4 文档(里面可能有图片) 等等 注意点 必须使用try catch finally 来包 不用throws(流是要关闭的 如果中途抛错 throws 无法将流关 ...