一、背景

在我们工作的过程中,有些时候我们需要用到父子文档的关系映射。**比如:**一个问题有多个答案、一本书籍有多个评论等等。此处我们可以使用 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. python-request 实现企业微信接口自动化-1(DDT)

    环境准备 python+requests 读取企业微信api开发文档,得知调用企业微信接口必须先获取企业微信的accesstoken是通过 ("corpid","&quo ...

  2. ubuntu14.04 安装MySQL 5.7

    ubuntu14.04 默认在线安装MySQL 5.5 1) wget http://dev.mysql.com/get/mysql-apt-config_0.7.3-1_all.deb 2) dpk ...

  3. python库--tensorflow

    方法 返回值类型 参数 说明 张量    .constant() Tensort 张量 实例t value 创建一个常量tensor dtype=None 输出类型 shape=None 返回tens ...

  4. 学习Tomcat(三)之容器连接器

    Tomcat最底层使用的是Java标准的SocketServer和Socket接受和处理请求,但是Socket接受到的数据是网络运输层的TCP或UDP协议的数据,需要转为Http或者其它应用层协议的数 ...

  5. 设置自启动nginx(适用于其他软件)(LinuxDeploy里的Ubuntu)

    LinuxDeploy里的Ubuntu自启动nginx(适用于其他软件) 网上的教程是这样的,基本能用 1.编写脚本(这个文件及其内容安装Nginx后自动生成,没有的话内容自己Google) $ su ...

  6. 浏览器缓存旧的js文件或css文件导致没出现预期效果

    最好在加载的js或css文件后加上 ?v=1.0.0 版本号,更新js后就更改一下版本号即可

  7. 判断手机浏览器还是微信浏览器(PHP)

    //判断是否 微信浏览器 function isWeixin1() { if (strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== fa ...

  8. AT5661-[AGC040C]Neither AB nor BA【模型转换】

    正题 题目链接:https://www.luogu.com.cn/problem/AT5661 题目大意 一个包含\(A,B,C\)的序列,每次可以选择相邻的两个除了\(AB\)和\(BA\)的删去. ...

  9. CF1392G-Omkar and Pies【dp】

    正题 题目链接:https://www.luogu.com.cn/problem/CF1392G 题目大意 两个长度为\(k\)的起始和目标01串. \(n\)个操作交换起始串的两个位置,选择一段长度 ...

  10. P3170-[CQOI2015]标识设计【插头dp】

    正题 题目链接:https://www.luogu.com.cn/problem/P3170 题目大意 给出\(n*m\)的网格上有一些障碍,要求用三个\(L\)形(高宽随意,不能退化成线段/点)覆盖 ...