Elasticsearch 2.3.0 脚本篇

Elasticsearch的脚本模块可以使用脚本对Elasticsearch的字段进行再次处理。例如,可以用来重新评估查询的自定义得分,可以对索引中的某个字段再次加工处理。

脚本默认是关闭的,如果这个时候执行脚本会报以下错误:

{

"error": {

"root_cause": [

{

"type": "remote_transport_exception",

"reason": "[Left-Winger][127.0.0.1:9300][indices:data/write/update[s]]"

}],

"type": "illegal_argument_exception",

"reason": "failed to execute script",

"caused_by": {

"type": "script_exception",

"reason": "scripts of type [indexed], operation [update] and lang [groovy] are disabled"

}

},

"status": 400

}

可以通过配置来启用脚本引擎,配置的位置在elasticsearch.yml文件中添加如下内容:

script.inline: true

script.indexed: true

对这些设置,有三种配置值:

描述

false

完全禁用脚本

true

启用脚本

sandbox

脚本仅可以用沙盒语言执行

表格 8.7 细粒度动态脚本设置

默认配置值为:

script.inline: sandbox

script.indexed: sandbox

script.file: true

也可以在已下操作中执行脚本:

描述

aggs

聚合

search

搜索接口、过滤接口或建议接口(例如filters、script_fields)。

update

升级接口

plugin

通用plugin类别下,脚本使用的任何插件

插件也可以进行自定义操作,利用这种格式:${pluginName}_${operation}。例如在任何脚本引擎上禁用更新和映射:

script.update: false

script.mapping: false

也支持明确的脚本语言设置,需要script.engine.<engine>前缀,优先权高于其他通用设置:

script.engine.groovy.file.aggs: true

script.engine.groovy.file.mapping: true

script.engine.groovy.file.search: true

script.engine.groovy.file.update: true

script.engine.groovy.file.plugin: true

script.engine.groovy.indexed.aggs: true

script.engine.groovy.indexed.mapping: false

script.engine.groovy.indexed.search: true

script.engine.groovy.indexed.update: false

script.engine.groovy.indexed.plugin: false

script.engine.groovy.inline.aggs: true

script.engine.groovy.inline.mapping: false

script.engine.groovy.inline.search: false

script.engine.groovy.inline.update: false

script.engine.groovy.inline.plugin: false

 

系统的脚本模块默认使用groovy作为的脚本语言。可以通过设置script.default_lang可以进行修改。

可以用语言插件来支持不同的语言脚本。所以在使用脚本接口的参数中提供了lang参数定义脚本语言。

语言

沙盒

必要插件

groovy

内置

expression

内置

mustache

内置

javascript

elasticsearch-lang-javascript

python

elasticsearch-lang-python

为了增加安全性,Elasticsearch不允许在请求中指定非沙盒语言。默认的脚本目录位置可以在elasticsearch.yml中设置path.scripts进行修改。放置在这个目录中的脚本会自动选中并且可以被使用。一旦脚本被放在这个目录中,可以通过脚本名进行引用。

1.1.1 脚本使用

在Elasticsearch中使用脚本有三种方式:

1、直接在请求体中使用脚本。

2、把脚本存储在索引中,通过引用脚本id来使用。

3、把脚本存储在本地磁盘中,默认的位置为:elasticsearch\config\scripts,通过引用脚本名称进行使用。

下面通过举例来说明使用脚本的三种方法。

首先建一个索引,添加一条数据。

PUT localhost:9200/secisland/secilog/1

{

"eventCount":1,

"eventName" :"linux login event"

}

下面我们用脚本对eventCount做加法操作。

n 用第一种方法直接在请求中执行脚本:

http://127.0.0.1:9200/secisland/secilog/1/_update

{

    "script" : "ctx._source.eventCount+=count",

    "params" : {

        "count" : 4

    }

}

n 下面我们用第二种方法操作,在用第二种方法前,先要把脚本存储在Elasticsearch中:

POST 127.0.0.1:9200/_scripts/groovy/indexedCalculateCount 

{

     "script": "ctx._source.eventCount+=count"

}

然后通过脚本Id进行文档操作:

POST http://127.0.0.1:9200/secisland/secilog/1/_update

{

  "script": {

    "id": "indexedCalculateCount",

    "lang": "groovy",

    "params": {

      "count": 8

    }

  }

}

n 下面我们用第三种方法操作,在第三种方法操作前,先要把脚本存储在文件中,文件名为indexedCalculateCount.groovy,文件中的内容为:ctx._source.eventCount+=count。

注意:Elasticsearch对文件读取有个时间,刚建好后,不能生效,做验证的时候可以重启进行生效。

POST http://127.0.0.1:9200/secisland/secilog/1/_update/

{

  "script": {

    "file": "indexedCalculateCount",

    "lang": "groovy",

    "params": {

      "count": 8

    }

  }

}

1.1.2 脚本配置

A. 索引脚本

