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

1、线上环境问题

老师、同学们,有人遇到过这个问题么,索引中有一个 integer 数组字段,然后通过脚本获取数组下标为1的值作为运行时字段,发现返回的值是乱的,并不是下标为1的值, 具体如下:

DELETE my_index
PUT my_index
{"mappings": {"properties": {"price": {"type": "integer"}}}
}POST /my_index/_doc
{"price": [5,6,99,3]
}POST /my_index/_doc
{"price": [22,11,19,-1]
}
GET my_index/_search
{"runtime_mappings": {"price_a": {"type": "double","script": {"source": """double v = doc['price'][1];emit(v);"""}}},"fields": [{"field": "price_a"}]
}

是不是因为doc value存储的结果是乱序的?

结果为:

5f1ef5a8169db5b4d7134a984bf8a2ec.png                                                                                         ——问题来自技术交流群

2、问题分析

2.1 Elasticsearch 数组是如何存取的?

在 Elasticsearch 中,数组并不是一种特殊的数据类型。

当你在JSON文档中有一个数组字段并将其索引到Elasticsearch时,Elasticsearch会将数组中的每个元素当作独立的值进行索引,但它不会存储数组的结构或顺序信息。

例如,假设你有以下文档:

{"tags": ["A", "B", "C"]}

Elasticsearch会像你分别为文档添加了三个标签"A"、"B"和"C"一样对待它。

数组字段(和许多其他字段类型)在 Elasticsearch 中主要是通过Doc Values来存储的。

Doc Values 是一种优化的、磁盘上的、列式数据结构,它们使得对字段的排序和聚合变得非常快速和高效。

但是,列式存储并不保留原始数据的顺序,这就是为什么数组在 Elasticsearch中会丢失其原始顺序的原因。

2.2 访问数组数据

当你在脚本或查询中访问数组字段时,例如 doc['tags'],你实际上得到的是一个值列表。

即使原始数组只有一个值,你也会得到一个值列表。因此,通常需要检查其.size( )并通过.value或具体的索引来访问特定的值。

2.3 数组与嵌套文档类型 Nested

尽管数组不保留顺序,但 Elasticsearch 提供了一种 nested 数据类型,可以让你索引数组中的对象,并保持它们之间的关系。

这对于复杂的对象数组非常有用,但同时也带来了一些复杂性,如使用特定的 nested 查询和聚合。

3、如何获取指定下标的数据?

3.1 方案一、微小改动。

#### 删除索引
DELETE my_index#### 创建索引
PUT my_index
{"mappings": {"properties": {"price": {"type": "integer"}}}
}#### 导入数据
POST /my_index/_doc
{"price": [5,6,99,3]
}POST /my_index/_doc
{"price": [22,11,19,-1]
}
#### 创建预处理管道
PUT _ingest/pipeline/split_array_pipeline
{"description": "Splits the price array into individual fields","processors": [{"script": {"source": """if (ctx.containsKey('price') && ctx.price instanceof List && ctx.price.size() > 0) {for (int i = 0; i < ctx.price.size(); i++) {ctx['price_' + i] = ctx.price[i];}}"""}}]
}

split_array_pipeline 预处理管道的含义:

  • description:

描述该管道的目的。在这个案例中,我们说明这个管道的目的是将price数组分解为单独的字段。

  • processors:

是一个处理器数组,每个处理器都完成一个特定的任务。在这里,我们只有一个script处理器。

在 script 处理器中,我们编写了一个小脚本,检查是否存在一个名为 price 的字段,该字段是否是一个数组,以及数组是否至少有一个元素。如果所有这些条件都满足,脚本会遍历数组并为数组中的每个元素创建一个新字段。新字段的名称将是 price_0、price_1等,其中的数字是数组的索引。

这种预处理管道非常有用,特别是当原始数据格式不适合直接索引到 Elasticsearch 时。通过使用预处理管道,我们可以在索引数据之前对其进行所需的转换或清理。

POST my_index/_update_by_query?pipeline=split_array_pipeline
{"query": {"match_all": {}}
}GET my_index/_search
{"runtime_mappings": {"price_a": {"type": "double","script": {"source": """if (doc['price_0'].size() > 0) {double v = doc['price_0'].value;emit(v);}"""}}},"fields": [{"field": "price_a"}]
}

