Elasticsearch中父子文档的关联:利用Join类型赋予文档的层级关系

news2024/11/19 19:36:24
码到三十五 : 个人主页

心中有诗画,指尖舞代码,目光览世界,步履越千山,人间尽值得 !

Elasticsearch是一个强大的搜索引擎,它提供了丰富的功能来满足复杂的搜索需求。其中,父子索引类型的join功能是一个强大的工具,它允许我们在同一索引中创建具有层级关系的文档。在这篇博客中,我们将深入探讨Elasticsearch中的父子索引类型join,包括其工作原理、如何使用以及需要注意的事项。

目录

    • 前言
      • 1. 父子关系文档
      • 2. Nested嵌套类型
      • 3. Nested类型和父子类型的差异
    • 一、使用对象数组存在的问题
    • 二、父子索引类型join的工作原理和作用
      • 父子join关联解决的问题
      • 使用join字段的优势
    • 三、父子join关联的使用
      • 3.1 创建带join字段的索引
      • 3.2 添加父子文档
      • 3.3 特殊搜索方式
      • 3.4 聚集操作
    • 四、应用层关联数据
    • 五、注意事项和性能考虑
    • 结语

前言

在Elasticsearch的实际应用中,嵌套文档是一个常见的需求,尤其是当我们需要对对象数组进行独立索引和查询时。在Elasticsearch中,这类嵌套结构被称为父子文档,它们能够“彼此独立地进行查询”。实现这一功能主要有两种方式:

1. 父子关系文档

  • 在Elasticsearch 5.x版本中,这种关系是通过parent-child父子type来实现的,允许一个索引对应多个type。
  • 但从6.x版本开始,由于Elasticsearch不再支持单个索引对应多个type,因此父子索引的实现方式转变为使用Join数据类型。

2. Nested嵌套类型

  • 这是一种更为紧凑和高效的方式来处理嵌套文档,允许在单个文档中直接嵌套其他文档,并保持它们之间的关联性,便于进行复杂的查询操作。

3. Nested类型和父子类型的差异

Nested类型

  1. 数据结构:Nested类型用于索引和查询对象数组,其中每个对象都可以看作是一个独立的文档。这些对象在内部被视为独立的文档,可以独立地进行索引和查询。
  2. 查询性能:由于Nested类型的每个嵌套对象都是独立索引的,因此查询性能相对较高。你可以直接针对嵌套对象的特定字段进行查询,而无需扫描整个文档。
  3. 使用场景:当你有一个文档,其中包含多个与主文档相关联的子对象时,例如一个订单文档中包含多个商品项,每个商品项都有自己的一组属性,这时使用Nested类型是非常合适的。
  4. 更新限制:更新Nested类型中的一个嵌套对象通常需要重新索引整个主文档,这可能会影响性能。

在这里插入图片描述
父子类型

  1. 数据结构:父子Join类型允许你将两个独立的文档(父文档和子文档)通过关系字段连接起来。每个文档都是单独存储的,但它们之间通过特定的join字段来建立关联。
  2. 查询性能:查询性能可能略低于Nested类型,因为父子文档是分开存储的,查询时可能需要进行额外的连接操作。
  3. 使用场景:当你需要处理具有一对多关系的文档时,例如博客文章(父文档)和评论(子文档),或者用户和他们的订单等场景,父子Join类型是一个很好的选择。
  4. 更新灵活性:与Nested类型不同,使用父子Join类型时,你可以独立地更新父文档或子文档,而无需重新索引与其相关联的文档。这提供了更大的灵活性,特别是在需要频繁更新或添加新关联数据的情况下。

Nested类型和父子Join类型在处理关联数据时各有优势。Nested类型更适合处理静态的、紧密关联的嵌套数据,而父子Join类型则更适合处理需要动态更新或具有一对多关系的文档。

一、使用对象数组存在的问题

对象数组的默认存储方式

Elasticsearch内部并不直接支持对象的层次结构,而是将对象层次结构扁平化为一个字段名和字段值的简单列表。这种处理方式可能导致数据关联性的丢失。例如,考虑以下文档:

