如何使用Elasticsearch groovy script脚本更新数据

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用Elasticsearch groovy script脚本更新数据相关的知识,希望对你有一定的参考价值。

今天细说一下elasticsearch的update更新功能,以及如何利用script脚本更新数据。

想要使用script脚本功能,需要在配置文件elasticsearch.yml里设置

Python

script.disable_dynamic: false

关于elasticsearch script的文章,总是会没完没了的修改

ES支持更新,但是更新的方式是通过一个提供的脚本进行的。ES的做法是,通过
index找到相应的存放记录的节点,然后执行脚本,执行完之后,返回新的索引。实际上执行的是一个get和reindex的过程,在这个过程中,通过
versioning来控制没有其它的更新操作(这个功能是0.19后可用的)。具体实现的原理应该和elasticsearch
Versioning相关。

get,reindex的含义是,ES先取出这条记录,然后根据新数据生成新记录,然后在把新记录放回到ES中(并不会覆盖老的记录)。

现在没有数据,首先我们需要创建一条记录

Python

$ curl -XPUT localhost:9200/xiaorui.cc/blog/1 -d \'
"counter" : 1,
"tags" : ["red"]
\'

$ curl -XPUT localhost:9200/xiaorui.cc/blog/1 -d \'
"counter" : 1,
"tags" : ["red"]
\'

直接修改数据,一定要注意,直接update的化,会覆盖以前的数据,另外update的时候,需要/index/type/id ,一定要带着id。 elasticsearch 应该不支持搜索query方式update修改数据。

Python

curl -XPUT \'localhost:9200/xiaorui.cc/blog/1?pretty\' -d \'

"name": "xiaorui.cc"
\'

curl -XPUT \'localhost:9200/xiaorui.cc/blog/1?pretty\' -d \'

"name": "xiaorui.cc"
\'

elasticsearch提供了doc这个局部更新参数,他可以局部修改,而不会直接覆盖以前的数据,这会针对特定的k v,字段修改。

Python

curl -XPOST \'localhost:9200/xiaorui.cc/blog/1/_update?pretty\' -d \'

"doc": "name": "ruifengyun"
\'

curl -XPOST \'localhost:9200/xiaorui.cc/blog/1/_update?pretty\' -d \'

"doc": "name": "ruifengyun"
\'

当Elasticsearch API不能满足要求时,Elasticsearch允许你使用脚本实现自己的逻辑。脚本支持非常多的API,例如搜索、排序、聚合和文档更新。脚本可以通过请求的一部分、检索特殊的.scripts索引或者从磁盘加载方式执行。

下面是es script的用法,这些脚本是groovy开发的。 下面的语句的意思是说,将counter的值加4

Python

$ curl -XPOST \'localhost:9200/xiaorui.cc/blog/1/_update\' -d \'
"script" : "ctx._source.counter += count",
"params" :
"count" : 4

\'

$ curl -XPOST \'localhost:9200/xiaorui.cc/blog/1/_update\' -d \'
"script" : "ctx._source.counter += count",
"params" :
"count" : 4

\'

通过上面的例子,我们知道tags是个列表,如果用doc局部更新的语法,他是无法做到append的,还是会覆盖tags这个字段。 那么怎么实现列表扩展? 请使用elasticsearch script实现。

Python

$ curl -XPOST \'localhost:9200/xiaorui.cc/blog/1/_update\' -d \'
"script" : "ctx._source.tags += tag",
"params" :
"tag" : "white"

\'

$ curl -XPOST \'localhost:9200/xiaorui.cc/blog/1/_update\' -d \'
"script" : "ctx._source.tags += tag",
"params" :
"tag" : "white"

\'

_update也支持upsert功能,没有这个字段或者key,也会添加这个记录。下面是一个例子,如果没有counter字段,则插入该字段:

Python

$ curl -XPOST \'localhost:9200/xiaorui.cc/blog/1/_update\' -d \'
"script" : "ctx._source.counter += count",
"params" :
"count" : 4
,
"upsert" :
"counter" : 1

\'

$ curl -XPOST \'localhost:9200/xiaorui.cc/blog/1/_update\' -d \'
"script" : "ctx._source.counter += count",
"params" :
"count" : 4
,
"upsert" :
"counter" : 1

\'

下面我们来复杂点的groovy script脚本用法. 当你的source没有china这个key,那么我会增加一个kv

Python

curl -XPOST "http://localhost:9200/xiaorui.cc/blog/80/_update" -d\'

"script": "if (!ctx._source.containsKey(\\"china\\")) ctx._source.attending = newField ",
"params" : "newField" : "blue" ,
"myfield": "data"
\'

curl -XPOST "http://localhost:9200/xiaorui.cc/blog/80/_update" -d\'