运行时字段(Runtime Fields)。运行时字段是 7.12 版本后引入的功能,允许你定义临时字段,这些字段的值是在查询时通过脚本计算的,而不是在索引时预先存储的。

如上代码中:

  • 我们定义了一个名为 price_a 的新运行时字段。字段类型为 double。

  • 我们提供了一个Painless 脚本,用于计算此字段的值。

脚本解读:

  • if (doc['price_0'].size() > 0):

这检查price_0字段是否存在并且有值。在Elasticsearch的脚本中,doc['field_name']表示获取该字段的值,.size()方法用于检查该字段是否有值(在某些文档中,该字段可能不存在或为空)。

  • double v = doc['price_0'].value;:

如果上面的条件为真,这行代码会从price_0字段中取出值,并将其转换为double类型。

  • emit(v);:

这是Painless脚本的关键指令。它将指定的值输出为运行时字段price_a的值。

执行结果如下,结果已经达到预期。

fda64f8f1db9ef87286e902581cda187.png

3.2 方案二:Nested 实现

Nested 嵌套数据类型,咱们之前文章多次讲过,不明白的同学可以翻看一下历史文章。

### 定义索引
PUT /my_nested_index
{"mappings": {"properties": {"prices": {"type": "nested","properties": {"value": {"type": "integer"}}}}}
}### 导入数据
POST /my_nested_index/_doc
{"prices": [{"value": 5},{"value": 6},{"value": 99},{"value": 3}]
}POST /my_nested_index/_doc
{"prices": [{"value": 22},{"value": 11},{"value": 19},{"value": -1}]
}
#### 执行检索
GET my_nested_index/_search
{"query": {"bool": {"must": [{"nested": {"path": "prices","query": {"exists": {"field": "prices.value"}},"inner_hits": {"size": 1}}}]}}
}

如果你想只返回 inner_hits 下的第一个数据结果,你可以使用size参数。通过设置size为 1,你可以限制inner_hits返回的结果数量。

返回结果:

24306f80c2394ec29945d334d23a6c37.png

4、小结

当我们使用 Elasticsearch 处理数组数据时,很容易误解其实际行为。本文详细探讨了Elasticsearch如何处理和存储数组,并提供了几种获取数组中特定位置元素的方法。

首先,我们必须理解 Elasticsearch 不是以传统的方式存储数组,而是将每个元素视为独立的值。因此,我们不能简单地通过下标直接访问数组中的某个特定元素。

有几种方法可以解决这个问题:

使用预处理管道:通过创建一个预处理管道来分解数组并为每个元素生成一个新字段。这种方法非常直观,允许我们轻松访问任何特定位置的元素。

使用 Nested 数据类型:对于需要保留其元素间关系的复杂数组,Nested数据类型是一个非常有效的选择。这使我们能够对数组中的每个对象执行更复杂的查询,并且能够保留它们之间的关系。

这两种方法都有其优点和缺点。选择哪一种方法取决于你的具体需求和数据结构。预处理管道方案适用于那些希望保持数据的简单性并能够直接访问数组元素的场景。而 Nested 数据类型则适用于那些需要在数组对象之间维护关系的更复杂的场景。

在任何情况下,理解你的数据结构和 Elasticsearch 如何处理它是至关重要的。希望通过这篇文章,你对Elasticsearch的数组处理有了更深入的理解,并能够更有效地解决与数组相关的问题。

最后,不管你选择哪种方法,都要确保经常测试和验证数据的完整性和准确性。这样,你就可以确保在生产环境中得到预期的结果,避免因为数据结构的误解而产生的潜在问题。

推荐阅读

  1. 全网首发!从 0 到 1 Elasticsearch 8.X 通关视频

  2. 重磅 | 死磕 Elasticsearch 8.X 方法论认知清单

  3. 如何系统的学习 Elasticsearch ?

  4. 2023,做点事

  5. 干货 | Elasticsearch Nested类型深入详解

  6. Elasticsearch Nested 选型,先看这一篇!

  7. 干货 | Elasticsearch Nested 数组大小求解,一网打尽!

  8. Elasticsearch 有没有数组类型?有哪些坑?

  9. 干货 | 拆解一个 Elasticsearch Nested 类型复杂查询问题

