深入了解 Elasticsearch 8.1 中的 Script 使用

alt

一、什么是 Elasticsearch Script?

Elasticsearch 中的 Script 是一种灵活的方式,允许用户在查询、聚合和更新文档时执行自定义的脚本。这些脚本可以用来动态计算字段值、修改查询行为、执行复杂的条件逻辑等等。

二、支持的脚本语言有哪些

支持多种脚本语言,包括 PainlessExpressionMustacheJava等,其中默认的是Painless

alt

三、Painless 脚本的使用

Painless 是一种专为 Elasticsearch 设计的脚本语言,具有安全、快速、简单的特点,使其在 Elasticsearch 中非常方便入门。

  1. 安全性: Painless 被设计为一种安全的脚本语言。它采取了一系列的安全措施,如禁止无限循环、禁止访问 Java 类库中的危险类等,以减轻潜在的安全风险。

  2. 高性能: Painless 是为高性能而设计的,特别是在 Elasticsearch 中。它经过了优化,可以在大规模数据集上快速执行。

  3. 易学易用: Painless 实现了任何具有基本编码经验的人都自然熟悉的语法。Painless 使用 Java 语法的子集,并进行了一些额外的改进,以增强可读性并删除样板文件。

  4. 无需编译: Painless 脚本不需要预先编译。它可以在运行时解释,所以我们可以动态调整脚本而无需重新编译整个应用程序。

  5. 支持参数化: Painless 允许在脚本中使用参数,这可以使脚本更通用,适用于多种情况。参数化脚本可以接受外部传递的值,从而在不修改脚本的情况下改变其行为。

  6. 支持多种数据类型: Painless 支持多种数据类型,包括数字、字符串、日期、布尔值等。

  7. 集成性: Painless 被紧密集成到 Java 中,可以用于查询、聚合、脚本字段、脚本排序等各种用例。

3.1、编写我们的第一个脚本

使用的 Elasticsearch 版本为 8.1,历史文章除非特别说明,最近更文的 ES版本都为 Elasticsearch8.1 版本

脚本的组成有三个参数,只要是在 Elasticsearch API 支持脚本的地方,都可以使用如下三个参数来使用脚本。

 "script": {"lang":   "...","source" | "id": "...","params": { ... }}
  • lang:执行脚本语言类型,默认 painless
  • source,id:脚本的源码本身,或者提前存储的 脚本ID
  • params:作为变量传递给脚本的参数

下面我们将通过实际的例子来进行说明

3.2、在检索中使用脚本

  • 首先我们先往索引中插入一篇文档

    PUT zfc-doc-000007/_doc/1
    {"sum": 5,"message":"test painless"
    }
    
  • 使用脚本实现 sum的值 乘2,此处使用变量 multiplier,在脚本的参数中指定参数值为2,其中doc['sum'].value * params['multiplier']的意思就是获取文档中sum的值并乘以脚本中 multiplier 的值

    GET zfc-doc-000007/_search
    {"script_fields": {"my_doubled_field": {"script": { "source": "doc['sum'].value * params['multiplier']", "params": {"multiplier": 2}}}}
    }
    
  • 在获取脚本的参数中的变量值除了使用params['参数名']这种方式之外,还可以使用params.get('multiplier')方法获取

    GET zfc-doc-000007/_search
    {"script_fields": {"my_doubled_field": {"script": {"lang":   "painless","source": "doc['sum'].value * params.get('multiplier');","params": {"multiplier": 2}}}}
    }
    

上面我们是在检索请求中使用的脚本字段来使用的脚本,下面我们先内置一个脚本,通过使用脚本ID来使用内置的脚本

3.3、使用内置的脚本

  • 创建一个脚本calculate-score,它可以使用Math.log(_score * 2) + params['my_modifier']修改分数值

    POST _scripts/calculate-score
    {"script": {"lang": "painless","source": "Math.log(_score * 2) + params['my_modifier']"}
    }
  • 创建完成的脚本我们可以使用_scriptAPI查看脚本的内容

    GET _scripts/calculate-score
    
  • 在检索中只需要如下指定脚本的ID即可进行检索时使用

    GET zfc-doc-000007/_search
    {"query": {"script_score": {"query": {"match": {"message": "painless"}},"script": {"id": "calculate-score", "params": {"my_modifier": 2}}}}
    }
    
  • 如果想删除脚本只需要调用DELETE 即可

    DELETE _scripts/calculate-score
    

下面我们再来演示一下如何使用脚本更新文档中的内容

