Elasticsearch索引之嵌套类型:深度剖析与实战应用

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: Elasticsearch索引之嵌套类型:深度剖析与实战应用

前言

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

父子文档关系:

在Elasticsearch 5.x版本中,这种关系是通过parent-child父子type来实现的,允许一个索引对应多个type。

但从6.x版本开始,由于Elasticsearch不再支持单个索引对应多个type,因此父子索引的实现方式转变为使用Join数据类型。

Nested嵌套类型:

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

简而言之,Elasticsearch提供了灵活的方式来处理嵌套文档和父子文档关系,以满足不同场景下的查询需求。

一、嵌套类型作用

(1)Nested类型:Nested是Elasticsearch中一种特殊的数据类型,专为处理对象数组设计。它允许对数组中的每个对象进行独立的索引和查询,保持对象内部字段间的关联性。

(2)对象数组的默认存储方式

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被扁平化为多值字段,它们之间的关联性已经丢失,因此查询结果可能不符合我们的预期。

(3)使用Nested类型解决问题

为了解决上述问题并保持对象内部字段的关联性,我们可以使用Nested类型。通过Nested类型,Elasticsearch能够正确地处理对象数组,使得我们可以对数组中的每个对象进行独立的查询,从而得到准确的结果。

二、nested 类型与object 类型的不同点

嵌套对象(nested object)相较于普通的对象(object)类型,在Elasticsearch中具有独特的特点和功能。以下是它们之间的主要差异:

嵌套对象(nested object)

  • 概述:嵌套类型是对象数据类型的一个特定版本,专为对象数组设计,使得数组中的每个对象都可以被独立地索引和查询。
  • 特征

字段相关性的保留:每个嵌套对象被独立索引后,能够确保对象中字段间的相关性不被破坏。这意味着在进行查询时,可以精确地找到满足条件的特定嵌套对象。

查询效率:由于嵌套文档直接内嵌在父文档中,查询嵌套文档与根文档的组合成本相对较低,从而保证了查询的高效性,其速度与单独存储文档几乎无异。

数据的隐藏与访问:嵌套文档在内部是隐藏存储的,无法直接访问。若需对嵌套对象进行修改(增加、删除或更改),则必须对整个父文档进行重新索引。值得注意的是,查询时返回的是包含匹配嵌套对象的整个父文档,而非单独的嵌套文档。

相比之下,**普通的对象(object)**类型在处理对象数组时,默认会将对象内部的字段扁平化,这可能导致字段间的关联性丢失。因此,在进行复杂查询时,可能无法精确地定位到对象数组中的特定对象,从而影响查询结果的准确性。


总的来说,嵌套对象通过保留字段间的相关性和提供高效的查询性能,为处理对象数组提供了一种更为精确和灵活的方式。然而,这也带来了数据访问和修改的某些限制,需要权衡利弊后做出选择。

三、嵌套类型的定义

在Elasticsearch中,嵌套类型主要用于处理包含多个内部对象的字段,这些内部对象通常与外部对象相关联。通过在映射(mapping)中定义一个字段为嵌套类型,我们可以对这些关联数据进行有效的查询。

嵌套类型定义:

PUT /my_index
{
  "mappings": {
    "properties": {
      "user": {
        "type": "nested", 
        "properties": {
          "name": {
            "type": "text"
          },
          "age": {
            "type": "integer"
          }
        }
      }
    }
  }
}

user字段被定义为嵌套类型,包含nameage两个子字段。这样的定义允许存储和查询多个与用户相关的内部对象。

四、索引嵌套文档

一旦定义了嵌套索引,就可以开始索引包含嵌套字段的文档了。以下是一个栗子:

PUT /my_index/_doc/1
{
  "user": [
    {
      "name": "Alice",
      "age": 25
    },
    {
      "name": "Bob",
      "age": 30
    }
  ]
}

user字段是一个数组,每个数组元素都是一个对象,包含nameage字段。这种数据结构允许我们存储多个与用户相关的记录,并保持它们之间的关联性。

五、查询嵌套文档

查询嵌套文档时,需要使用特定的nested查询语法。以下是一个查询名字为"Alice"的用户的dsl:

GET /my_index/_search
{
  "query": {
    "nested": {
      "path": "user",
      "query": {
        "match": {
          "user.name": "Alice"
        }
      }
    }
  }
}

这个查询将返回所有包含名字为"Alice"的用户的文档。通过nested查询,可以精确地定位到嵌套字段中的特定数据,并进行高效的检索。

六、排序和聚合

除了基本的查询功能外,Elasticsearch还允许我们对嵌套字段进行排序和聚合操作。然而,由于嵌套字段的特殊性,这些操作可能比常规字段更复杂。需要使用特定的nested排序和聚合语法来实现这些功能。

例如,如果我们想按照用户的年龄进行排序,可以使用以下查询:

GET /my_index/_search
{
  "sort": [
    {
      "user.age": {
        "order": "asc",
        "nested": {
          "path": "user"
        }
      }
    }
  ],
  "query": {
    "match_all": {}
  }
}

这个查询将按照用户的年龄进行升序排序,并返回所有文档。通过使用nested排序语法,我们可以确保正确地处理嵌套字段中的数据。

类似地,也可以对嵌套字段进行聚合操作,以获取有关数据的统计信息。例如,我们可以计算用户的平均年龄:

GET /my_index/_search
{
  "size": 0,
  "aggs": {
    "nested_users": {
      "nested": {
        "path": "user"
      },
      "aggs": {
        "average_age": {
          "avg": {
            "field": "user.age"
          }
        }
      }
    }
  }
}

