Elasticsearch:如何在 Elasticsearch 中存储复杂的关系数据

这篇具有很好参考价值的文章主要介绍了Elasticsearch:如何在 Elasticsearch 中存储复杂的关系数据。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Elasticsearch:如何在 Elasticsearch 中存储复杂的关系数据

在传统的数据库中,对数据关系的描述无外乎三种:一对一、一对多和多对多关系。 如果有关系相关的数据,我们一般在建表的时候加上主外键。 建立数据链接,然后在查询或者统计中通过 join 恢复或者补全数据,最后得到我们需要的结果数据,然后转换到 Elasticsearch中,如何处理这些关系数据呢?

我们都知道 Elasticsearch 是一个 NoSQL 类型的数据库,弱化了对关系的处理,因为像 Lucene、Elasticsearch、Solor 这样的全文搜索框架对性能的要求更高。 一旦发生 join 操作,性能会很差,所以在使用搜索框架的时候,应该避免把搜索引擎当作关系型数据库来使用。

当然实际数据肯定是有关联的,那么在 Elasticsearch 中如何处理和管理这些关联数据呢?

大家都知道 Elasticsearch 天生支持 JSON 数据是完美的,只要是标准 JSON 结构的数据,不管多复杂,不管嵌套多少层,都可以存储在 Elasticsearch 中,然后可以查询分析,检索。在该机制中,处理和管理关系的方式主要有以下三种:

1)使用 object 和 array[object] 字段类型自动存储多层结构的 JSON 数据

这是 Elasticsearch 默认的机制,也就是我们没有设置任何 mapping,直接往 Elasticsearch 服务器插入一个复杂的 JSON 数据,也能插入成功,而且可以支持检索,(可以这样是因为 Elasticsearch 默认是动态的 mapping ,只要插入标准的 JSON 结构就会自动转换,当然我们也可以控制映射类型,Elasticsearch 支持动态映射和静态映射,静态映射也分严格类型,弱类型,通用类型,不再在这里展开。有兴趣的可以到官网了解)如下数据之一:

PUT cars/_doc/1
{
  "name": "Zach",
  "car": [
    {
      "maker": "Saturn",
      "model": "SL"
    },
    {
      "maker": "Subaru",
      "model": "Imprezza"
    }
  ]
}

我们在 Kibana 中直接打入上面的命令,我们可以查看这个 cars 索引的 mapping。

GET cars/_mapping

上面的命令返回的结果:

{
  "cars": {
    "mappings": {
      "properties": {
        "car": {
          "properties": {
            "maker": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "model": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            }
          }
        },
        "name": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        }
      }
    }
  }
}

生成的存储结构类似于以下内容:

{  
  "name"  :  "Zach" ,  
  "car.maker"  : [ "Saturn" , "Subaru" ]  
  "car.model"  : [ "SL" ,  "Imprezza" ]  
}

因为 Elasticsearch 的底层 Lucene 是天然支持多值存储的,所以看起来像上面的数组结构。 实际上,Elasticsearch 是作为一个多值字段存储在这个字段中的。

这样的数据实际上包含了数据和关系。 它看起来像一个一对多的关系。 一个人拥有多辆汽车。 但其实并不是严格的关系,因为 Lucene 底层是平放存储的,所以多辆车的数据其实是混在一起的 数据,你不能根据人名来返回其中的一辆车,因为整个数据是一个整体,无论什么操作都会返回整个数据。

上述的数据结够,在有些时候是很有用的,但是它不能维护 car.maker 及 car.model 的对应关系。比如我们查询 car.maker 为 Subaru 时,它不能返回 car.model 为 Imprezza。

更多阅读,请参阅我之前的文章 “Elasticsearch: object 及 nested 数据类型”。

2)使用 nested[object] 类型来存储具有多级关系的数据

Elasticsearch:如何在 Elasticsearch 中存储复杂的关系数据

在上面的场景中,我们指出了 array 中存储的数组对象并不是严格相关的,因为第二层的数据没有分离。 如果要分离,则必须使用 nested 类型显式定义数据结构。 只有这样,第二层的多辆汽车数据才相互独立,也就是说可以单独获取或查询某辆汽车的数据。Nested 类型是 object 数据类型的特殊版本。它允许对象数组以一种可以彼此独立查询的方式进行索引

同样的 JSON 数据:


  "name": "Zach",
  "car": [
    {
      "maker": "Saturn",
      "model": "SL"
    },
    {
      "maker": "Subaru",
      "model": "Imprezza"
    }
  ]

如果我们使用上面的 object 来进行存储的话,那么 Elasticsearch 将把整个信息当做一个整体进行存储。如果我们把 car 数据定义为 nested 数据类型,它的形式如下:

PUT cars
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "car": {
        "type": "nested",
        "properties": {
          "maker": {
            "type": "keyword"
          },
          "model": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

如上所示, car 被定义为 nested 数据类型。最终 Elasticsearch 显示的存储为3个:1 个是 root 文档,另外两个是 car 数组中的两个文档。查询的时候可以独立查询,性能还不错,缺点是更新的代价比较大,每次子文档更新都要重建整个结构的索引,所以 nested 适用于嵌套多级关系不经常更新的场景。

Nested 类型的数据,需要使用其指定的查询和聚合方式才能生效,普通的 Elasticsearch 查询只能查询 1 级或根级属性,nested 属性无法查询,如果要查询,必须使用 embedded 的 Set 查询或聚合。

嵌套应用程序有两种模式:

  • 嵌套查询:每个查询在单个文档中有效,包括排序
  • 嵌套聚合或过滤:同级别所有文档全局有效,包括过滤排序

更多阅读:Elasticsearch: object 及 nested 数据类型

3)父/子关系

父/子模式与嵌套非常相似,但应用侧重点不同。

在使用 parent/children 管理关系时,Elasticsearch 会在每个 shard 的内存中维护一张关系表。 检索时,关联数据由 has_parent 和 has_child 过滤器获取。 在这种模式下,使用父文档和子文档。 也是独立的,查询性能会比嵌套模式略低,因为插入时父文档和子文档会通过路由分布在同一个 shard,但不保证在同一个Lucene sengment index segment,所以检索性能略低。 此外,每次检索 Elasticsearch 时,都需要从内存关系表中获取数据关联信息。 也需要一定的时间。 嵌套的好处是更新父文档或子文档。 不影响其他文档,所以更新频繁的多级关系使用 parent/children 模式是最合适的。

在 Elasticsearch 中,Join 可以让我们创建 parent/child 关系。Elasticsearch 不是一个 RDMS。通常 join 数据类型尽量不要使用,除非不得已。那么 Elasticsearch 为什么需要 Join 数据类型呢?

在 Elasticsearch 中,更新一个 object 需要 root object 一个完整的 reindex:

  • 即使是一个 field 的一个字符的改变
  • 即便是 nested object 也需要完整的 reindex 才可以实现搜索

通常情况下,这是完全 OK 的,但是在有些场合下,如果我们有频繁的更新操作,这样可能对性能带来很大的影响。

join 数据类型可以完全地把两个 object 分开,但是还是保持这两者之前的关系。

  1. parent 及 child 是完全分开的两个文档
  2. parent 可以单独更新而不需要重新 reindex child
  3. children 可以任意被添加/串改/删除而不影响 parent 及其它的 children

与 nested 类型类似,父子关系也允许你将不同的实体关联在一起,但它们在实现和行为上有所不同。 与 nested 文档不同,它们不在同一文档中,而 parent/child 文档是完全独立的文档。 它们遵循一对多关系原则,允许你将一种类型定义为 parent 类型,将一种或多种类型定义为 child 类型

即便 join 数据类型给我们带来了方便,但是,它也在搜索时给我带来额外的内存及计算方便的开销。

join 数据类型是一个特殊字段,用于在同一索引的文档中创建父/子关系。 关系部分定义文档中的一组可能关系,每个关系是父(parent)名称和子(child)名称。 

一个例子:

PUT my_index
{
  "mappings": {
    "properties": {
      "my_join_field": { 
        "type": "join",
        "relations": {
          "question": "answer" 
        }
      }
    }
  }
}

在这里我们定义了一个叫做 my_index 的索引。在这个索引中,我们定义了一个 field,它的名字是 my_join_field。它的类型是 join 数据类型。同时我们定义了单个关系:question 是 answer 的 parent。

要使用 join 来 index 文档,必须在 source 中提供关系的 name 和文档的可选 parent。 例如,以下示例在 question 上下文中创建两个 parent 文档:

PUT my_index/_doc/1?refresh
{
  "text": "This is a question",
  "my_join_field": {
    "name": "question" 
  }
}
 
PUT my_index/_doc/2?refresh
{
  "text": "This is another question",
  "my_join_field": {
    "name": "question"
  }
}

更多阅读:Elasticsearch:Join 数据类型,Elasticsearch:在 Elasticsearch 中的 join 数据类型父子关系。文章来源地址https://www.toymoban.com/news/detail-446819.html

总结

方法一:

  • 简单、快速、高性能
  • 善于维持一对一的关系
  • 无需特别查询

方法二:

  • 由于底层存储在同一个 Lucene sengment 中,因此读取和查询性能比较方法更快。
  • 更新单个子文档会重建整个数据结构,所以不适合更新频繁嵌套的场景。
  • 可以维护一对多和多对多的存储关系

方法三:

  • 多关系数据,存储完全独立,但存在于同一个分片中,因此读取和查询性能略低于第二种方式。
  • 需要额外内存,维护管理关系表
  • 更新文档不会影响其他子文档,适合更新频繁使用的场景。
  • 排序和打分操作繁琐,需要额外的脚本函数支持
  • 每种方式都有自己适合的应用场景,所以在实践中,我们需要根据实际业务场景选择合适的存储方式

到了这里,关于Elasticsearch:如何在 Elasticsearch 中存储复杂的关系数据的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spark、RDD、Hive 、Hadoop-Hive 和传统关系型数据库区别

    Hive Hadoop Hive 和传统关系型数据库区别 Spark 概念 基于内存的分布式计算框架 只负责算 不负责存 spark 在离线计算 功能上 类似于mapreduce的作用 MapReduce的缺点 运行速度慢 (没有充分利用内存) 接口比较简单,仅支持Map Reduce 功能比较单一 只能做离线计算 Spark优势 运行速度快

    2024年02月13日
    浏览(33)
  • Elasticsearch 对比传统数据库:深入挖掘 Elasticsearch 的优势

    当你为项目选择数据库或搜索引擎时,了解每个选项的细微差别至关重要。 今天,我们将深入探讨 Elasticsearch 的优势,并探讨它与传统 SQL 和 NoSQL 数据库的比较。 Elasticsearch 以强大的 Apache Lucene 库为基础,是一个分布式搜索和分析引擎。 它以其速度、可扩展性以及快速索引

    2024年02月10日
    浏览(33)
  • es elasticsearch 八 mapping 映射 、复杂数据类型

    目录 Mapping 映射 复杂数据类型 Mapping 映射 精确匹配 必须和对应字段值安全一致才可查出 全文检索 缩写搜索全程、格式转换 大小写 同义词 全文检索核心原理 分词,初步的倒排索引的建立 重建倒排索引 时态转换、重复数的转换、同义词的转换、大小写的转换 分词器 analy

    2024年02月07日
    浏览(45)
  • Java操作elasticSearch复杂查询以及解析数据以及索引保存数据

    说明:基于银行测试库的操作 es的银行测试库,看一个Kibana操作 然后用java检索解析这个数据 聚合搜索 address 中包含 mill 的所有人的年龄分布以及平均薪资 以下是分解思路实现步骤: #聚合搜索 address 中包含 mill 的所有人的年龄分布以及平均年龄 GET bank/_search { “query”:{ “

    2024年02月10日
    浏览(48)
  • Python爬虫之关系型数据库存储#5

    爬虫专栏:   关系型数据库是基于关系模型的数据库,而关系模型是通过二维表来保存的,所以它的存储方式就是行列组成的表,每一列是一个字段,每一行是一条记录。表可以看作某个实体的集合,而实体之间存在联系,这就需要表与表之间的关联关系来体现,如主键外键

    2024年02月20日
    浏览(34)
  • Elasticsearch与关系型数据库集成

    Elasticsearch是一个开源的搜索和分析引擎,基于Lucene库开发,具有高性能、可扩展性和实时性等特点。关系型数据库则是一种结构化数据库管理系统,以表格形式存储数据,支持SQL查询语言。在现实应用中,Elasticsearch与关系型数据库往往需要进行集成,以实现更高效、灵活的

    2024年02月20日
    浏览(55)
  • Elasticsearch数据存储优化方案

    优化Elasticsearch数据存储有助于提升系统性能、降低成本、提高数据查询效率以及增强系统的稳定性和可靠性。通常我们再优化Elasticsearch数据存储会遇到一些问题,导致项目卡壳。以下是优化Elasticsearch数据存储的一些重要作用: 1、问题背景 在某些场景中,我们可能会考虑绕

    2024年04月09日
    浏览(27)
  • Elasticsearch数据存储与查询

    Elasticsearch数据存储与查询 Elasticsearch是一个分布式、实时的搜索和分析引擎,基于Lucene库开发。它可以处理大量数据,提供快速、准确的搜索结果。Elasticsearch支持多种数据类型的存储和查询,如文本、数值、日期等。它还提供了强大的分析功能,如词频统计、提取等。

    2024年02月19日
    浏览(27)
  • elasticSearch数据存储与搜索基本原理

    为啥想学习es,主要是在工作中会用到,但是因为不了解原理,所以用起来畏手畏脚的,就想了解下es是怎么存储数据,以及es是怎么搜索数据的,我们平时应该如何使用es,以及使用时候需要注意的方面。 es:https://github.com/elastic/elasticsearch lucene:https://github.com/apache/lucene.git es是

    2024年02月16日
    浏览(25)
  • 常规操作elasticSearch查看和索引(存储)数据

    常规操作elasticSearch: 对于elasticSearch的操作 通常用rest API完成 查看所有节点: 示例返回: 查看健康状态: 示例返回: 查看主节点: 示例返回: 查看所有索引(类比mysql查看所数据库): 示例返回: 保存一条数据 put 保存: 注意: put保存必须有id(唯一识别) 示例返回:

    2023年04月08日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包