Elasticsearch 企业级实战 01:Painless 脚本如何调试?

在企业级应用中,Elasticsearch 常常被用来处理复杂的数据查询和操作。

Painless 是 Elasticsearch 的内置脚本语言,虽然强大,但调试起来并不容易。

本文将详细介绍如何在实战中有效调试 Painless 脚本,以提高开发和运维效率。

本文所有实现均在 Elasticsearch 8.11 dev-tool 环境充分验证,建议放大图片查看结果。

1、 抛出问题

在使用 Elasticsearch 的过程中,咱们开发者经常需要编写和调试 Painless 脚本,例如在查询、更新文档或定义复杂的预处理条件时。

由于 Painless 没有 REPL 环境(实时代码测试工具),调试嵌入在 Elasticsearch 中的脚本变得更加困难。

开发者无法直接在交互式环境中输入和测试 Painless 脚本,必须依赖诸如 Kibana 的 Painless Lab 或其他工具来间接调试和验证脚本。

这增加了调试的复杂性和开发周期。

2、脚本调试方式分类

通过大量的调研工作,其实核心就分两类。

2.1 调试方案 1:Elasticsearch  Debug.Explain 调试

Painless 提供的调试工具,可以在脚本中插入 Debug.explain 方法,通过抛出异常的方式输出变量信息。

参见官网:https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-debugging.html

2.2 调试方案 2:Kibana Painless Lab 工具调试

Elasticsearch 7.13 引入的实验性功能 Painless Lab,是一个交互式代码编辑器,可以实时测试和调试 Painless 脚本。

参见如下图,相信你和我一样,看过这幅图,但没有真正用过。下一篇我们多花笔墨解读这一部分的用法。

3b5dd116a8bdada53a54fec5bb9f7edb.png

3、Debug.Explain 调试实战案例

依然以官方示例作为范例解读,参见:

https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-debugging.html#_debug_explain

3.1 官方样例解读

假设我们有一个包含球员数据的索引,文档如下:

DELETE hockey
PUT /hockey/_doc/1?refresh
{
"first": "johnny",
"last": "gaudreau",
"goals": [9, 27, 1],
"assists": [17, 46, 0],
"gp": [26, 82, 1]
}

我们可以使用以下脚本来查看 goals 字段的类型:

POST /hockey/_explain/1
{"query": {"script": {"script": "Debug.explain(doc.goals)"}}
}

执行结果如下:

0c28f8ba65edd1e97e939494cef93fb4.png

当看到上面一堆输出的时候,相信你和我的表情一致:“这是啥?”、“错了吧?”、“就这”......

42224d4a7b0bec6c7a2b6cb1187f5910.jpeg

结合上文定义:“通过抛出异常的方式输出变量信息”,本质上是抛出异常了。

3.2 延伸详细解读

我们一点点剖析一下,如下内容官网没有提供。

我们使用脚本的本质,我延展一下:

3.2.1 脚本过滤检索
POST /hockey/_search
{"query": {"bool": {"filter": {"script": {"script": """def goals = doc['goals'];// 计算总和def sum = 0;for (def goal : goals) {sum += goal;}return sum > 30;"""}}}}
}

过滤查询出总和大于 30 的数据。结果符合预期,如下图所示:

c1f2bcde3776b9302399e84f6d6c3fa7.png

那,如何调试呢?

3.2.2 explain API 调试文档是否满足条件

极简单的方式,可以借助:explain 解读。也就是说:使用 _explain API 来探究并调试一个脚本查询。

细节参见:

https://www.elastic.co/guide/en/elasticsearch/reference/current/search-explain.html

执行命令如下:

POST /hockey/_explain/1
{"query": {"bool": {"filter": {"script": {"script": """def goals = doc['goals'];//Debug.explain(goals);// 计算总和def sum = 0;for (def goal : goals) {sum += goal;}return sum > 30;"""}}}}
}

之前咱们讲过 explain 可以详尽展开评分计算细节。

2f7a31e9414bc79549c3d61c9c45270e.png

而此处还展示了:matched与否标记,如果条件满足则返回 true;如果不满足则返回 false。

显然,咱们的文档1符合查询条件。

3.2.3 Debug.explain 使用细节调试

还不够,doc['goals'] 到底来自哪里呢?

如下 DSL 仅在 3.2.2 基础上加了  Debug.explain 。

POST /hockey/_explain/1
{"query": {"bool": {"filter": {"script": {"script": """def goals = doc['goals'];Debug.explain(doc['goals']);// 计算总和def sum = 0;for (def goal : goals) {sum += goal;}return sum > 30;"""}}}}
}

执行结果截图如下:

5a1a6199689ae366c330c011d30e15b8.png

该错误指出在调用 Debug.explain(doc['goals']); 时发生了运行时错误。