Elasticsearch可以在名为_scripts的内部索引中存储脚本,并且通过id进行引用。脚本请求的格式:/_scripts/{lang}/{id}

lang表示脚本语言,id表示脚本编号。

1. 保存脚本

POST localhost:9200/_scripts/groovy/indexedCalculateScore

{

     "script": "log(_score * 2) + my_modifier"

}

2. 使用脚本

POST localhost:9200/_search

{

  "query": {

    "function_score": {

      "query": {

        "match": {

          "body": "foo"

        }

      },

      "functions": [

        {

          "script_score": {

            "script": {

              "id": "indexedCalculateScore",

              "lang" : "groovy",

              "params": {

                "my_modifier": 8

              }

            }

          }

        }

      ]

    }

  }

}

3. 查看脚本

GET localhost:9200/_scripts/groovy/indexedCalculateScore

4. 删除脚本

DELETE localhost:9200/_scripts/groovy/indexedCalculateScore

B. 启用动态脚本

在应用或代理后面执行Elasticsearch,可以从外界保护Elasticsearch。如果允许用户运行内联脚本或索引脚本,会继承运行Elasticsearch的用户权限。因此动态脚本默认仅支持沙盒语言。

首先,应该使用root用户权限运行Elasticsearch,可以允许脚本在服务器上访问或做任何事情。其次,不应该让用户直接访问Elasticsearch,而是要有一个中间代理应用。如果确实想要用户直接访问Elasticsearch,需要决定是否足够信任用户来运行脚本。

C. 脚本自动重载

周期性扫描config/scripts目录的修改。新的和修改的脚本会被重载删除的脚本会从预加载脚本缓存中移除。重载频率可以使用resource.reload.interval设置指定,默认值为60s。设置script.auto_reload_enabled为false可以完全禁用脚本重载。

本文由赛克 蓝德(secisland)原创,转载请标明作者和出处。

D. 本地(Java)脚本

有时,groovy和expressions是不够的。在这种情况下,可以执行本地脚本。

执行本地脚本的最好方式是编写并且安装一个插件。

为了注册实际脚本,需要引用NativeScriptFactory来构成脚本。实际脚本需要继承AbstractExecutableScript或AbstractSearchScript。第二种可能是最有用的并且有多个可以继承的子类,比如AbstractLongSearchScript、AbstractDoubleSearchScript和AnstractFloatSearchScript。最后,插件需要通过onModule(ScriptModule)方法注册本地脚本。

public class MyNativeScriptPlugin extends Plugin {

    @Override

    public String name() {

        return "my-native-script";

    }

    @Override

    public String description() {

        return "my native script that does something great";

    }

    public void onModule(ScriptModule scriptModule) {

        scriptModule.registerScript("my_script", MyNativeScriptFactory.class);

    }

 

    public static class MyNativeScriptFactory implements NativeScriptFactory {

        @Override

        public ExecutableScript newScript(@Nullable Map<String, Object> params) {

            return new MyNativeScript();

        }

        @Override

        public boolean needsScores() {

            return false;

        }

    }

 

    public static class MyNativeScript extends AbstractFloatSearchScript {

        @Override

        public float runAsFloat() {

            float a = (float) source().get("a");

            float b = (float) source().get("b");

            return a * b;

        }

    }

}

可以执行脚本通过指定lang为native,指定inline为脚本名。

POST localhost:9200/_search

{

  "query": {

    "function_score": {

      "query": {

        "match": {

          "body": "foo"

        }

      },

      "functions": [

        {

          "script_score": {

            "script": {

                "inline": "my_script",

                "lang" : "native"

            }

          }

        }

      ]

    }

  }

}

E. Lucene表达式脚本

警告:Lucene表达式模块正经历重大的发展,展现的功能可能会被修改。

Lucene的表达式模块提供了一个机制来将Javascript表达式编译成字节码。表达式脚本可以用于script_score、script_fields、排序脚本和数字型聚合脚本。

表达式脚本变量可以接受:

l 单值文档字段,例如doc[‘myfield’].value,也可以写作doc[‘myfield’]。

l 传给脚本的参数,例如mymodifier。

l 当前文档的得分,_score(只有用在script_score的时候)。

表达式脚本日期类型可以使用这些方法:

l getYear()

l getMonth()

l getDayOfMonth()

l getHourOfDay()

l getMinutes()

l getSeconds()

比如,获取日期字段间年份的不同:

doc[‘date1’].getYear() – doc[‘date0’].getYear()

相对于其他脚本语言,有一些限制:

l 只接受数字型字段

l 保存的字段不可用

l 如果只有一部分文档包含字段值,缺失字段值的文档默认值为0。

F. 得分

聚合中所有可以使用的脚本,当前文档的得分可以用_score获得。

G. 文档字段

大多数脚本围绕指定文档字段数据的使用。doc[‘field_name’]可以用来访问文档内指定字段数据。注意,只能是简单值字段(不能返回Json对象)并且只有不分词字段或单索引词字段是有意义的。