3.4、使用脚本操作文档

  • 先添加一个文档来进行测试

    PUT zfc-doc-000007/_doc/1
    {"counter" : 1,"tags" : ["red"]
    }
    
  • 使用脚本对文档中的 counter 的值与脚本中的 count 值进行相加

    
    POST zfc-doc-000007/_update/1
    {"script" : {"source": "ctx._source.counter += params.count","lang": "painless","params" : {"count" : 4}}
    }
    
  • 我们还可以对文档中的数组类型的tags字段进行增加子对象,比如增加一个blue

    POST zfc-doc-000007/_update/1
    {"script": {"source": "ctx._source.tags.add(params['tag'])","lang": "painless","params": {"tag": "blue"}}
    }
    
  • 使用脚本对文档中的 tags 的值进行删除,条件就是当 tag 的值与脚本中的值相等时删除。如下为当 tags 的值为blue时,删除blue

    POST zfc-doc-000007/_update/1
    {"script": {"source": "if (ctx._source.tags.contains(params['tag'])) { ctx._source.tags.remove(ctx._source.tags.indexOf(params['tag'])) }","lang": "painless","params": {"tag": "blue"}}
    }
    
  • 上面只是对已有字段的增加删除修改,下面还可以使用脚本进行新字段的增加,比如增加一个字段new_field,值是value_of_new_field

    POST zfc-doc-000007/_update/1
    {"script" : "ctx._source.new_field = 'value_of_new_field'"
    }
    
  • 上面是字段的增加,下面就是字段的移除

    POST zfc-doc-000007/_update/1
    {"script" : "ctx._source.remove('new_field')"
    }
    
  • 除了对字段的删除,数组对象内部值的删除,还可以对文档进行删除。如下,当 tags 里面包含 blue 时,删除当前文档

    POST zfc-doc-000007/_update/1
    {"script": {"source": "if (ctx._source.tags.contains(params['tag'])) { ctx.op = 'delete' } else { ctx.op = 'none' }","lang": "painless","params": {"tag": "blue"}}
    }
    

3.5、使用脚本解析日志信息

所谓的解析字符串,只是一组固定格式的字符串,提前使用变量的形式编译,在插入文档时,通过脚本进行解析保存,方便后面的检索等请求

假如我们有如下数据

"message" : "247.37.0.0 - - [30/Apr/2020:14:31:22 -0500] \"GET /images/hm_nbg.jpg HTTP/1.0\" 304 0"

那么我们可以使用如下变量的形式解析该字符串

%{clientip} %{ident} %{auth} [%{@timestamp}] \"%{verb} %{request} HTTP/%{httpversion}\" %{status} %{size}

下面我们使用例子来说明脚本解析字符串之后是何种形式的存在

  • 创建一个索引保存解析的数据

    PUT zfc-doc-000008
    {"mappings": {"properties": {"message": {"type": "wildcard"}}}
    }
    
  • 内置一个脚本,实现解析字符串信息,并提取需要的信息,如下为提取当前日志中的 http 响应信息response,对于如下脚本的测试API使用详情可以参考官网

    https://www.elastic.co/guide/en/elasticsearch/painless/8.1/painless-execute-api.html

    POST /_scripts/painless/_execute
    {"script": {"source": """String response=dissect('%{clientip} %{ident} %{auth} [%{@timestamp}] "%{verb} %{request} HTTP/%{httpversion}" %{response} %{size}').extract(doc["message"].value)?.response;if (response != null) emit(Integer.parseInt(response)); """},"context": "long_field", "context_setup": {"index": "zfc-doc-000008","document": {          "message": """247.37.0.0 - - [30/Apr/2020:14:31:22 -0500] "GET /images/hm_nbg.jpg HTTP/1.0" 304 0"""}}
    }
    

