经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Elasticsearch » 查看文章
ES 27 - Elasticsearch脚本的使用实践
来源:cnblogs  作者:瘦风  时间:2019/8/16 9:18:53  对本文有异议

本文以 ES 6.6.0 版本为例进行演示.

1 关于脚本

ES提供了脚本支持 —— 可以通过Groovy外置脚本(已过时)、内置painless脚本实现各种复杂操作.

—— painless有轻便之意, 使用时直接在语法中调用即可, 无需外置, 也就是不支持通过外部文件存储painless脚本并调用的方法.

  1. // 向ES中插入一条数据:
  2. PUT employee/developer/1
  3. {
  4. "name": "shou feng",
  5. "age": 20,
  6. "salary": 10000
  7. }
  8. // 通过GET发送脚本, 允许为每个匹配的文档返回脚本评估(script evaluation)内容:
  9. GET employee/_search
  10. {
  11. "script_fields": {
  12. "change_age_field": { // 该字段不存在 - script fields可以处理未存储的字段
  13. "script": {
  14. "lang": "expression",
  15. "source": "doc['age'] * multiplier", // 获取age字段的值进行计算
  16. "params": {
  17. "multiplier": 2
  18. }
  19. }
  20. }
  21. }
  22. }
  23. // 响应结果为:
  24. {
  25. "took" : 1,
  26. "timed_out" : false,
  27. "_shards" : {
  28. "total" : 5,
  29. "successful" : 5,
  30. "skipped" : 0,
  31. "failed" : 0
  32. },
  33. "hits" : {
  34. "total" : 1,
  35. "max_score" : 1.0,
  36. "hits" : [
  37. {
  38. "_index" : "employee",
  39. "_type" : "developer",
  40. "_id" : "1",
  41. "_score" : 1.0,
  42. "fields" : {
  43. "change_age_field" : [
  44. 40.0
  45. ]
  46. }
  47. }
  48. ]
  49. }
  50. }

2 脚本使用的最佳实践

Elasticsearch第一次加载一个新脚本时, 会将新脚本编译并存储在缓存中.

编译可能是一个繁重的过程, 如果需要将变量传递给脚本, 建议: 将它们作为命名参数传递给脚本本身(方式①), 而不是硬编码在脚本中(方式②).

(1) 方式① 参数传递:

  1. "source": "doc['age'] * multiplier",
  2. "params": {
  3. "multiplier": 2
  4. }

(2) 方式② 硬编码:

  1. "source": "doc['age'] * 2"

(3) 优劣对比:

  • 每次乘数改变时都必须重新编译第②个版本, 而第①个版本只编译一次.

  • 如果短时间内编译过多的脚本, ES将拒绝带有circuit_breaking_exception错误的新脚本.

  • Elasticsearch默认情况下, 每分钟最多编译15个内联脚本, 可以通过修改 script.max_compilations_rate 的值来更改此设置.

2.1 创建脚本并存储

可以使用_scripts API 将脚本存储在集群状态中, 并从集群状态中检索脚本.

使用_scripts/{id}的方式操作脚本, 具体步骤如下:

(1) 首先在集群状态中创建名为calculate-score的脚本:

  1. POST _scripts/calculate-score
  2. {
  3. "script": {
  4. "lang": "painless",
  5. "source": "Math.log(_score * 2) + params.my_modifier"
  6. }
  7. }

(2) 检索存储的脚本:

  1. GET _scripts/calculate-score

(3) 通过脚本id使用已创建的脚本:

  1. GET _search
  2. {
  3. "query": {
  4. "script": {
  5. "script": {
  6. "id": "calculate-score",
  7. "params": {
  8. "my_modifier": 2 // 传递脚本所需的参数
  9. }
  10. }
  11. }
  12. }
  13. }

(4) 删除脚本:

  1. DELETE _scripts/calculate-score

2.2 脚本的缓存

默认情况下, 所有的脚本都会被缓存到ES集群中, 因此只有当脚本被更新之后, ES才会重新编译它们.

同样, 脚本没有过期时间的说法, 但可以使用script.cache.expire设置更改过期时间.

也可以使用script.cache.max_size配置此脚本缓存的大小, 默认缓存大小为100.

存储脚本的大小限制为65535字节, 可以通过 script.max_size_in_bytes来更改, 但是如果脚本非常大, 就应该考虑相关脚本的实现引擎是否足够优秀.

2.3 Script Field - 脚本字段

脚本字段还可以通过访问_source字段来提取文档的其他字段 —— 使用params ['_source']提取要从中获取的内容.

比如访问_source元字段中message字段的内容, 可以用: "script": "params['_source']['message']"访问.

另外: 理解doc['my_field'].valueparams['_source']['my_field']之间的区别非常重要:

① 使用doc关键字: 将导致该字段的术语加载到内存(缓存)中, 这样脚本的执行速度会更快, 但也会带来更多的内存消耗. 另外, doc […]符号只允许简单的值字段(不能从中返回JSON对象), 并且它只对非分析或基于单个术语的字段有意义.

② 使用params关键字: 每次使用时都必须加载和解析_source, 这是非常缓慢的.

建议: 使用doc关键字, 从文档中访问相关字段的值, 这种方式更加高效.


参考资料

ES 6.6 官方文档 - How to use scripts

版权声明

作者: 马瘦风(https://healchow.com)

出处: 博客园 马瘦风的博客(https://www.cnblogs.com/shoufeng)

感谢阅读, 如果文章有帮助或启发到你, 点个[好文要顶??] 或 [推荐??] 吧??

本文版权归博主所有, 欢迎转载, 但 [必须在文章页面明显位置标明原文链接], 否则博主保留追究相关人员法律责任的权利.

原文链接:http://www.cnblogs.com/shoufeng/p/11360177.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号