可以从字段中获取下列数据:

表达式

描述

doc[‘field_name’].value

字段的本地值。

doc[‘field_name’].values

字段的本地数组值。如果字段没有值,返回一个空数组。

doc[‘field_name’].empty

布尔值,表示文档中的字段是否有值。

doc[‘field_name’].multiValued

布尔值,表示文集中有多个值的字段。

doc[‘field_name’].lat

地理点类型的纬度。

doc[‘field_name’].lon

地理点类型的经度。

doc[‘field_name’].lats

地理点类型的纬度(复数)。

doc[‘field_name’].lons

地理点类型的经度(复数)。

doc[‘field_name’].distance(lat,lon)

地理点字段和提供的经纬度之间的平面距离(米)。

doc[‘field_name’].distanceWithDefault(lat,lon,default)

地理点字段从提供的经纬度和默认值的平面距离(米)。

doc[‘field_name’].distanceInMiles(lat,lon)

地理点字段和提供的经纬度之间的平面距离(英里)。

doc[‘field_name’].distanceInMilesWithDefault(lat,lon,default)

地理点字段从提供的经纬度和默认值的平面距离(英里)。

doc[‘field_name’].distanceInKm(lat,lon)

地理点字段和提供的经纬度之间的平面距离(千米)。

doc[‘field_name’].distanceInkmWithDefault(lat,lon,default)

地理点字段从提供的经纬度和默认值的平面距离(千米)。

doc[‘field_name’].arcDistance(lat,lon)

地理点字段和提供的经纬度之间的天穹距离(米)。

doc[‘field_name’].arcDistanceWithDefault(lat,lon,default)

地理点字段从提供的经纬度和默认值的天穹距离(米)。

doc[‘field_name’].arcDistanceInMiles(lat,lon)

地理点字段和提供的经纬度之间的天穹距离(英里)。

doc[‘field_name’].arcDistanceInMilesWithDefault(lat,lon,default)

地理点字段从提供的经纬度和默认值的天穹距离(英里)。

doc[‘field_name’].arcDistanceInKm(lat,lon)

地理点字段和提供的经纬度之间的天穹距离(千米)。

doc[‘field_name’].arcDistanceInKmWithDefault(lat,lon,default)

地理点字段从提供的经纬度和默认值的天穹距离(千米)。

doc[‘field_name’].factorDistance(lat,lon)

地理点字段从提供的经纬度之间的距离因子。

doc[‘field_name’].factorDistance(lat,lon,default)

地理点字段从提供的经纬度和默认值的距离因子。

doc[‘field_name’].geohashDistance(geohash)

地理点字段从提供的地理散列的天穹距离(米)。

doc[‘field_name’].geohashDistanceInKm(geohash)

地理点字段从提供的地理散列的天穹距离(千米)。

doc[‘field_name’].geohashDistanceInMiles(geohash)

地理点字段从提供的地理散列的天穹距离(英里)。

表格 8.9 脚本提取数据

H. 保存的字段

执行脚本的时候,保存的字段也可以访问。通过使用_fields[‘my_field_name’].value或_fields[‘my_field_name’].values。

I. 在脚本中访问文档的得分

当使用脚本计算文档得分(例如,通过function_score查询),可以在groovy脚本中使用_score变量访问得分。

J. 源字段

当执行脚本的时候,可以访问源字段。每个文档都会加载源字段、分析并且提供给脚本进行评估。使用方式,形如_source.obj1.obj2.field3。

K. Groovy内置方法

方法

描述

sin(a)

返回角度的三角正弦

cos(a)

返回角度的三角余弦

tan(a)

返回角度的三角正切

asin(a)

返回反正弦值

acos(a)

返回反余弦值

atan(a)

返回反正切值

toRadians(angdeg)

转换角度度量近似为弧度

toDegrees(angrad)

转换弧度度量近似为角度

exp(a)

返回欧拉数e的指数值

log(a)

返回值的自然对数(基于e)

log10(a)

返回值基于10的对数

sqrt(a)

返回值的平方根

cbrt(a)

返回双精度值的立方根

IEEEremainder(f1,f2)

进行余数运算

ceil(a)

向下取整

floor(a)

向上取整

rint(a)

取整

atan2(y,x)

转换直角坐标(x,y)到极坐标(r,θ),返回θ值

pow(a,b)

返回ab

round(a)

取整

random()

返回随机双精度数

abs(a)

返回值的绝对值

max(a,b)

返回大值

min(a,b)

返回小值

ulp(d)

返回参数的ulp的大小

signum(d)

返回自变量的符号函数

sinh(x)

返回值的双曲正弦值

cosh(x)

返回值的双曲余弦值

tanh(x)

返回值的双曲切线

hypot(x,y)

返回sqrt(x2+y2)

赛克蓝德(secisland)后续会逐步对Elasticsearch的最新版本的各项功能进行分析,近请期待。

转载于:https://my.oschina.net/secisland/blog/683518

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值