这个聚合查询将计算所有用户的平均年龄,并返回结果。通过使用nested聚合语法,我们可以对嵌套字段中的数据执行复杂的统计分析。

七、注意事项和性能考虑

尽管嵌套索引在Elasticsearch中非常有用,但也有一些需要注意的事项和性能考虑因素:

性能影响:嵌套字段会增加索引的复杂性,并可能影响性能。由于嵌套字段需要额外的存储空间来维护内部对象之间的关系,因此索引和查询这些字段可能会比常规字段更耗时。

更新开销:当你更新嵌套文档中的某个内部对象时,整个嵌套数组都会被重新索引。这可能会导致性能下降,特别是在处理大量数据时。因此,在设计数据模型时需要谨慎考虑更新的频率和影响。

查询复杂性:对嵌套字段进行查询可能比常规字段更复杂。你需要使用特定的nested查询语法,并确保正确地引用嵌套路径和字段名。此外,过于复杂的查询可能会导致性能下降。

八、替代方案

如果你发现嵌套字段导致性能问题或查询复杂性增加,可以考虑以下替代方案:

数据模型扁平化:尝试将数据模型扁平化,将嵌套字段拆分为单独的字段或文档。这样可以简化查询和索引过程,但可能会增加数据冗余和存储开销。


父子文档关系:Elasticsearch支持父子文档关系,允许你定义文档之间的层次结构。这种关系可以用于处理具有一对多关系的数据,并提供更灵活的查询和聚合功能。然而,父子文档关系也可能带来一些性能上的考虑因素。

  1. 应用逻辑管理:另一种方法是将关联数据存储在单独的索引中,并使用应用程序逻辑来管理和查询这些数据之间的关系。这种方法可以提供更大的灵活性,但需要在应用程序中实现额外的逻辑来处理关联数据。

结语

Elasticsearch中的嵌套索引是一个强大的功能,允许你处理具有一对多关系的复杂数据结构。通过正确使用嵌套索引、查询、排序和聚合功能,你可以高效地检索和分析关联数据。然而,在使用嵌套索引时需要注意性能影响和查询复杂性,并根据具体情况考虑替代方案来优化数据模型和查询性能。

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
1月前
|
自然语言处理 大数据 应用服务中间件
大数据-172 Elasticsearch 索引操作 与 IK 分词器 自定义停用词 Nginx 服务
大数据-172 Elasticsearch 索引操作 与 IK 分词器 自定义停用词 Nginx 服务
60 5
|
10天前
|
存储 SQL 监控
|
7天前
|
存储 JSON 关系型数据库
Elasticsearch 索引
【11月更文挑战第3天】
24 4
|
10天前
|
自然语言处理 监控 数据可视化
|
19天前
|
测试技术 API 开发工具
ElasticSearch7.6.x 模板及滚动索引创建及注意事项
ElasticSearch7.6.x 模板及滚动索引创建及注意事项
33 8
|
1月前
|
人工智能
云端问道12期-构建基于Elasticsearch的企业级AI搜索应用陪跑班获奖名单公布啦!
云端问道12期-构建基于Elasticsearch的企业级AI搜索应用陪跑班获奖名单公布啦!
172 2
|
7天前
|
存储 安全 数据管理
如何在 Rocky Linux 8 上安装和配置 Elasticsearch
本文详细介绍了在 Rocky Linux 8 上安装和配置 Elasticsearch 的步骤,包括添加仓库、安装 Elasticsearch、配置文件修改、设置内存和文件描述符、启动和验证 Elasticsearch,以及常见问题的解决方法。通过这些步骤,你可以快速搭建起这个强大的分布式搜索和分析引擎。
20 5
|
1月前
|
存储 JSON Java
elasticsearch学习一:了解 ES,版本之间的对应。安装elasticsearch,kibana,head插件、elasticsearch-ik分词器。
这篇文章是关于Elasticsearch的学习指南,包括了解Elasticsearch、版本对应、安装运行Elasticsearch和Kibana、安装head插件和elasticsearch-ik分词器的步骤。
109 0
elasticsearch学习一:了解 ES,版本之间的对应。安装elasticsearch,kibana,head插件、elasticsearch-ik分词器。
|
2月前
|
NoSQL 关系型数据库 Redis
mall在linux环境下的部署(基于Docker容器),Docker安装mysql、redis、nginx、rabbitmq、elasticsearch、logstash、kibana、mongo
mall在linux环境下的部署(基于Docker容器),docker安装mysql、redis、nginx、rabbitmq、elasticsearch、logstash、kibana、mongodb、minio详细教程,拉取镜像、运行容器
mall在linux环境下的部署(基于Docker容器),Docker安装mysql、redis、nginx、rabbitmq、elasticsearch、logstash、kibana、mongo
|
3月前
|
数据可视化 Docker 容器
一文教会你如何通过Docker安装elasticsearch和kibana 【详细过程+图解】
这篇文章提供了通过Docker安装Elasticsearch和Kibana的详细过程和图解,包括下载镜像、创建和启动容器、处理可能遇到的启动失败情况(如权限不足和配置文件错误)、测试Elasticsearch和Kibana的连接,以及解决空间不足的问题。文章还特别指出了配置文件中空格的重要性以及环境变量中字母大小写的问题。
一文教会你如何通过Docker安装elasticsearch和kibana 【详细过程+图解】