"script": "if (!ctx._source.containsKey(\\"china\\")) ctx._source.attending = newField ",
"params" : "newField" : "blue" ,
"myfield": "data"
\'

下面的script语法相对复杂的,会遍历一组字典,然后进行判断赋值。


“55555″: 22,
“name”: “lisi”,
“distr_pan”: [

“k”: 15,
“v”: 15


“k”: 20,
“v”: 20

]


Python

$ curl -XPUT \'localhost:9200/xiaorui.cc/blog/9123/_update\' -d \'

"script" : "def x = false;ctx._source.distr_pan.each(if(it.get(\'k\')==target)x=true);if(x)ctx._source.distr_pan +=v",
"params":
"v":"k":nlp, "v":35,
"target":15



$ curl -XPUT \'localhost:9200/xiaorui.cc/blog/9123/_update\' -d \'

"script" : "def x = false;ctx._source.distr_pan.each(if(it.get(\'k\')==target)x=true);if(x)ctx._source.distr_pan +=v",
"params":
"v":"k":nlp, "v":35,
"target":15



elasticsearch script就讲解到这里了,很多例子已经简单明了…
script貌似不是很安全,最少远程代码执行的漏洞暴露过几次了. 下次把python版的script走一遍试试.
貌似对于我们你者来说,不管是groovy python,没什么太大却别,语法看起来都一个模子。
参考技术A Python

script.disable_dynamic: false

关于elasticsearch script的文章,总是会没完没了的修改

ES支持更新,但是更新的方式是通过一个提供的脚本进行的。ES的做法是,通过
index找到相应的存放记录的节点,然后执行脚本,执行完之后,返回新的索引。实际上执行的是一个get和reindex的过程,在这个过程中,通过
versioning来控制没有其它的更新操作(这个功能是0.19后可用的)。具体实现的原理应该和elasticsearch
Versioning相关。本回答被提问者采纳

elasticsearch系列java定义score

概述

ES支持groovy 和 java两种语言自定义score的计算方法,groovy甚至可以嵌套在请求的参数中,有点厉害,不过不在本篇讨论范围。

如何用自定义的java代码来定义score如何产生,这用到了ES的插件功能

关于es插件的相关操作,可以通过以下命令获得

./bin elasticsearch-plugn –h

 

操作步骤

1.增加配置

首先需要在ES的配置中增加以下,

旧版本是

script.disable_dynamic: false

 

目前用的ES是5.2.2,根据日志提示,改成如下,改完后需要重启ES

script.inline: true

script.stored: true

 

不得不说这个日志提供的信息真不错

 

 

如果不加这两条配置,则会这样这种错误

 

2.写java代码

//java代码格式参考

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

 

3.写配置文件

配置文件格式参考

https://github.com/elastic/elasticsearch/blob/master/buildSrc/src/main/resources/plugin-descriptor.properties

 

4.上传到ES集群

在$ELASTICSEARCH_HOME/plugins新建一个文件夹,这个文件夹的名称就是这个插件的名称,

例如有 三个文件夹

可以通过如下命令找到他们

 

在新建的文件夹中,导入jarplugin-descriptor.properties文件(必须有)

 

5.重启ES服务

kill -9 pid

nohup ./elasticsearch & 

 

6.使用

{

  "query": {

    "function_score": {

      "query": {

        "match": {

          "your_fields": "xxxx"

        }

      },

      "functions": [

        {

          "script_score": {

            "script": {

              "inline": "key",

              "lang": "native",

              "params": {

                "your_fields": "xxxxx"

              }

            }

          }

        }

      ]

    }

  }

}

 

 

key解释:

Key

解释

备注

inline

调用插件的key,和插件名称是两个东西

在NativeScriptFactory接口中的
getName()方法设置

lang

自定义方式

native意思是用java原生实现

 

 

//关于自定义function-script-score

https://www.elastic.co/guide/en/elasticsearch/reference/5.2/query-dsl-function-score-query.html#function-script-score

 

7.更新插件

由于ES集群会缓存插件代码,就算把插件删了依然可用,目前还是需要重启来更新插件

 

参考资料

//自定义java制作插件必要的步骤

https://www.elastic.co/guide/en/elasticsearch/plugins/5.2/plugin-authors.html#_plugin_structure

//github完整插件

https://github.com/momoxixi/elasticsearch-feature-vector-scoring

 

以上是关于如何使用Elasticsearch groovy script脚本更新数据的主要内容,如果未能解决你的问题,请参考以下文章

ElasticSearch:在禁用 Groovy 的 _score 字段上进行聚合

Elasticsearch 无法使用 lang groovy 运行内联脚本 [doc ....]

Elasticsearch自定义过滤插件实现复杂逻辑过滤

Elasticsearch的Groovy Script自定义评分检索

(37)ElasticSearch基于groovy脚本执行partial update

elasticsearch系列java定义score