首页 > 其他分享 >Elasticsearch7.X Scripting脚本使用详解

Elasticsearch7.X Scripting脚本使用详解

时间:2024-01-04 11:33:43浏览次数:36  
标签:脚本 index 自定义 script painless source Elasticsearch7 详解 Scripting

0、题记

除了官方文档,其他能找到的介绍Elasticsearch脚本(Scripting)的资料少之又少。

一方面:性能问题。
官方文档性能优化中明确指出使用脚本会导致性能低;

另一方面:使用场景相对少。
非复杂业务场景下,基础的增、删、改、查基本上就能搞定。

但,不能否认,在解决复杂业务问题(如:自定义评分、自定义文本相关度、自定义过滤、自定义聚合分析)时,脚本依然是Elasticsearch强悍的利器之一。

本文在官方文档基础上,结合实际业务场景,在Elasticsearch7.3环境下进行脚本使用解读。

1、官方scripting使用建议

Avoid scripts——In general, scripts should be avoided.
If they are absolutely needed, you should prefer the painless and expressions engines.

ebay在性能优化实践中也强调(本文做了扩展延伸):

避免使用脚本查询(script query)计算动态字段。

例如:我们有一个包含大量剧院信息的索引,我们需要查询以"Down"开头的所有剧院。你可能运行一个如下脚本查询:

1POST seats/_search
 2{
 3 "query": {
 4  "bool":{
 5    "filter": { 
 6    "script":{
 7      "script":{
 8        "lang":"painless",
 9        "source": "doc['theatre'].value.startsWith('Down')"
10      }
11    }
12    }
13  }
14 }
15}

这个查询非常耗费资源,并且减慢整个系统。

解决方案:

  • 方案一:prefix前缀匹配;实测性能:prefix较scripting性能提升5倍。
  • 方案二:索引时考虑添加一个名为“theatre_prefix”的keyword类型字段。然后我们可以查询"theatre_prefix":"Down"。

2、ES Scripting历史


版本

使用脚本

< Elasticsearch 1.4

MVEL 脚本

< Elasticsearch 5.0

Groovy 脚本

‘>= Elasticsearch 5.0

painless 脚本

Groovy 的出现是解决MVEL的安全隐患问题;
但Groovy仍存在内存泄露+安全漏洞问题,

painless脚本的官宣时间:2016年9月21日。看似很新,截止目前,已经三年左右时间了。

正如其名字:无痛。painless的出现是为了用户更方便、高效的使用脚本。

https://www.elastic.co/cn/blog/painless-a-new-scripting-language

3、Painless Scripting 简介

Painless是一种简单,安全的脚本语言,专为与Elasticsearch一起使用而设计。它是Elasticsearch的默认脚本语言,可以安全地用于内联和存储脚本。

Painless特点:

  • 性能牛逼:Painless脚本运行速度比备选方案(包括Groovy)快几倍。
  • 安全性强:使用白名单来限制函数与字段的访问,避免了可能的安全隐患。
  • 可选输入:变量和参数可以使用显式类型或动态def类型。
  • 上手容易:扩展了java的基本语法,并兼容groove风格的脚本语言特性。
  • 特定优化:是ES官方专为Elasticsearch脚本编写而设计。

4、Scripting 应用场景

认知前提:
增删改查能解决业务场景80%的问题,Painless脚本操作一般应用于相对复杂的业务场景中。

常见场景举例如下:

  • 自定义字段
  • 自定义评分
  • 自定义更新
  • 自定义reindex
  • 聚合
  • 其他自定义操作

5、Scripting 使用模板

心中有模板,脚本认知就有了“套路”。

1"script": {
2    "lang":   "...",  
3    "source" | "id": "...", 
4    "params": { ... } 
5  }
  1. lang:代表language脚本语言,默认指定为:painless。
  2. source:脚本的核心部分,id应用于:stored script。
  3. params:传递给脚本使用的变量参数。

6、Scripting 实战

6.1 自定义字段

举例:返回原有Mapping未定义的字段值。
如:以my_doubled_field返回my_field字段的翻倍后的结果。

1GET my_index/_search
 2{
 3  "script_fields": {
 4    "my_doubled_field": {
 5      "script": {
 6        "lang":   "expression",
 7        "source": "doc['my_field'] * multiplier",
 8        "params": {
 9          "multiplier": 2
10        }
11      }
12    }
13  }
14}

注意:这里脚本语言选择的expression,下一节讲解。