Debug.explain 是一个调试方法,用于在脚本中输出变量的信息。然而,这种方法在某些上下文中可能不被允许,或者 doc['goals'] 字段的类型 ScriptDocValues.Longs 导致了这个问题。

其实,我们还能得到如下有价值信息:

  • (1):"to_string": "[1, 9, 27]" 显示了 doc['goals'] 字段的值,即一个包含 [1, 9, 27] 的数组。

  • (2):"painless_class": "org.elasticsearch.index.fielddata.ScriptDocValues.Longs" 指出导致错误的类是 ScriptDocValues.Longs。这是一个表示长整型字段值的类。

关于这个类的官方文档,可以参见:

根据:org.elasticsearch.index.fielddata.ScriptDocValues.Longs

找到 fielddata 子模块,进而找到文档,参见下图。

cb4e87d4feaf91a6fa16e1c491a2ffdb.png

13a2803a55f5f326b6f20fc3fc34e24a.png

https://www.elastic.co/guide/en/elasticsearch/painless/8.11/painless-api-reference-shared-org-elasticsearch-index-fielddata.html#painless-api-reference-shared-ScriptDocValues-Longs

其实,这些 API 就是我们使用脚本的依据和参考。

这里,往往也是被问最多的地方:Elasticsearch 脚本细节运算的 API 在哪里查?支持哪些方法?

有了它,我们进一步可以执行脚本了,举例:sort 使用如下:

POST /hockey/_search
{"script_fields": {"sorted_goals": {"script": {"lang": "painless","source": """// 获取 goals 数组,并复制到一个新的列表中def goals = new ArrayList(doc['goals']);// 定义排序比较器,从大到小排序goals.sort((a, b) -> b.compareTo(a));// 返回排序后的数组return goals;"""}}}
}

b5eb1f15469cc8801d23bdfe0c9be255.png

goals.sort((a, b) -> b.compareTo(a)); ——语法的核心是使用 Java 8 的 lambda 表达式和 Comparator 接口来定义排序规则。

b.compareTo(a) 是对 b 和 a 进行比较的方法调用。compareTo 方法返回一个整数,用于指示元素的顺序:

  • 如果返回负数,则表示 b 小于 a。

  • 如果返回零,则表示 b 等于 a。

  • 如果返回正数,则表示 b 大于 a。仔细看来,这是意外的收获!

4、小结

篇幅原因,本文只给出了Painless 脚本的第一种调试方式:Debug.explain 的详尽解读。

相信对你的脚本调试也会有帮助,如果你有脚本调试疑问,欢迎留言交流哈。

关于 Kibana Painless Lab 工具调试 ,且听下回分解。

探究 | Elasticsearch Painless 脚本 ctx、doc、_source 的区别是什么?

Elasticsearch 脚本安全使用指南

干货 | Elasticsearch7.X Scripting脚本使用详解

新时代写作与互动:《一本书讲透 Elasticsearch》读者群的创新之路

b86b68bf07fb765364a8fade799a7151.png

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

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

http://elastic6.cn——ElasticStack进阶助手

ae314ab5274e0f91d1936a47766f1312.gif

抢先一步学习进阶干货!

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

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

相关文章

百日筑基第二十三天-23种设计模式-创建型总汇

百日筑基第二十三天-23种设计模式-创建型总汇 前言 设计模式可以说是对于七大设计原则的实现。 总体来说设计模式分为三大类: 创建型模式,共五种:单例模式、简单工厂模式、抽象工厂模式、建造者模式、原型模式。结构型模式,共…

java基础之数组,int[]和ArrayList

开始学java的时候,对于 int[] 和ArrayList总是懵懵懂懂的,不知道啥时候用哪个。现在终于了解了,总结一下跟大家分享一下 int[]数组 创建// 方式一:创建一个固定的数组 int arr1 {1,2,3,4,5}; // 方式二:创建一个长度为10的数组 double[] ar…

28_EfficientNetV2网络详解

V1:https://blog.csdn.net/qq_51605551/article/details/140487051?spm1001.2014.3001.5502 1.1 简介 EfficientNetV2是Google研究人员Mingxing Tan和Quoc V. Le等人在2021年提出的一种深度学习模型,它是EfficientNet系列的最新迭代,旨在提…

HLS加密技术:保障流媒体内容安全的利器

随着网络视频内容的爆炸性增长,如何有效保护视频内容的版权和安全成为了一个亟待解决的问题。HLS(HTTP Live Streaming)加密技术作为一种先进的流媒体加密手段,凭借其高效性和安全性,在直播、点播等场景中得到了广泛应…

十大排序 之 选择排序

!!!排序仅针对于数组哦本次排序是按照升序来的哦 介绍 快速排序英文名为SelectSort从数组中找到最小的放到前边 基本思路 1、默认待排序数组中第一个作为最小值2、找待排序数组(注意不是整个数组哦)中真正的最小值3…

【机器学习实战】Datawhale夏令营2:深度学习回顾

