前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一网打尽:Elasticsearch 数组全量实战操作指南

一网打尽:Elasticsearch 数组全量实战操作指南

作者头像
铭毅天下
发布2024-07-15 12:37:27
880
发布2024-07-15 12:37:27
举报
文章被收录于专栏:铭毅天下

在 Elasticsearch 中处理复杂数据类型如数组时,提供了极高的灵活性,但同时也带来了一定的复杂性,尤其在使用脚本进行高级查询和数据操作时。

举例来自微信群的企业级实战问题如下:

本博客旨在通过一系列实战案例,展示如何有效地在 Elasticsearch 中使用脚本来处理数组类型的字段。

1. 背景和挑战

在现代数据环境中,数据往往以复杂和非结构化的形式存在,数组字段的处理尤为常见。

Elasticsearch 通过其强大的 Painless 脚本语言支持,提供了一种灵活的方式来操作这些数据。然而,脚本的使用可能会让用户在错误调试和性能优化上遇到挑战。

2. Elasticsearch 的 Painless 脚本

Painless 是 Elasticsearch 专为快速、安全、可管理性强而设计的脚本语言。用于执行复杂的数据处理任务,如计算、数据转换、条件逻辑等。

更多关于 Painless 的官方文档可以参见:

https://www.elastic.co/guide/en/elasticsearch/painless/current/index.html

3. 逐步解析数组操作脚本

3.1 索引创建与数据插入

在这个例子中,我们将创建一个名为 vehicles 的索引,该索引用于存储关于车辆的信息,包括发行日期、在线日期范围、所有者、公司 ID、货物类型、车辆长度(数组形式)和车辆类型。

代码语言:javascript
复制
PUT /vehicles
{
  "mappings": {
    "properties": {
      "issue_date": {"type": "date"},
      "online_date": {
        "properties": {
          "gte": {"type": "date"},
          "lte": {"type": "date"}
        }
      },
      "owner": {"type": "integer"},
      "company_id": {"type": "integer"},
      "goods_type": {"type": "integer"},
      "car_length": {"type": "integer"},  // 注意,这里定义为单个整数,我们需要修改以支持数组
      "car_type": {"type": "keyword"}
    }
  }
}

注意:在原定义中,car_length 被定义为整数,但因为它是一个数组,我们需要确保在真实环境中将其定义为 "type": "integer" 且在设置时需要标识为数组可以接受多个整数。

数据插入时,使用 _bulk API 可以提高数据插入的效率,特别适合处理大批量数据。示例如下:

代码语言:javascript
复制
POST /vehicles/_bulk
{ "index": {} }
{ "issue_date": "2024-07-07T21:44:56Z", "owner": 6347, "company_id": 2513, "goods_type": 21, "car_length": [16, 18], "car_type": ["轿车", "货车", "大挂车"] }

在这个数据中,car_length 是一个数组,包含两个整数值 [16, 18]。

3.2 数组操作示例

  • 基础操作:获取数组长度,检查是否为空。
  • 聚合操作:求和、计算最大/最小值、计算平均值,这些都是分析数据时常用的统计操作。
  • 条件过滤:根据特定条件筛选数组元素,常用于数据清洗或选取符合条件的数据集。
  • 复杂逻辑:例如加权求和,根据业务规则动态调整权重,这类操作在金融分析、资源分配等场景中尤为重要。

我们一个个实操如下:

3.2.1 查询数组的第一个元素

在 Elasticsearch 中,可以使用 Painless 脚本语言来处理更复杂的查询。例如,若要访问 car_length 数组的第一个元素,我们可以在查询中添加一个脚本字段:

代码语言:javascript
复制
POST /vehicles/_search
{
  "script_fields": {
    "first_car_length": {
      "script": {
        "lang": "painless",
        "source": "if (doc['car_length'].size() > 0) { return doc['car_length'][0]; } else { return 'none'; }"
      }
    }
  }
}

这个脚本检查 car_length 是否非空,如果非空,则返回第一个元素;否则返回 'none'。

在 Elasticsearch 中处理数组类型字段的脚本操作可以变得相当复杂,尤其是当涉及到数据的实际业务逻辑时。

以下是一些进阶的示例,演示如何使用 Elasticsearch 的 Painless 脚本语言来执行数组字段的常规操作,从基本到高级。

3.2.2 基础操作:获取数组长度

获取数组长度是数组操作中最基础的功能之一,可以用来判断数组是否为空,或者用在更复杂的脚本逻辑中。

代码语言:javascript
复制
POST /vehicles/_search
{
  "script_fields": {
    "car_length_count": {
      "script": {
        "lang": "painless",
        "source": "doc['car_length'].size()"
      }
    }
  }
}

3.2.3 求和操作:计算数组元素总和

计算数组中所有元素的总和是处理数组类型数据时的常见需求,特别是在统计和分析数据时。

代码语言:javascript
复制
POST /vehicles/_search
{
  "script_fields": {
    "car_length_sum": {
      "script": {
        "lang": "painless",
        "source": "int sum = 0; for (int length : doc['car_length']) { sum += length; } return sum;"
      }
    }
  }
}

3.2.4 最大/最小值:寻找数组中的极值

在数组中找到最大或最小的元素,这对于数据分析和决策制定是非常有用的。