如:返回日期字段中的“年”或“月”或“日”等。

1GET hockey/_search
 2{
 3  "script_fields": {
 4    "birth_year": {
 5      "script": {
 6        "source": "doc.born.value.year"
 7      }
 8    }
 9  }
10}

6.2 自定义评分

1GET my_index/_search
 2{
 3  "query": {
 4    "function_score": {
 5      "query": {
 6        "match": {
 7          "text": "quick brown fox"
 8        }
 9      },
10      "script_score": {
11        "script": {
12          "lang": "expression",
13          "source": "_score * doc['popularity']"
14        }
15      }
16    }
17  }
18}

6.3 自定义更新

Update:将已有字段值赋值给其他字段。

1POST hockey/_update/1
 2{
 3  "script": {
 4    "lang": "painless",
 5    "source": """
 6      ctx._source.last = params.last;
 7      ctx._source.nick = params.nick
 8    """,
 9    "params": {
10      "last": "gaudreau",
11      "nick": "hockey"
12    }
13  }
14}

Update_by_query:满足b开头(注意正则)的字段,末尾添加matched。

1POST hockey/_update_by_query
 2{
 3  "script": {
 4    "lang": "painless",
 5    "source": """
 6      if (ctx._source.last =~ /b/) {
 7        ctx._source.last += "matched";
 8      } else {
 9        ctx.op = "noop";
10      }
11    """
12  }
13}

6.4 自定义reindex

Elasticsearch认证考试题:

有index_a包含一些文档, 要求创建索引index_b,通过reindex api将index_a的文档索引到index_b。

要求:
1)增加一个整形字段,value是index_a的field_x的字符长度;

2)再增加一个数组类型的字段,value是field_y的词集合。

(field_y是空格分割的一组词,比方"foo bar",索引到index_b后,要求变成["foo", "bar"])

1POST _reindex
 2{
 3  "conflicts": "proceed",
 4  "source": {
 5    "index": "index_a"
 6  },
 7  "dest": {
 8    "index": "index_b"
 9  },
10  "script": {
11    "source": "ctx._source.parts = / /.split(ctx._source.address); ctx._source.tag = ctx._source.city.length();"
12  }
13}

语法参考:

https://www.elastic.co/guide/en/elasticsearch/painless/7.3/painless-regexes.html

6.5 聚合

1GET /_search
 2{
 3    "aggs" : {
 4        "genres" : {
 5            "terms" : {
 6                "script" : {
 7                    "source": "doc['genre'].value",
 8                    "lang": "painless"
 9                }
10            }
11        }
12    }
13
14}

6.6 其他自定义操作

需要结合业务去实践。

7、常见坑及问题

7.1 脚本只有Painless吗?

显然不是,第6节用到的expression 是Lucene’s expressions 脚本语言。

还可以基于脚本引擎自己开发插件实现,

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

7.2 怎么界定是expressions 还是Painless?

"lang": "painless",
"lang": "expressions ",
是唯一区分。

7.3 使用painless就百分之百“无痛”,无漏洞后顾之忧了吗?

凡事不能绝对。
核心注意点:
第一:不要root账户下运行Elasticsearch。
第二:不要公开ES路径给其他用户。
第三:不要公开ES路径到互联网。

实战推荐:

  • 1、用户在搜索框中键入文本,文本将直接发送到后台的match、match_phrase、Simple query string或 Suggesters.
  • 2、作为应用程序开发过程的一部分(而非全部)开放上述查询的脚本。
  • 3、使用用户提供的参数运行脚本。
  • 4、文档固定的Mapping结构。

不推荐:

  • 1、用户可以编写任意scripts, queries(检索), _search requests(search请求)。
  • 2、文档结构可以用户自定义。

8、小结

本文讲解了脚本的发展历史、使用场景、应用实战,但相比于实际业务的复杂需求仍然是九牛一毛。

实战中,肯定还会遇到这样、那样的问题。

参考:

https://www.elastic.co/guide/en/elasticsearch/reference/current/tune-for-search-speed.html
https://www.infoq.cn/article/elasticsearch-performance-tuning-practice-at-ebay
https://github.com/laoyang360/deep_elasticsearch/blob/master/es_dsl_study/6.scripting.md
https://github.com/elastic/elasticsearch/issues/19396
https://www.youtube.com/watch?v=3FLEJJ8PsM4
https://blog.csdn.net/u013613428/article/details/78134170