如果我们还想操作当前解析的数据我们可以使用运行时字段,因为运行时字段不需要进行索引会更加的灵活,可以很方便的修改脚本及运行方式。

  • 那么我们现在删除一下刚刚创建的索引,重新添加一下,创建语句如下

    DELETE zfc-doc-000008
    PUT /zfc-doc-000008
    {"mappings": {"properties": {"@timestamp": {"format": "strict_date_optional_time||epoch_second","type": "date"},"message": {"type": "wildcard"}}}
    }
    
  • 添加一个运行时字段来保存解析的结果

    PUT zfc-doc-000008/_mappings
    {"runtime": {"http.response": {"type": "long","script": """String response=dissect('%{clientip} %{ident} %{auth} [%{@timestamp}] "%{verb} %{request} HTTP/%{httpversion}" %{response} %{size}').extract(doc["message"].value)?.response;if (response != null) emit(Integer.parseInt(response));"""}}
    }
    
  • 添加几条测试数据用于测试

    POST /zfc-doc-000008/_bulk?refresh=true
    {"index":{}}
    {"timestamp":"2020-04-30T14:30:17-05:00","message":"40.135.0.0 - - [30/Apr/2020:14:30:17 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
    {"index":{}}
    {"timestamp":"2020-04-30T14:30:53-05:00","message":"232.0.0.0 - - [30/Apr/2020:14:30:53 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
    {"index":{}}
    {"timestamp":"2020-04-30T14:31:12-05:00","message":"26.1.0.0 - - [30/Apr/2020:14:31:12 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
    {"index":{}}
    {"timestamp":"2020-04-30T14:31:19-05:00","message":"247.37.0.0 - - [30/Apr/2020:14:31:19 -0500] \"GET /french/splash_inet.html HTTP/1.0\" 200 3781"}
    {"index":{}}
    {"timestamp":"2020-04-30T14:31:22-05:00","message":"247.37.0.0 - - [30/Apr/2020:14:31:22 -0500] \"GET /images/hm_nbg.jpg HTTP/1.0\" 304 0"}
    {"index":{}}
    {"timestamp":"2020-04-30T14:31:27-05:00","message":"252.0.0.0 - - [30/Apr/2020:14:31:27 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
    {"index":{}}
    {"timestamp":"2020-04-30T14:31:28-05:00","message":"not a valid apache log"}
    
  • 下面我们进行运行时字段检索响应为304的数据

    
    GET zfc-doc-000008/_search
    {"query": {"match": {"http.response": "304"}},"fields" : ["http.response"]
    }
  • 刚才是属于提前内置好运行时字段,我们也可以直接在检索时指定运行时字段来使用,但下面所示的仅在运行时有效。如下所示

    GET zfc-doc-000008/_search
    {"runtime_mappings": {"http.response": {"type": "long","script": """String response=dissect('%{clientip} %{ident} %{auth} [%{@timestamp}] "%{verb} %{request} HTTP/%{httpversion}" %{response} %{size}').extract(doc["message"].value)?.response;if (response != null) emit(Integer.parseInt(response));"""}},"query": {"match": {"http.response": "304"}},"fields" : ["http.response"]
    }
    

我们也可以根据特定的值进行拆分,获取所需要的信息

3.6、使用脚本解析 GC 信息

  • 例如如下 ElasticsearchGC 信息

    [2021-04-27T16:16:34.699+0000][82460][gc,heap,exit]   class space    used 266K, capacity 384K, committed 384K, reserved 1048576K
    
  • 下面我们根据 GC 信息编写一个解析模式

    [%{@timestamp}][%{code}][%{desc}]  %{ident} used %{usize}, capacity %{csize}, committed %{comsize}, reserved %{rsize}
    
  • 然后在检索时就可以使用如下语句来提交信息到运行时字段,首先添加测试数据,注意索引名称已经更换,解析模式不匹配会报错

    
    POST /zfc-doc-000010/_bulk?refresh
    {"index":{}}
    {"gc": "[2021-04-27T16:16:34.699+0000][82460][gc,heap,exit]   class space    used 266K, capacity 384K, committed 384K, reserved 1048576K"}
    {"index":{}}
    {"gc": "[2021-03-24T20:27:24.184+0000][90239][gc,heap,exit]   class space    used 15255K, capacity 16726K, committed 16844K, reserved 1048576K"}
    {"index":{}}
    {"gc": "[2021-03-24T20:27:24.184+0000][90239][gc,heap,exit]  Metaspace       used 115409K, capacity 119541K, committed 120248K, reserved 1153024K"}
    {"index":{}}
    {"gc": "[2021-04-19T15:03:21.735+0000][84408][gc,heap,exit]   class space    used 14503K, capacity 15894K, committed 15948K, reserved 1048576K"}
    {"index":{}}
    {"gc": "[2021-04-19T15:03:21.735+0000][84408][gc,heap,exit]  Metaspace       used 107719K, capacity 111775K, committed 112724K, reserved 1146880K"}
    {"index":{}}
    {"gc": "[2021-04-27T16:16:34.699+0000][82460][gc,heap,exit]  class space  used 266K, capacity 367K, committed 384K, reserved 1048576K"}
    
  • 使用检索语句展示解析数据到运行时字段中

    GET zfc-doc-000010/_search
    {"runtime_mappings": {"gc_size": {"type": "keyword","script": """Map gc=dissect('[%{@timestamp}][%{code}][%{desc}]  %{ident} used %{usize}, capacity %{csize}, committed %{comsize}, reserved %{rsize}').extract(doc["gc.keyword"].value);if (gc != null) emit("used" + ' ' + gc.usize + ', ' + "capacity" + ' ' + gc.csize + ', ' + "committed" + ' ' + gc.comsize);"""}},"size": 1,"aggs": {"sizes": {"terms": {"field": "gc_size","size": 10}}},"fields" : ["gc_size"]
    }
    

通过上面的查询测试可以知道,Elasticsearch 中的 script 默认的时 painless 语言,功能已经非常强大可以满足我们的日常需求,如果还想更高级的脚本,可以使用 Java 语言来编写自己的脚本。关于 Expressions 的表达式的使用就参与官网吧,本文的所有例子均来自官网,并自测完成。如有错误欢迎指出,共同进步。

后面有机会会出现一片使用Java编译脚本的使用,等后面时间吧,最近这段时间听尴尬的,也托更很久了,以后慢慢的都要补上。

2023 最后俩月了,加油。

原文链接

https://www.elastic.co/guide/en/elasticsearch/reference/8.1/modules-scripting.html

本文由 mdnice 多平台发布

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

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

相关文章

JavaWeb——关于servlet种mapping地址映射的一些问题

6、Servlet 6.4、Mapping问题 一个Servlet可以指定一个映射路径 <servlet-mapping><servlet-name>hello</servlet-name><url-pattern>/hello</url-pattern> </servlet-mapping>一个Servlet可以指定多个映射路径 <servlet-mapping>&…

音视频技术开发周刊 | 317

每周一期&#xff0c;纵览音视频技术领域的干货。 新闻投稿&#xff1a;contributelivevideostack.com。 MIT惊人再证大语言模型是世界模型&#xff01;LLM能分清真理和谎言&#xff0c;还能被人类洗脑 MIT等学者的「世界模型」第二弹来了&#xff01;这次&#xff0c;他们证明…

中文编程工具免费版下载,中文开发语言工具免费版下载

中文编程工具免费版下载&#xff0c;中文开发语言工具免费版下载 中文编程工具开发的实际部分案例如下图 编程系统化课程总目录及明细&#xff0c;点击进入了解详情。 https://blog.csdn.net/qq_29129627/article/details/134073098?spm1001.2014.3001.5502

异步 AIMD 收敛

给出的一直都是同步 AIMD 收敛&#xff0c;所以简单&#xff0c;但不至于 bbr 单流情形退化成简陋。 给出一个异步 AIMD 收敛过程是必要的&#xff0c;可见&#xff0c;它同样是简洁优美的&#xff1a; 虽然我没有标注太多&#xff0c;它始终没有成为一团乱麻。 和同步 AIM…

softmax的高效CUDA编程和oneflow实现初步解析

本文参考了添加链接描述,其中oneflow实现softmax的CUDA编程源代码参考链接添加链接描述 关于softmax的解读以及CUDA代码实现可以参考本人之前编写的几篇文章添加链接描述,添加链接描述,添加链接描述 下面这个图片是之前本人实现的softmax.cu经过接入python接口,最终和pytor…

06、SpringCloud -- 订单详情界面实现

目录 订单详情界面实现需求&#xff1a;代码前端后端controllerservicemapperdomain 效果&#xff1a; 订单详情界面实现 需求&#xff1a; 现在的订单详情界面是这样的。需要获取订单的数据对这个详情页面进行渲染 代码 前端 后端 controller service mapper domain 日…

低功耗设计-ir drop的signoff corner怎么选择?

我正在「拾陆楼」和朋友们讨论有趣的话题&#xff0c;你⼀起来吧&#xff1f; 拾陆楼知识星球入口 相关文章链接: Multi Voltage Flow笔记 有几个方向&#xff0c;看公司需求吧 1.功耗最差的&#xff1b; 2.tt的&#xff08;tt85 是比较接近芯片真实工作情况的&#xff09…

Hbase

目录 1 概述 1.1 HBase 数据模型 1.1.1 HBase 逻辑结构 1.1.2 HBase 物理存储结构 1.1.3 数据模型 1.2 HBase 基本架构 2 HBase 快速入门 2.1 HBase 安装部署 hadoop3.X和Hbase2.X不兼容问题&#xff1a; 2.2 基本操作 3 HBase API 3.1 环境准备 3.2 创建连接 3.2.1 单线程创建…

【数据结构】数组和字符串(七):特殊矩阵的压缩存储:三元组表的转置、加法、乘法操作

文章目录 4.2.1 矩阵的数组表示4.2.2 特殊矩阵的压缩存储a. 对角矩阵的压缩存储b~c. 三角、对称矩阵的压缩存储d. 稀疏矩阵的压缩存储——三元组表4.2.3三元组表的转置、加法、乘法、操作转置加法乘法算法测试实验结果代码整合 4.2.1 矩阵的数组表示 【数据结构】数组和字符串…

github搜索技巧探索

毕设涉及到推荐系统&#xff0c;那么就用搜索推荐系统相关资料来探索一下GitHub的搜搜技巧 文章目录 1. 基础搜索2. 限定在特定仓库搜索3. 按照语言搜索4. 按照star数量搜索5. 搜索特定用户/组织的仓库6. 查找特定文件或路径7. 按时间搜索8. 搜索不包含某个词的仓库9. 搜索特定…

Spring MVC的常用注解(接收请求数据篇)

目录 RequestMapping 例子&#xff1a; RequestMapping 支持什么类型的请求 使 RequestMapping 只支持特定的类型 RestController 通过 HTTP 请求传递参数给后端 1.传递单个参数 注意使⽤基本类型来接收参数的情况 2.传递多个参数 3.传递对象 4.RequestParam 后端参数…

【教3妹学编辑-算法题】每棵子树内缺失的最小基因值

3妹&#xff1a;“太阳当空照&#xff0c;花儿对我笑&#xff0c;小鸟说早早早&#xff0c;你为什么背上炸药包” 2哥 :3妹&#xff0c;什么事呀这么开发。 3妹&#xff1a;2哥你看今天的天气多好啊&#xff0c;阳光明媚、万里无云、秋高气爽&#xff0c;适合秋游。 2哥&#x…

超全整理,Jmeter性能测试-脚本error报错排查/分布式压测(详全)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能脚本error报错…

【JavaSE专栏57】深度解析Java中的this和super关键字:用途、差异和实际应用

深度解析Java中的this和super关键字&#xff1a;用途、差异和实际应用 摘要引言1. this关键字1.1 什是this关键字&#xff1f; &#x1f914;使用 this 解决成员变量和参数之间的歧义&#xff1a;在构造方法中调用其他构造方法&#xff1a;1.3 引用成员变量和方法 &#x1f3af…

使用内网穿透工具进行支付宝沙箱环境支付的SDK接口远程测试

Java支付宝沙箱环境支付&#xff0c;SDK接口远程调试【内网穿透】 1.测试环境 MavenSpring bootJdk 1.8 2.本地配置 获取支付宝支付Java SDK,maven项目可以选择maven版本,普通java项目可以在GitHub下载,这里以maven为例 SDK下载地址&#xff1a;https://doc.open.alipay.com…

AutoEncoding与AutoRegressive:区别,联系和应用

关于AutoEncoding&#xff08;AE&#xff09;和AutoRegressive&#xff08;AR&#xff09; 前几天看了Ilya在Simons上做的关于Generative Model的演讲&#xff0c;介绍了OpenAI现在做的一些AutoRegressive的工作&#xff0c;昨天又看到LeCun宣称Auto-Regressive LLMs are doom…

CL_MVSNet复现可能会出现的问题汇总

1.最好按照说明文档要求配好python3.7和pytorch1.0 2. 【已解决】 FutureWarning: The module torch.distributed.launch is deprecated and will be removed in future. torch.distributed.launch被弃用&#xff0c;考虑使用torchrun模块进行替换。 解决方案&#xff1a; 将…

HDFS架构介绍

数新网络_让每个人享受数据的价值浙江数新网络有限公司是一家开源开放、专注于云数据智能操作系统和数据价值流通的服务商。公司自主研发的DataCyber云数据智能操作系统&#xff0c;主要包括数据平台CyberData、人工智能平台CyberAI、数据智能引擎CyberEngine、数据安全平台Cyb…

ChinaSoft 论坛巡礼 | 智慧化 IDE 论坛

2023年CCF中国软件大会&#xff08;CCF ChinaSoft 2023&#xff09;由CCF主办&#xff0c;CCF系统软件专委会、形式化方法专委会、软件工程专委会以及复旦大学联合承办&#xff0c;将于2023年12月1-3日在上海国际会议中心举行。 本次大会主题是“智能化软件创新推动数字经济与社…

ubuntu(18.04) 安装 blast

1、下载 https://ftp.ncbi.nlm.nih.gov/blast/executables/blast/LATEST/2、解压&#xff0c;配置环境变量 tar zvxf ncbi-blast-2.14.1-x64-linux.tar.gz解压后改名为 blast 配置环境变量&#xff0c;可以不配置 使用的时候直接绝对路径使用 vim ~/.bashrc 将下面添加道最…