#DataWhale夏令营 #ai夏令营 文章目录 1. 深度学习的定义1.1 深度学习&图神经网络1.2 机器学习和深度学习的关系 2. 深度学习的训练流程2.1 数学基础2.1.1 梯度下降法基本原理数学表达步骤学习率 α梯度下降的变体 2.1.2 神经网络与矩阵网络结构表示前向传播激活函数…

《昇思25天学习打卡营第22天|生成式-Diffusion扩散模型》

Diffusion扩散模型 本文基于Hugging Face:The Annotated Diffusion Model一文翻译迁移而来,同时参考了由浅入深了解Diffusion Model一文。 本教程在Jupyter Notebook上成功运行。如您下载本文档为Python文件,执行Python文件时,请…

数据结构day2

一、思维导图 内存分配 二、课后习题 分文件编译 //sys.h #ifndef TEST_H #define TEST_H #define MAX_SIZE 100//定义学生类型 typedef struct Stu {char name[20]; //姓名int age; //年龄double score; //分数 }stu;//定义班级类型 typedef struct Class {struct …

Xilinx FPGA DDR4 接口配置基础(PG150)

1. 简介 本文为硬件平台创建PL IP模块,创建PL内核,子系统功能仿真,并评估Vivado的时序、资源和功耗收敛。 本文设计过程的主题包括: ClockingResetsProtocol DescriptionCustomizing and Generating the CoreExample Design D…

Linux学习(2):shell脚本和正则

概述 一般使用/bin/bash,也就是bash解析器。最广泛,大家公认。 一般shell脚本的后缀都是 .sh 简单写一个: 执行方法:sh sh文件 or bash sh文件,(不用x权限)直接运行./sh文件可能会有权限问题&#xff…

定制开发AI智能名片商城微信小程序在私域流量池构建中的应用与策略

摘要 在数字经济蓬勃发展的今天,私域流量已成为企业竞争的新战场。定制开发AI智能名片商城微信小程序,作为私域流量池构建的创新工具,正以其独特的优势助力企业实现用户资源的深度挖掘与高效转化。本文深入探讨了定制开发AI智能名片商城微信…

《昇思25天学习打卡营第20天|GAN图像生成》

生成对抗网络(GAN)是一种深度学习模型,用于生成逼真的图像。在手写数字识别的任务中,GAN 可以用来生成与真实手写数字相似的图像,以增强模型的训练数据集。GAN 主要由两个部分组成:生成器(Gener…

UDP客户端、服务端及简易聊天室实现 —— Java

UDP 协议(用户数据包协议) UDP 是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接,简单来说,当客户端向接收端发送数据时,客户端不会确认接收端是否存在,就会发出…

FATE Flow 源码解析 - 日志输出机制

背景介绍 在 之前的文章 中介绍了 FATE 的作业处理流程,在实际的使用过程中,为了查找执行中的异常,需要借助运行生成的日志,但是 FATE-Flow 包含的流程比较复杂,对应的日志也很多,而且分散在不同的文件中&…

Go语言中的并发

简单介绍go中的并发编程. 涉及内容主要为goroutine, goroutine间的通信(主要是channel), 并发控制(等待、退出). 想查看更多与Go相关的内容, 可以查看我的Go编程栏目 Goroutine 语法 在一个函数调用前加上go即可, go func(). 语法很简单, 可以说是并发写起来最简单的程序语言…

【简单介绍Gitea】

🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出…

广联达Linkworks ArchiveWebService XML实体注入漏洞复现

0x01 产品简介 广联达 LinkWorks(也称为 GlinkLink 或 GTP-LinkWorks)是广联达公司(Glodon)开发的一种BIM(建筑信息模型)协同平台。广联达是中国领先的数字建造技术提供商之一,专注于为建筑、工程和建筑设计行业提供数字化解决方案。 0x02 漏洞概述 广联达 LinkWorks…

【C#】已知有三个坐标点:P0、P1、P2,当满足P3和P4连成的一条直线 与 P0和P1连成一条直线平行且长度一致,该如何计算P3、P4?

问题描述 已知有三个坐标点:P0、P1、P2,当满足P3和P4连成的一条直线 与 P0和P1连成一条直线平行且长度一致,该如何计算P3、P4? 解决办法 思路一:斜率及点斜式方程 # 示例坐标 x0, y0 1, 1 # P0坐标 x1, y1 4, 4 # …

leetcode力扣_二分查找

69.x的平方根 给你一个非负整数 x ,计算并返回 x 的 算术平方根 。由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。 示例 1&…

数据结构——线性表(循环链表)

一、循环链表定义 将单链表中终端结点的指针端由空指针改为指向头结点,就使整个单链表形成一 个环,这种头尾相接的单链表称为单循环链表,简称循环链表(circular linked list)。 循环链表解决了一个很麻烦的问题。如何从当中一 个结点出发&am…