标签:脚本,index,自定义,script,painless,source,Elasticsearch7,详解,Scripting
From: https://blog.51cto.com/u_64214/9097596

相关文章

  • 【机器学习】常见算法详解第1篇:K近邻 KNN和API使用(已分享,附代码)
    本系列文章md笔记(已分享)主要讨论机器学习算法相关知识。机器学习算法文章笔记以算法、案例为驱动的学习,伴随浅显易懂的数学知识,让大家掌握机器学习常见算法原理,应用Scikit-learn实现机器学习算法的应用,结合场景解决实际问题。包括K-近邻算法,线性回归,逻辑回归,决策树算法,集成学习,聚......
  • Apache Commons VFS(虚拟文件系统)使用详解
    第1章:ApacheCommonsVFS简介大家好,我是小黑,今天我们来聊聊ApacheCommonsVFS(虚拟文件系统)。想必很多朋友都听说过或者用过ApacheCommons的其他库,但是VFS可能还有点陌生。那么,什么是ApacheCommonsVFS呢?简单来说,它是一个用于处理各种类型文件系统的Java库。不管是本地文件系......
  • 【迅搜12】搜索技巧(二)搜索条件详解
    搜索技巧(二)搜索条件详解上回我们已经学习了一些简单的搜索功能,比如设置搜索语句、分页方法、数量查询以及高亮和折叠的查询效果。而今天,我们将更加深入地学习其它搜索相关的内容。最核心的,就是布尔查询,也就是类似于我们在数据库中的AND和OR之类的语法。不过在这之前,就像是Expl......
  • Pytest测试框架基本使用方法详解
    pytest介绍pytest是一个非常成熟的全功能的Python测试框架,主要特点有以下几点:1、简单灵活,容易上手,文档丰富;2、支持参数化,可以细粒度地控制要测试的测试用例;3、能够支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试、接口自动化测试(pytest+requests);4、......
  • 【微服务】springboot整合kafka-stream使用详解
    目录一、前言二、kafkastream概述2.1什么是kafkastream2.2为什么需要kafkastream2.2.1对接成本低2.2.2节省资源2.2.3使用简单2.3kafkastream特点2.4kafkastream中的一些概念2.5 KafkaStream应用场景三、环境准备3.1搭建zk3.1.1自定义docker网络3.1.2 拉取zk镜像3.......
  • Python字符串操作:获取子序列的方法详解
    在Python中,处理字符串是一项常见的任务,其中一个常见的需求是从一个字符串中获取某一特定的子序列。这个子序列可以是一个连续的子字符串,也可以是不连续的一组字符。在这篇文章中,我们将探讨在Python中获取子序列的几种常见方法。1.切片操作Python中的切片操作是获取子序列的一种简便......
  • @ExceptionHandler详解
    一、@ExceptionHandler介绍@ExceptionHandler注解我们一般是用来自定义异常的。可以认为它是一个异常拦截器(处理器)。异常间的层次关系二、@ExceptionHandler的使用1:极简测试,一共4个类: 1、一个SpringBoot启动类 2、一个控制层 3、一个异常处理类 4、一个service类启动类:Exc......
  • 轻松转换,一键搞定:JVS低代码平台的日期格式转换功能详解!
    日期和时间在我们的日常生活中起着至关重要的作用,无论是计划日程、管理项目还是执行其他任务,都需要精确的时间信息。在JVS低代码平台上,日期格式转换主要依赖于逻辑引擎中的函数公式。这些函数为我们的用户提供了一种强大且灵活的方式来处理和转换日期时间数据。我们的时间函数旨在......
  • 24届春招实习必备技能(一)之MyBatis Plus入门实践详解
    一、什么是MyBatisPlus?MyBatisPlus简称MP,是mybatis的增强工具,旨在增强,不做改变。MyBatisPlus内置了内置通用Mapper、通用Service,仅仅通过少量配置即可实现单表大部分CRUD操作,更有强大的条件构造器,满足各类使用需求。官网地址:https://mp.baomidou.com/主要特性无侵入:只做增......
  • java基础知识点API之String详解--String基础看它就够了
    一:概述java中的String在java.lang包下,使用时可以直接使用不需要进行导包。字符串在日常使用中非常多,例如之前的变量定义。二:详细说明<1>JDK-帮助文档中对Strng类的介绍<2>字符串常量的创建,字符串常量在创建之后,它们的值不能被更改,但是可以被共享。publicstaticvoidmain(String[......