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

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 除了官方文档,其他能找到的介绍Elasticsearch脚本(Scripting)的资料少之又少。一方面:性能问题。官方文档性能优化中明确指出使用脚本会导致性能低;另一方面:使用场景相对少。非复杂业务场景下,基础的增、删、改、查基本上就能搞定。但,不能否认,在解决复杂业务问题(如:自定义评分、自定义文本相关度、自定义过滤、自定义聚合分析)时,脚本依然是Elasticsearch强悍的利器之一。

image.png

链接

本文在官方文档基础上,结合实际业务场景,在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  }


lang:代表language脚本语言,默认指定为:painless。


source:脚本的核心部分,id应用于:stored script。


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

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
7月前
|
JavaScript
ElasticSearch快照脚本
ElasticSearch快照脚本
72 0
|
7月前
|
Java 关系型数据库 MySQL
Elasticsearch【问题记录 01】启动服务&停止服务的2类方法【及 java.nio.file.AccessDeniedException: xx/pid 问题解决】(含shell脚本文件)
【4月更文挑战第12天】Elasticsearch【问题记录 01】启动服务&停止服务的2类方法【及 java.nio.file.AccessDeniedException: xx/pid 问题解决】(含shell脚本文件)
677 3
|
6月前
|
缓存 监控 安全
深入解析Elasticsearch中脚本原理
深入解析Elasticsearch中脚本原理
|
7月前
|
存储 数据处理 索引
Elasticsearch 8.X 小技巧:使用存储脚本优化数据索引与转换过程
Elasticsearch 8.X 小技巧:使用存储脚本优化数据索引与转换过程
105 6
|
7月前
|
关系型数据库 MySQL Java
Elasticsearch【问题记录 01】启动&停止服务的2类方法及 java.nio.file.AccessDeniedException: xx/pid 问题解决(含启停shell脚本)
Elasticsearch【问题记录 01】启动&停止服务的2类方法及 java.nio.file.AccessDeniedException: xx/pid 问题解决(含启停shell脚本)
168 0
|
Shell 索引 Perl
通过shell脚本统计elasticsearch indices每天的数量以及大小
通过shell脚本统计elasticsearch indices每天的数量以及大小
62 0
|
存储 JSON Java
【Elasticsearch】学好Elasticsearch系列-脚本查询
【Elasticsearch】学好Elasticsearch系列-脚本查询
467 0
|
存储 测试技术 Shell
Elasticsearch自定义脚本完成性能测试
1、ES性能测试 要求: 1)完成ES并发100次性能测试; 2)统计得出访问时间结果值。
347 0
|
Shell 测试技术
Elasticsearch自定义脚本完成性能测试
自定义脚本完成性能测试
525 0
|
Python
Elasticsearch批量导入数据脚本(python)
个人因业务需求,压测需要批量导入数据到es,然后这个脚本就出现了。。。。
3883 0