PUT user/user_info/1
{
  "group": "man",
  "userName": [ 
    {
      "first": "张",
      "last": "三"
    },
    {
      "first": "李",
      "last": "四"
    }
  ]
}

如果我们尝试查询first为“张”且last为“四”的数据,按照常理,这样的数据应该不存在。然而,使用以下查询:

GET /user/user_info/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "userName.first": "张"
          }
        },
        {
          "match": {
            "userName.last": "四"
          }
        }
      ]
    }
  }
}

意外地,我们可能会得到结果。这是因为Lucene(Elasticsearch的底层库)没有内部对象的概念,它将内部对象扁平化处理了。在内部,文档实际上被存储为:

{
  "group": "man",
  "userName.first": ["张", "李"],
  "userName.last": ["三", "四"]
}

可以看到,userName.firstuserName.last被扁平化为多值字段,它们之间的关联性已经丢失,因此查询结果可能不符合我们的预期。

二、父子索引类型join的工作原理和作用

在Elasticsearch中,父子索引类型join是通过特殊的字段类型来实现的,该字段类型被称为“join”。这个字段允许我们定义文档之间的父子关系。当我们创建一个包含join字段的索引时,我们需要指定哪些文档类型是父文档,哪些是子文档。

在底层,Elasticsearch使用特殊的路由机制来确保父子文档存储在同一个分片上。这是非常重要的,因为这样可以提高查询性能并确保数据的一致性。当我们索引一个子文档时,需要使用routing参数来指定其父文档的ID,以便Elasticsearch可以将它们路由到相同的分片。

父子join关联解决的问题

  1. 数据层级关系的表示:在实际应用中,很多数据天然具有层级或关联关系。例如,一个博客系统可能包含博客文章和对应的评论,其中博客文章是父级数据,而评论是与文章相关联的子级数据。父子索引类型允许在Elasticsearch中明确地表示这种数据之间的层级关系。

  2. 关联查询的优化:当数据之间存在关联关系时,我们经常需要进行跨层级的查询。比如,我们可能想要找到所有包含特定评论的博客文章,或者查找某篇博客文章下的所有评论。通过使用父子索引类型,Elasticsearch可以高效地处理这类关联查询,因为它内部优化了父子文档之间的关联访问。

  3. 数据聚合和分析:在数据分析场景下,我们可能需要对具有层级关系的数据进行聚合操作。父子索引类型使得这类聚合更加直观和高效。例如,可以很容易地统计每篇博客文章有多少评论,或者分析不同类型的博客文章下评论的分布情况。

  4. 文档间的引用完整性:在某些情况下,确保文档间的引用完整性是很重要的。通过使用父子关系,可以更容易地管理和维护这种完整性。例如,当删除一个父文档时,可以方便地找到并处理所有相关的子文档。

  5. 简化数据模型:在某些情况下,使用父子关系可以简化数据模型的设计。通过将相关联的数据组织在同一个索引中,并明确它们的层级关系,可以减少数据冗余和提高数据的一致性。

虽然父子索引类型提供了解决上述问题的有效手段,但它也带来了一些额外的复杂性和性能考虑。因此,在使用之前需要仔细评估数据模型和查询需求,以确定是否适合使用父子索引类型。

使用join字段的优势

join字段提供了一种在索引中明确定义父子文档之间关系的方法。使用join字段的优势在于:

  • 独立操作:可以独立地对子文档进行增加、删除和修改操作,而不需要对整个数组进行操作。
  • 性能优化:父子文档位于同一索引,减少了查询时的网络开销,因为不需要跨索引进行搜索。
  • 特殊搜索方式:支持以父搜子、以子搜父等特殊搜索方式,使得查询更加灵活和高效。
  • 聚集操作:join字段还支持children和parent聚集操作,用于对父子文档进行统计分析。

三、父子join关联的使用

3.1 创建带join字段的索引

创建一个新的索引,并定义好父子文档的映射关系。在映射中加入join字段,并设置好父子关系的名称。例如,我们可以定义一个订单索引,其中包含商品子文档。