代码语言:javascript
复制
POST /vehicles/_search
{
  "script_fields": {
    "max_car_length": {
      "script": {
        "lang": "painless",
        "source": "int max = Integer.MIN_VALUE; for (int val : doc['car_length']) { if (val > max) { max = val; } } return max;"
      }
    },
    "min_car_length": {
      "script": {
        "lang": "painless",
        "source": "int min = Integer.MAX_VALUE; for (int val : doc['car_length']) { if (val < min) { min = val; } } return min;"
      }
    }
  }
}

3.2.5 过滤操作:基于条件筛选数组元素

根据特定条件筛选数组中的元素,这在处理满足特定标准的数据项时特别有用。

代码语言:javascript
复制
POST /vehicles/_search
{
  "script_fields": {
    "filtered_lengths": {
      "script": {
        "lang": "painless",
        "source": "doc['car_length'].stream().filter(length -> length > 15).collect(Collectors.toList())"
      }
    }
  }
}

还有一种简单的写法:

代码语言:javascript
复制
POST /vehicles/_search
{
  "script_fields": {
    "filtered_lengths": {
      "script": {
        "lang": "painless",
        "source": """
          List filtered = new ArrayList();
          for (int length : doc['car_length']) {
            if (length > 17) {
              filtered.add(length);
            }
          }
          return filtered;
        """
      }
    }
  }
}

创建一个新的 ArrayList,名为 filtered,用于存储过滤后的结果。通过 for 循环遍历 car_length 数组中的每个元素。在循环体内部,对每个元素使用 if 条件语句来检查是否大于 15。如果条件为真,就将该元素添加到 filtered 列表中。脚本最终返回 filtered 列表,该列表包含所有大于 15 的 car_length 值。

这个方法对于执行数组的过滤操作是非常有效的,并且在执行上比使用 Stream API 更为简洁和高效,特别是在 Elasticsearch 的 Painless 环境中。

3.2.6 高级统计:计算平均车长

计算数组的平均值是统计数据的一种常见需求,对于理解数据的整体趋势非常重要。

代码语言:javascript
复制
POST /vehicles/_search
{
  "script_fields": {
    "average_car_length": {
      "script": {
        "lang": "painless",
        "source": "double sum = 0; for (int length : doc['car_length']) { sum += length; } return sum / doc['car_length'].size();"
      }
    }
  }
}

3.2.7 复杂业务逻辑:计算条件权重总和

在某些业务场景下,我们可能需要根据数组中的每个元素计算加权总和,其中权重可能由另一个字段或复杂的业务规则确定。

代码语言:javascript
复制
POST /vehicles/_search
{
  "script_fields": {
    "weighted_sum": {
      "script": {
        "lang": "painless",
        "source": "double sum = 0; for (int i = 0; i < doc['car_length'].size(); i++) { sum += doc['car_length'][i] * (i + 1); } return sum;"
      }
    }
  }
}

在这个示例中,我们使用每个元素的索引位置作为权重,这只是一个简单的例子,实际应用中权重可能更复杂。

这些示例覆盖了从基本到复杂的多种操作,每种操作都可以根据具体的业务需求进行调整和扩展。在使用 Elasticsearch 进行数据处理时,合理运用 Painless 脚本可以极大地增强查询的灵活性和功能。

4、结论

在使用脚本进行数组操作时,应考虑性能和资源消耗。适当的优化策略,如使用缓存、限制操作大小、选择合适的索引和数据模型,写入前的 ingest 预处理都是确保良好性能的关键。

合理利用 Elasticsearch 的 Painless 脚本功能可以显著提高数据处理的灵活性和效率,但需要根据具体业务需求进行调整。

希望本文能帮助您更有效地利用 Elasticsearch 处理和分析数据。

5、推荐阅读

[1] 官方 Elasticsearch 文档:深入理解 Elasticsearch 的架构和原理

https://elastic.co/guide/en/elasticsearch/reference/current/index.html

[2] Elasticsearch: The Definitive Guide:提供 Elasticsearch 使用方法和最佳实践的详尽介绍。(版本虽老,但经得起时间的检验)

https://www.elastic.co/guide/en/elasticsearch/guide/master/index.html

[3] Elasticsearch 数组脚本细节

https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-operators-array.html

[4] Elasticsearch 有没有数组类型?有哪些坑?

[5] Elasticsearch 8.X 可以按照数组下标取数据吗?

[6] 干货 | Elasticsearch Nested 数组大小求解,一网打尽!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-07-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 铭毅天下Elasticsearch 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 背景和挑战
  • 2. Elasticsearch 的 Painless 脚本
  • 3. 逐步解析数组操作脚本
    • 3.1 索引创建与数据插入
      • 3.2 数组操作示例
        • 3.2.1 查询数组的第一个元素
        • 3.2.2 基础操作:获取数组长度
        • 3.2.6 高级统计:计算平均车长
    • 4、结论
    • 5、推荐阅读
    相关产品与服务
    Elasticsearch Service
    腾讯云 Elasticsearch Service(ES)是云端全托管海量数据检索分析服务,拥有高性能自研内核,集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群,也支持免运维、自动弹性、按需使用的 Serverless 模式。使用 ES 您可以高效构建信息检索、日志分析、运维监控等服务,它独特的向量检索还可助您构建基于语义、图像的AI深度应用。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档