Elasticsearch script入门

创建脚本

//语法:POST _script/名字
POST _script/calculate-discount
{
   "script":{
       "lang":"painless",
       "source":"doc['price'].value * params.discount"
  }
}

查看脚本

GET _script/calculate-discount

删除脚本

DELETE _script/calculate-discount

引用脚本

GET product/_search
{
   "script_fields":{
       "discount_price":{
           "script":{
               //这里不需要再指定source,而是直接指定对应上面存储了的脚本id名即可
               "id":"calculate-discount",
               "params":{
                   "discount":0.8
              }
          }
      }
  }
}

Painless简介

Painless可以对文档字段进行加工处理

更新或者删除字段,处理数据聚合操作

Script Field:对返回的字段提前进行计算

Function Score:对文档的分数进行处理

在Reindex API,Update By Query时,对数据进行处理

脚本编写的语言,默认为painless。

脚本本身可以指定为内联脚本的source或存储脚本的id

应传递给脚本的任何命名参数

Painless关键字

if  else  while  do  for  in  continue  break  return  new  try  catch  throw  this  instanceof

通过Painless脚本访问字段

Update ctx._source.field_name

Search&Aggregation doc['field_name']

可以将表达式脚本用于script_score、script_fields、排序脚本和数字聚合脚本,只需将lang参数设置为expression。

script脚本修改文档

修改文档时,通过ctx._source.fieldname来指定某个字段

POST pigg_test/_update/1
{
   "script":"ctx._source.age += 1"
}
指定integer类型的age为一个新值
POST pigg_test/_update/1
{
   "script":"ctx._source.age = 34"
}
另一种好用的方法
POST pigg_test/_update/1
{
   "script":"ctx._source.age = params.value",
   "params":{
       "value":34
  }
}
当要修改值时,只需修改params里的value值,不需要修改ctx._source.age = params.value这个脚本

指定数组添加一个值
POST pigg_test/_update/1
{
   "script":"ctx._source.age(params.value)",
   "params":{
       "value":"王冬"
  }
}
指定数组删除某个值
POST pigg_test/_update/1
{
   "script":{
       "source":"ctx._source.remove(ctx._source.name.indexOf(params.value))",
       "params":{
           "value":"王冬"
      }
  }
}
先判断是否存在,然后指定数组删除某个值
POST pigg_test/_update/1
{
   "script":{
       "source":"if(ctx._source.name.indexOf(params.value) >=0) ctx._source.name.remove(ctx._source.name.indexOf(params.value))",
       "params":{
           "value":"王冬"
      }
  }
}

字段直接复制值
POST pigg_test/_update/1
{
   "script":{
  "source":"ctx._source.new_name = ctx._source.name"
  }
}
但是这里得注意,这里也仅仅是复制值,不复制字段的mapping配置,如果不预先设置new_name的mapping配置,new_name还是会是ES的默认的text。

删除一个字段,不修改mapping
POST pigg_test/_update/1
{
   "script":"ctx._source.remove('new_name')"
}

获取字段值方法

Doc_values是一个列式字段值存储,默认情况下在除text字段外所有字段上启用。

如果text类型,用doc['fieldname'].value会报错

当text类型包含keyword子字段时,用doc['fieldname.keyword'].value就可以

doc['fieldname'].value         params['_source']['my_field']      

doc.fieldname.value

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

使用params关键字: 每次使用时都必须加载和解析_source, 这是非常缓慢的.
建议: 使用doc关键字, 从文档中访问相关字段的值, 这种方式更加高效

 

GET pigg_test/_search
{
   "script_fields":{
       "sum_score":{
           "script":{
               "lang":"painless",
               "source":"def sum = 0;sum = doc['chinese'].value + doc['match'].value + doc['english'].value; return sum;"
          }
      }
  }
}

GET pigg_test/_search
{
   "script_fields":{
       "new_address":{
           "script":{
               "source":"'地址是:' + doc['address.keyword'].value"
          }
      }
  }
}
如果text类型,用params._source.fieldname
GET pigg_test/_search
{
   "script_fields":{
       "new_address":{
           "script":{
               "source":"'地址是:' + params._source.address"
          }
      }
  }
}
用size()或length来获取数组的长度
GET pigg_test/_search
{
   "query":{
       "script":{
           "script":"doc['name'].size() ==3"
      }
  }
}
GET pigg_test/_search
{
   "query":{
       "script":{
           "script":"doc['name'].length == 3"
      }
  }
}
在聚合中使用script
GRT pigg_test/search
{
   "size":10,
   "aggs":{
       "name_total_count":{
           "sum":{
               "script":"doc['name'].size()"
          }
      }
  }
}

数字字段

doc['field_name'].value             字段的值,作为 double
doc['field_name'].empty             一个布尔值,指示该字段在文档中是否没有值
doc['field_name'].length            本文档中的值的数量
doc['field_name'].min()             本文档中字段的最小值
doc['field_name'].max()             本文档中字段的最大值
doc['field_name'].median()          本文档中字段的中值
doc['field_name'].avg()             本文档中值的平均值
doc['field_name'].sum()             本文档中的值的总和
当文档完全缺少该字段时,默认情况下该值将被视为0. 您可以将其视为另一个值,
例如doc['myfield'].empty ? 100 : doc['myfield'].value

 

日期字段