PUT order-join
{
  "settings": {
    "number_of_shards": 5,
    "number_of_replicas": 1
  },
  "mappings": {
    "properties": {
      "orderid": { "type": "integer" },
      "buyer": { "type": "keyword" },
      "order_time": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss" },
      "goodsid": { "type": "integer" },
      "goods_name": { "type": "keyword" },
      "price": { "type": "double" },
      "produce_time": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss" },
      "my_join_field": {
        "type": "join",
        "relations": {
          "order": "goods"
        }
      }
    }
  }
}

3.2 添加父子文档

在添加文档时,需要明确指定文档的父子关系。父文档只需指定join字段的关系名称,而子文档则需指定父文档的主键和关系名称。

PUT order-join/_doc/1
{
  "orderid": "1",
  "buyer": "tom",
  "order_time": "2020-11-04 00:00:00",
  "my_join_field": {
    "name": "order"
  }
}

PUT order-join/_doc/2?routing=1
{
  "goodsid": "1",
  "goods_name": "milk",
  "price": 5.2,
  "produce_time": "2020-10-04 00:00:00",
  "my_join_field": {
    "name": "goods",
    "parent": "1"
  }
}

3.3 特殊搜索方式

利用join字段,可以实现一些特殊的搜索操作:

  • 以父搜子:通过父文档的属性来查询子文档。例如,我们可以查询所有属于特定买家的商品。

    POST order-join/_search
    {
      "query": {
        "has_parent": {
          "parent_type": "order",
          "query": {
            "term": {
              "buyer": {
                "value": "tom"
              }
            }
          }
        }
      }
    }
    
  • 以子搜父:通过子文档的属性来查询父文档。例如,我们可以查询所有包含特定商品的订单。

    POST order-join/_search
    {
      "query": {
        "has_child": {
          "type": "goods",
          "query": {
            "match_all": {}
          }
        }
      }
    }
    
  • 父文档主键搜索:通过父文档的主键值来查询所有关联的子文档。例如,我们可以查询订单号为1的所有商品。

    POST order-join/_search
    {
      "query": {
        "parent_id": {
          "type": "goods",
          "id": "1"
        }
      }
    }
    

3.4 聚集操作

join字段还支持children和parent聚集操作,用于对父子文档进行统计分析。

  • children聚集:统计每个父文档的子文档数据。例如,我们可以统计每个买家购买的商品名称和数量。

    POST order-join/_search
    {
      "query": {
        "match_all": {}
      },
      "aggs": {
        "orders": {
          "terms": {
            "field": "buyer",
            "size": 10
          },
          "aggs": {
            "goods_data": {
              "children": {
                "type": "goods"
              },
              "aggs": {
                "goods_name": {
                  "terms": {
                    "field": "goods_name",
                    "size": 10
                  }
                }
              }
            }
          }
        }
      }
    }
    
  • parent聚集:统计每个子文档的父文档数据。例如,我们可以统计每种商品的购买者信息。

    POST order-join/_search
    {
      "aggs": {
        "goods": {
          "terms": {
            "field": "goods_name",
            "size": 10
          },
          "aggs": {
            "goods_data": {
              "parent": {
                "type": "goods"
              },
              "aggs": {
                "orders": {
                  "terms": {
                    "field": "buyer",
                    "size": 10
                  }
                }
              }
            }
          }
        }
      }
    }
    

四、应用层关联数据

除了使用join字段,还可以在应用层通过外键字段来实现父子关联。这种方法需要为父文档和子文档分别建立索引,并在查询时进行多次请求。虽然这种方法在处理父子关系时可能不如join字段高效,但它提供了更多的灵活性。

五、注意事项和性能考虑

  • 性能影响:由于父子文档必须存储在同一个分片上,这可能会对索引的性能产生影响。当数据量非常大时,单个分片上的文档数量可能会增加,从而影响查询和索引性能。因此,在设计数据模型时需要谨慎考虑父子关系的使用。
  • 数据一致性:当更新或删除父子文档时,需要确保数据的一致性。Elasticsearch不会自动处理父子文档之间的一致性,因此需要应用程序逻辑来确保数据同步。

