当前位置: 首页 > news >正文

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

抢先一步学习进阶干货!

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • OPPO 2024届校招正式批笔试题-后端(C卷)
  • LLM基础模型系列:Prompt-Tuning
  • 前端实现将多个页面导出为pdf(分页)
  • SSL vpn easy connect 选路连接失败,可能当前连接网络异常,请稍后重试
  • 防火墙--双机热备
  • python + Pytest + requests 的接口自动化步骤
  • SQL基础 | NOT NULL 约束介绍
  • 7.13实训日志
  • Qt易错总结
  • Chrome浏览器的Profile数据内容简介
  • 一边吃谷一边痛,二次元距离三次元还有多远?
  • 电视盒子变身NAS之安装termux
  • IDEA中Git常用操作及Git存储原理
  • LeetCode-计数质数
  • 分享 .NET EF6 查询并返回树形结构数据的 2 个思路和具体实现方法
  • Angular 响应式表单之下拉框
  • CoolViewPager:即刻刷新,自定义边缘效果颜色,双向自动循环,内置垂直切换效果,想要的都在这里...
  • Docker 1.12实践:Docker Service、Stack与分布式应用捆绑包
  • Flex布局到底解决了什么问题
  • Nginx 通过 Lua + Redis 实现动态封禁 IP
  • 读懂package.json -- 依赖管理
  • 技术胖1-4季视频复习— (看视频笔记)
  • 快速构建spring-cloud+sleuth+rabbit+ zipkin+es+kibana+grafana日志跟踪平台
  • 什么软件可以剪辑音乐?
  • 在Unity中实现一个简单的消息管理器
  • hi-nginx-1.3.4编译安装
  • #13 yum、编译安装与sed命令的使用
  • #define用法
  • #include<初见C语言之指针(5)>
  • #QT(QCharts绘制曲线)
  • #ubuntu# #git# repository git config --global --add safe.directory
  • #宝哥教你#查看jquery绑定的事件函数
  • (35)远程识别(又称无人机识别)(二)
  • (java版)排序算法----【冒泡,选择,插入,希尔,快速排序,归并排序,基数排序】超详细~~
  • (leetcode学习)236. 二叉树的最近公共祖先
  • (Matlab)基于蝙蝠算法实现电力系统经济调度
  • (定时器/计数器)中断系统(详解与使用)
  • (三分钟)速览传统边缘检测算子
  • (四)Linux Shell编程——输入输出重定向
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (一)ClickHouse 中的 `MaterializedMySQL` 数据库引擎的使用方法、设置、特性和限制。
  • (转)使用VMware vSphere标准交换机设置网络连接
  • .NET Core 中插件式开发实现
  • .net 调用php,php 调用.net com组件 --
  • .NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)
  • .net最好用的JSON类Newtonsoft.Json获取多级数据SelectToken
  • .vimrc php,修改home目录下的.vimrc文件,vim配置php高亮显示
  • @Bean注解详解
  • [ C++ ] STL---仿函数与priority_queue
  • [].shift.call( arguments ) 和 [].slice.call( arguments )
  • [100天算法】-不同路径 III(day 73)
  • [100天算法】-目标和(day 79)
  • [ai笔记4] 将AI工具场景化,应用于生活和工作
  • [Algorithm][综合训练][kotori和气球][体操队形][二叉树中的最大路径和]详细讲解
  • [Android 13]Input系列--获取触摸窗口