doc['field_name'].date.centuryOfEra          世纪 (1-2920000)
doc['field_name'].date.dayOfMonth            日 (1-31),例如1一个月的第一天
doc['field_name'].date.dayOfWeek             星期几 (1-7),例如1星期一
doc['field_name'].date.dayOfYear             一年中的某一天,例如11 1
doc['field_name'].date.era                   时代:0对于公元前,1对于公元
doc['field_name'].date.hourOfDay             小时 (0-23)
doc['field_name'].date.millisOfDay           一天内的毫秒数 (0-86399999)
doc['field_name'].date.millisOfSecond        秒内的毫秒 (0-999)
doc['field_name'].date.minuteOfDay           一天中的分钟 (0-1439)
doc['field_name'].date.minuteOfHour          小时内的分钟 (0-59)
doc['field_name'].date.monthOfYear           一年中的月份 (1-12),例如1一月
doc['field_name'].date.secondOfDay           一天内的第二个 (0-86399)
doc['field_name'].date.secondOfMinute        一分钟内的第二个 (0-59)
doc['field_name'].date.year                  年(-292000000 - 292000000
doc['field_name'].date.yearOfCentury         世纪内的年份 (1-100)
doc['field_name'].date.yearOfEra             时代内的年份(1-292000000

显示date字段 date0 date1 之间的年份差异
doc['date1'].date.year - doc['date0'].date.year

Geo_point字段

doc['field_name'].empty                      一个布尔值,指示该字段在文档中是否没有值。
doc['field_name'].lat                        地理点的纬度。
doc['field_name'].lon                        地理点的经度。

以下示例以公里为单位计算距华盛顿特区的距离:

haversin(38.9072, 77.0369, doc['field_name'].lat, doc['field_name'].lon)

在这个例子中,坐标可以作为参数传递给脚本,例如基于用户的地理位置。

 

脚本中的多行语句

ES是支持多行脚本编写的:只需要source后面的语句的开头和结尾都是三个引号,再两对三引号之间写下多行内容即可,语句和语句直接使用“;”结尾,和java差不多

POST product2/_update/1
{
"script":{
"lang":"painless",
"source":"""
ctx._source.name += params.name;
ctx._source.price -= 1
""",
"params":{
"name":"无线充电",
"price":"1"
}
}
}

 

script_score

允许用户在检索中灵活修改文档score,来实现自己干预结果排名的目的,另外script score性能要高于function score

GET /_search
{
"query":{
"script_score":{
"query":{
"match":{"message":"elasticsearch"}
},
"script":{
"source":"doc['my-int'].value / 10"
}
}
}
}

query:(必须,查询对象)用于返回文档的查询

script:(必须,脚本对象)用于计算query

查询的最终相关性script_score不能为负数。为了支持某些优搜索化,Lucene要求分数为正数或0

min_score:(可选,浮点数)得分低于此浮点数的文档将被排除在搜索结果之外

boost:(可选,浮点数)由产生的文档分数script乘以boost产生最终文档的分数。默认为1.0

在脚本中使用相关性分数:可以访问_score表示文档当前相关性分数的变量。

weight:允许您将分数乘以提供的weight,这有时可能是需要的,因为在特定查询上设置的提升至会被标准化,而对于这个评分函数却没有。数值的类型是浮点型

random:生成从0到1但不包括1均匀分布的random_score分数,默认情况下,它会使用内部Lucene文档ID作为随机源,这非常有效,但不幸的是不可重现,因为文档可能会通过合并重新编号。

field_value_factor:该功能允许您使用文档中的字段来影响分数。它类似于使用script_score函数,但是,他避免了编写脚本的开销。如果用于多值字段,则仅在计算中使用该字段的第一个值。

假设您有一个使用数字my-int字段索引的文档,并希望使用该字段影响文档的分数
GET /_search
{
"query":{
"function_score":{
"field_value_factor":{
"field":"my-int",
"factor":1.2,
"modifier":"sqrt",
"missing":1
}
}
}
}
这将转化为一下评分公式:sqrt(1.2 * doc['ny-int'].value)
该功能有许多选项field_value_factor:
field 要从文档中提取的字段。
factor 与字段值相乘的可选因子。默认为1
modifier 应用于字段的修饰符,可以使一下之一:none,log,log1p,log2p,ln,ln1p,ln2p,square,sqrt或reciprocal,默认为none。

衰减函数:使用一个函数对文档进行评分,该函数根据文档的数字字段值与用户给定原点的距离而衰减。这类似于范围查询,但边缘平滑而不是框。

要对具有数字字段的查询使用距离评分,用户必须为每个字段定义一个origin和一个scale。origin需要定义计算距离的中心点,以及定义scale衰减率,衰减函数指定为

"DECAY_FUNCTION":{ 应该是linear,exp或者gauss之一。
"FIELD_NAME":{ 指定的字段必须是数字,日期或地理点字段
"origin":"11,12",
"scale":"2km",
"offset":"0km",
"decay":0.33
}
}
gauss:正常衰减
exp:指数衰减
linear:线性衰减

 

 

 

预定义函数

Saturation
saturation(value,k) = value/(k + value)

"script":{
"source":"saturation(doc['my-int'].value,1)"
}

Sigmoid
si

 

 

 

script_fields

您可以使用改script_fields参数来检索每个命中的脚本评估(基于不同的字段)。

GET /_search
{
"query":{
"match_all":{}
},
"script_fields":{
"test1":{
"script":{
"lang":"painless",
"source":"doc['price'].value * 2"
}
},
"test2":{
"script":{
"lang":"painless",
"source":"doc['price'].value * params.factor",
"params":{
"factor":2.0
}
}
}
}
}

脚本字段可以处理未存储的字段(price在上述情况下),并允许脚本字段还可以访问实际_source文档并使用params['_source']

GET /_search
{
"query":{
"match_all":{}
},
"script_fields":{
"test1":{
"script":"params['_source']['message']"
}
}
 

__EOF__

本文作者dong
本文链接https://www.cnblogs.com/cxd424/p/15868183.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   dong栋  阅读(1264)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示