结语

Elasticsearch中的父子索引类型join是一个强大的工具,它允许我们在同一索引中创建具有层级关系的文档。通过正确使用join字段和相关的查询DSL,我们可以有效地表示和查询具有父子关系的数据模型。然而,在使用时需要注意性能影响和数据一致性等问题,并确保与当前Elasticsearch版本的兼容性。



听说...关注下面公众号的人都变牛了,纯技术,纯干货 !

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1594101.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

离谱!奇安信人事总监透露:Web安全不会岗位这些就别投简历了

有人的地方就有江湖,有互联网安全的地方,就必然有Web安全工程师的身影。但其实Web安全是近几年才备受关注的,从事这方面的专业人员并不多,这就导致整个市场Web安全研究员的供求严重不平衡。 这种供求不平衡直接反映在Web安全研究…

Windows沙盒:sandboxie-plus工作原理及安装使用指导

文章目录 1、简介2、工作原理3、主要功能4、安装4.1、下载安装文件4.2、运行安装程序4.3、选择安装路径 5、使用方法6、总结 1、简介 Sandboxie是一款安全软件,也被称为沙箱。它的主要功能是创建一个隔离的虚拟环境,用户能够在其中运行或安装应用程序&a…

mmdetection模型使用mmdeploy部署在windows上的c++部署流程【详细全面版】

0. 前置说明: 该文档适用于:已经使用mmdetection训练好了模型,并且完成了模型转换。要进行模型部署了。 1. 概述 MMDeploy 定义的模型部署流程,如下图所示: 模型转换【待撰写,敬请期待…】 主要功能是:把输入的模型格式,转换为目标设备的推理引擎所要求的模型格式…

973: 统计利用先序遍历创建的二叉树叶结点的个数

解法&#xff1a; #include<iostream> #include<queue> using namespace std; // 定义二叉树结点 struct TreeNode {char val;TreeNode* left;TreeNode* right;TreeNode(char x) :val(x), left(NULL), right(NULL) {}; }; // 先序递归遍历建立二叉树 TreeNode* bu…

C++11---多线程

看前须知&#xff1a;如果对线程不了解的&#xff0c;可以先去看Linux---多线程(上)&#xff0c;(下)这两篇文章 那里主要讲了线程的一些基础概念和底层相关理解&#xff0c;对我们阅读这篇文章会有所帮助 一、thread --- 线程 1、thread相关接口介绍 在C11之前&#xff0c;涉…

汇编语言程序设计-1-绪论

1. 绪论 文章目录 1. 绪论1.1 导学1.2 为什么要学汇编语言1.3 由机器语言到汇编语言1.4 计算机的组成1.5 内存的读写与地址空间1.6 汇编语言实践环境搭建 参考视频&#xff1a;烟台大学贺利坚老师的网课《汇编语言程序设计系列专题》&#xff0c;或者是B站《汇编语言程序设计 贺…

MybatisPlus实现数据权限隔离

引言 Mybatis Plus对Mybatis做了无侵入的增强&#xff0c;非常的好用&#xff0c;今天就给大家介绍它的其中一个实用功能&#xff1a;数据权限插件。 数据权限插件的应用场景和多租户的动态拦截拼接SQL一样。建议点赞收藏关注&#xff0c;方便以后复习查阅。 依赖 首先导入M…

c/c++普通for循环学习

学习一下 for 循环的几种不同方式&#xff0c;了解一下原理及差异 完整的测试代码参考 GitHub &#xff1a;for 循环测试代码 1 常用形态 对于 for 循环来说&#xff0c;最常用的形态如下 for (表达式1; 表达式2; 表达式3) {// code }流程图如下&#xff1a; 编写测试代码…

【随笔】Git 高级篇 -- 项目里程碑 git tag(二十)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

12 Php学习:魔术常量

PHP魔术常量 PHP 向它运行的任何脚本提供了大量的预定义常量。 不过很多常量都是由不同的扩展库定义的&#xff0c;只有在加载了这些扩展库时才会出现&#xff0c;或者动态加载后&#xff0c;或者在编译时已经包括进去了。 有八个魔术常量它们的值随着它们在代码中的位置改…