0ccc5009684511c3c757f579c97343d5.jpeg

更短时间更快习得更多干货!

和全球 近2000+ Elastic 爱好者一起精进!

be1df05a9d799ce1f17ad7161cce62ed.gif

一个人可以走得很快,但一群人走得更远!

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

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

相关文章

sql:SQL优化知识点记录(六)

&#xff08;1&#xff09;索引优化1 查看一下有没有建立索引&#xff1a; 用到索引中的一个&#xff1a;type中的ref决定访问性能 用到索引中的两个&#xff1a;通过key_len的长度可以看出来&#xff0c;比第一个大一点。或者通过ref&#xff1a;中用到了两个常量const 用到了…

【Android Framework系列】第14章 Fragment核心原理(AndroidX版本)

1 简介 Fragment是一个历史悠久的组件&#xff0c;从API 11引入至今&#xff0c;已经成为Android开发中最常用的组件之一。 Fragment表示应用界面中可重复使用的一部分。Fragment定义和管理自己的布局&#xff0c;具有自己的生命周期&#xff0c;并且可以处理自己的输入事件。…

如何合并为pdf文件?合并为pdf文件的方法

在数字化时代&#xff0c;人们越来越依赖电子文档进行信息交流和存储。合并为PDF成为一种常见需求&#xff0c;它能将多个文档合而为一&#xff0c;方便共享和管理。无论是合并多个单页文档&#xff0c;还是将多页文档合并&#xff0c;操作都变得简单高效。那么。如何合并为pdf…

移除链表元素_每日一题

“路虽远&#xff0c;行则将至” ❤️主页&#xff1a;小赛毛 ☕今日份刷题&#xff1a;移除链表元素 题目描述&#xff1a; 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例1&…

真香:Alibaba开源GitHub星标100K微服务架构全彩进阶手册

前言&#xff1a; 微服务架构作为一种高效灵活的应用架构&#xff0c;正在成为企业级应用开发的主流选择。在众多的微服务架构指南中&#xff0c;阿里巴巴开源的GitHub微服务架构全彩进阶手册备受瞩目&#xff0c;其100star更是证明了其在开发者社区中的重要地位。 这本手册汇…

【Yolov5+Deepsort】训练自己的数据集(3)| 目标检测追踪 | 轨迹绘制 | 报错分析解决

&#x1f4e2;前言&#xff1a;本篇是关于如何使用YoloV5Deepsort训练自己的数据集&#xff0c;从而实现目标检测与目标追踪&#xff0c;并绘制出物体的运动轨迹。本章讲解的为第三部分内容&#xff1a;数据集的制作、Deepsort模型的训练以及动物运动轨迹的绘制。本文中用到的数…

PHP旅游管理系统Dreamweaver开发mysql数据库web结构php编程计算机网页

一、源码特点 PHP 旅游管理系统是一套完善的web设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 PHP 旅游管理系统 源码下载地址&#xff1a; https://download.csdn.net/download/qq_41…

LeetCode 46题:全排列

题目 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]示例 2&#xff1a; 输入&#xff1a;…

gerrit 如何提交进行review

前言 本文主要介绍如何使用gerrit进行review。 下述所有流程都是参考&#xff1a; https://gerrit-review.googlesource.com/Documentation/intro-gerrit-walkthrough.html 先给一个commit后但是还没有push上去的一个办法&#xff1a; git reset --hard HEAD^可以多次reset.…

小白学go基础03-了解Go项目的项目结构

我们先来看看第一个Go项目——Go语言自身——的项目结构是什么样的。Go项目的项目结构自1.0版本发布以来一直十分稳定&#xff0c;直到现在Go项目的顶层结构基本没有大的改变。 截至Go项目commit 1e3ffb0c&#xff08;2019.5.14&#xff09;&#xff0c;Go1.0 项目结构如下&am…

VirtualBox7+Ubuntu22集群规划