Java——类和对象

目录 一.类定义和使用 1.简单认识类 2.类的定义格式 3.注意事项 二.课堂练习 1.定义一个狗类 2.定义一个学生类 3.注意事项&#xff1a; 三.类的实例化 1.什么是实例化 2.注意事项 3.类和对象的说明 四.this引用 1.为什么要有this引用 2.什么是this引用 五.对…

MySQL进阶二

目录 1.使用环境 2.排序窗口函数 3.聚合窗口函数 1.使用环境 数据库&#xff1a;MySQL 8.0.30 客户端&#xff1a;Navicat 15.0.12 接续MySQL进阶一&#xff1a; MySQL进阶一-CSDN博客文章浏览阅读452次&#xff0c;点赞9次&#xff0c;收藏4次。MySQL进阶操作一。https…

ThignsBoard通过服务端订阅共享属性

MQTT基础 客户端 MQTT连接 通过服务端订阅属性 案例 1、首先需要创建整个设备的信息&#xff0c;并复制访问令牌 ​​2、通过工具MQTTX连接上对应的Topic 3、测试链接是否成功 4、在MQTT上订阅对应的Topic 5、在客户端添加共享属性信息 6、查看整个设备的遥测数据 M…

Qt 窗⼝

Qt 窗⼝ 菜单栏创建菜单栏在菜单栏中添加菜单创建菜单项在菜单项之间添加分割线综合⽰例 ⼯具栏创建⼯具栏设置停靠位置设置浮动属性设置移动属性综合⽰例状态栏状态栏的创建在状态栏中显⽰实时消息在状态栏中显⽰永久消息 浮动窗⼝浮动窗⼝的创建设置停靠的位置 对话框对话框介…

Spring声明式事务控制

文章目录 1.编程式事务控制相关对象(了解即可)1.1PlarformTransactionManager1.2 TransactionDefinition 2.基于XML的声明式事务控制2.1声明式事务控制的实现 3.基于注解的声明式事务控制 1.编程式事务控制相关对象(了解即可) 1.1PlarformTransactionManager PlatformTransac…

NL2SQL实践系列(1):深入解析Prompt工程在text2sql中的应用技巧

NL2SQL实践系列(1)&#xff1a;深入解析Prompt工程在text2sql中的应用技巧 NL2SQL基础系列(1)&#xff1a;业界顶尖排行榜、权威测评数据集及LLM大模型&#xff08;Spider vs BIRD&#xff09;全面对比优劣分析[Text2SQL、Text2DSL] NL2SQL基础系列(2)&#xff1a;主流大模型…

LLM应用开发框架LangChain

1、LangChain简介 1.1、LangChain发展史 LangChain 的作者是 Harrison Chase&#xff0c;最初是于 2022 年 10 月开源的一个项目&#xff0c;在 GitHub 上获得大量关注之后迅速转变为一家初创公司。2017 年 Harrison Chase 还在哈佛上大学&#xff0c;如今已是硅谷的一家热门…

314_C++_QT表格的撤销、恢复,可对多行、多item进行撤销、恢复操作

行–删除后的,撤销、恢复图示: 原图示 删除后 撤销操作 恢复操作 item修改后的撤销、恢复 原item 撤销修改 恢复修改 代码: --</

vue快速入门(二十四)输入停顿再进行响应

注释很详细&#xff0c;直接上代码 上一篇 新增内容 使用侦听器监视数据变化情况使用clearTimeout与定时器实现停顿一段时间再操作内容 源码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"view…

Chatgpt掘金之旅—有爱AI商业实战篇|播客剧本写作|(十三)

演示站点&#xff1a; https://ai.uaai.cn 对话模块 官方论坛&#xff1a; www.jingyuai.com 京娱AI 一、AI技术创业播客剧本写作服务有哪些机会&#xff1f; 人工智能&#xff08;AI&#xff09;技术作为当今科技创新的前沿领域&#xff0c;为创业者提供了广阔的机会和挑战。…