1. 目的: 新入手了一台小主机&#xff08;8核 / Intel(R) Xeon(R) W-10885M CPU 2.40GHz 2.40 GHz, 16vCpu / 64G RAM / 系统类型 64 位操作系统, 基于 x64 的处理器&#xff09;&#xff0c;原装了一套Win11专业版&#xff0c;打算用VirtualBox 虚拟一个集群。 2. …

Vue2项目练手——通用后台管理项目第四节

Vue2项目练手——通用后台管理项目 数据的请求mock数据模拟实战文件目录src/api/mock.jssrc/api/mockServeData/home.jsmain.js 首页组件布局可视化图表可视化图表布局Home.vue echarts表Home.vue 数据的请求 mock数据模拟实战 mock官方文档 前端用来模拟后端接口的工具&…

UNIX网络编程卷一 学习笔记 第三十章 客户/服务器程序设计范式

开发一个Unix服务器程序时&#xff0c;我们本书做过的进程控制&#xff1a; 1.迭代服务器&#xff08;iterative server&#xff09;&#xff0c;它的适用情形极为有限&#xff0c;因为这样的服务器在完成对当前客户的服务前无法处理已等待服务的新客户。 2.并发服务器&#x…

SquirrelMail实现Web方式收发邮件_xionglling的博客-CSDN博客

SquirrelMail实现Web方式收发邮件_xionglling的博客-CSDN博客小松鼠实现Web邮件服务SquirrelMail 是一个用PHP开发的Web邮件系统。它内置纯PHP支持的IMAP和SMTP协议&#xff0c;所有页面都遵循 HTML 4.0标准(没有使用任何 JavaScript 代码)&#xff0c;以便最大限度兼容各种多浏…

Qt之事件过滤—筛选处理对象

文章目录 事件过滤完整代码 事件过滤 事件过滤是当事件发生时&#xff0c;可以对不同对象&#xff0c;实现不同操作&#xff0c;以达到筛选的效果。 步骤&#xff1a; 1、首先安装一个事件过滤器&#xff0c;为对象安装事件过滤&#xff0c;指定“谁”来监控这些事件对象 //给…

vue3+ts+uniapp实现小程序端input获取焦点计算上推页面距离

vue3tsuniapp实现小程序端input获取焦点计算上推页面距离 input获取焦点计算上推页面距离 1.先说我这边的需求2.发现问题3.解决思路4.代码展示 自我记录 1.先说我这边的需求 需求 1.给键盘同级添加一个按钮例如’下一步’ or ‘确认’ 这种按钮 2.初步想法就是获取input焦点时…

【LeetCode-中等题】146. LRU 缓存

文章目录 题目方法一&#xff1a;直接继承LinkedHashMap调用api方法二&#xff1a;自定义LinkedHashMap HashMap ListNode LinkedHashMap 题目 LRU缓存是什么&#xff1a;LRU缓存机制&#xff0c;你想知道的这里都有 实现 LRU 缓存算法 方法一&#xff1a;直接继承Linked…

单臂路由实验:通过Trunk和子接口实现VLAN互通

文章目录 一、实验背景与目的二、实验拓扑三、实验需求四、实验解法1. PC 配置 IP 地址2. PC3 属于 Vlan10&#xff0c;PC4 属于 Vlan20&#xff0c;配置单臂路由实现 Vlan10 和 Vlan20 三层互通3. 测试在 PC3 上 Ping PC4 &#xff0c;可以 Ping 通 PC4 摘要&#xff1a; 本文…

数学建模:回归分析

&#x1f506; 文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 数学建模&#xff1a;回归分析 文章目录 数学建模&#xff1a;回归分析回归分析多元线性回归案例 多项式回归一元多项式回归多元二项式回归 非线性回归逐步回归 回归分析 多元线性回归 案例 首先进行回归分…

ASP.NET Core 中的 MVC架构

MVC 架构 MVC架构把 App 按照逻辑分成三层&#xff1a; Controllers&#xff0c;接收 http request&#xff0c;配合 model&#xff0c;通过http response 返回 view&#xff0c;尽量不做别的事Models, 负责业务逻辑&#xff0c;App 的状态&#xff0c;以及数据处理Views&…