首页 > 其他分享 >ES脚本使用

ES脚本使用

时间:2024-10-20 14:25:15浏览次数:5  
标签:脚本 index expireDate script doc 使用 id ES

简要介绍

有时候需要一些复杂逻辑时,就需要用到ES提供的脚本,可以在字段、自定义分数、排序等场景下使用。

ES默认的脚本叫做painless

在支持脚本的ES API中,基本都循序以下的语法格式

"script": {
    "lang": "...",
    "source" | "id": "...",
    "params": {
         "name": "zhangsan",
         "age": 20
    }
}
  • lang:脚本语言,默认为painless

  • source: 脚本本身

  • id: 脚本id, 可以引用一段脚本

  • params: 脚本参数,支持传递字符串、数字参数,类型是一个Map。若脚步中需要参数,尽量不要硬编码到脚本中,因为脚本会进行编译,通过参数传递给脚本仅仅只需要编译一次,而参数不一样硬编码到脚本中,脚本内容会不一样,导致需要编译多次。

特别的,source在控制台书写时支持多行字符串语法,需要使用"""开头,与Java的多行字符串语法类似。

"source": """
  // 脚本
"""

painless简要介绍

它的语法基本和Java类似,可以使用大多数Java提供的标准类库,区别是不需要导包。

脚本官方文档

painless官方文档

Shared API为所有场景下都可以使用的API,其它API需要看上下文场景使用。Shared API已经提供了Java中最常用的几个包的标准类库了

  • java.lang
  • java.math
  • java.text
  • java.time
  • java.util

等等,可参见Shared API

所有的上下文

比如在排序场景中使用,则找Sort Context

会标明哪些API可以使用,以及语法示例。

内置的doc变量

在大多数上下文场景中,都会提供一个Map类型的内置doc变量,它包含了当前文档的所有字段。

painless为访问Map的值提供了简便语法,无序调用get方法,形如map['key']。

获取字段值

// 单个值的类型
def value = doc['fieldname'].value;
// 多个值的类型(数组), 使用doc['fieldname'].value只会返回第一个值
def value = doc['fieldname'].get(index);

判断该字段是否有值

// size方法返回值的个数,单值类型存在值则为1, 注意值为null是判定为没有值的
if (doc['fieldname'].size() > 0) {
    // doSomething
}

注:

  • 如果没有该字段,使用doc['fieldname'].value会抛异常
  • 不是所有字段类型都可以使用doc变量来获取,这个需要看对应上下文中的文档描述

ES字段类型对应的Java类型,如下面表格所示。

ES字段类型 简单类型 包装类型
boolean boolean Boolean
keyword String String
wildcard String String
long long Long
integer long Long
short long Long
byte long Long
double double Double
scaled_float double Double
half_float double Double
unsigned_long long Long
date ZonedDateTime ZonedDateTime

详情可参考此链接

排序案例

比如实现这么一个逻辑,索引中存在一个日期字段,排序规则如下

若大于等于当前日期,距离当前日期越近的排在前面,即这部分日期升序。

若小于等于当前日期,距离当前日期越近的也排在前面,但是优先级要次于上面大于等于当前日期的数据。

日期字段不存在的排最后面。

总结就是:未到期的升序排,已过期的降序排,未到期的优先于已过期的,值不存在的优先级最低。

索引

PUT /es_script_index
{
  "mappings": {
    "dynamic": "strict",
    "properties": {
      "id": {
        "type": "long"
      },
      "name": {
        "type": "text"
      },
      "expireDate": {
        "type": "date",
        "format": "yyyy-MM-dd"
      }
    }
  }
}

数据

POST /es_script_index/_bulk
{"index": {"_id": 1}}
{"id": 1, "expireDate": "2024-10-20"}
{"index": {"_id": 2}}
{"id": 2, "expireDate": "2024-10-22"}
{"index": {"_id": 3}}
{"id": 3, "expireDate": "2024-10-18"}
{"index": {"_id": 4}}
{"id": 4, "expireDate": "2024-10-19"}
{"index": {"_id": 5}}
{"id": 5, "expireDate": "2024-10-21"}
{"index": {"_id": 6}}
{"id": 6, "expireDate": null}
{"index": {"_id": 7}}
{"id": 7, "expireDate": "2024-10-17"}
{"index": {"_id": 8}}
{"id": 8}

排序DSL

GET /es_script_index/_search
{
  "from": 0,
  "size": 20,
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "_script": {
        "type": "number",
        "order": "desc",
        "script": {
          "source": """
            if (doc['expireDate'].size() > 0) {
              // doc['expireDate'].value为ZonedDateTime
              LocalDate expireDate = doc['expireDate'].value.toLocalDate();
              LocalDate currentDate = LocalDate.parse(params['currentDateStr']);
              // 已过期的返回之间的天数
              if (expireDate.isBefore(currentDate)) {
                return ChronoUnit.DAYS.between(currentDate, expireDate);
              }
              // 未过期的,先计算天数,然后再用一个很大的值减掉,这样越近的数值就会越大
              return Integer.MAX_VALUE - ChronoUnit.DAYS.between(currentDate, expireDate);
            }
            // 不存在返回最小值, 优先级最低
            return Integer.MIN_VALUE;
          """,
          "params": {
            "currentDateStr": "2024-10-20"
          }
        }
      }
    },
    {
      "id": "desc"
    }
  ]
}

解释:

type:值为number或者string,对应脚本的返回值类型为double或者String

order:asc/desc

字段案例

索引结构和数据同上

GET /es_script_index/_search
{
  "query": {
    "match_all": {}
  },
  "fields": ["*"], 
  "script_fields": {
    "diffDays": {
      "script": {
        "source": """
          if (doc['expireDate'].size() > 0) {
            // doc['expireDate'].value为ZonedDateTime
            LocalDate expireDate = doc['expireDate'].value.toLocalDate();
            LocalDate currentDate = LocalDate.parse(params['currentDateStr']);
            // 已过期的返回之间的天数
            if (expireDate.isBefore(currentDate)) {
              return ChronoUnit.DAYS.between(currentDate, expireDate);
            }
            // 未过期的,先计算天数,然后再用Long的最大值减掉,这样越近的数值就会越大
            return Integer.MAX_VALUE - ChronoUnit.DAYS.between(currentDate, expireDate);
          }
          // 不存在返回最小值, 优先级最低
          return Integer.MIN_VALUE;
        """,
        "params": {
          "currentDateStr": "2024-10-20"
        }
      }
    }
  }
}

注意:动态构造的script_fields无法使用于排序中。

标签:脚本,index,expireDate,script,doc,使用,id,ES
From: https://www.cnblogs.com/wt20/p/18487229

相关文章

  • Nuxt.js 应用中的 app:templatesGenerated 事件钩子详解
    title:Nuxt.js应用中的app:templatesGenerated事件钩子详解date:2024/10/19updated:2024/10/19author:cmdragonexcerpt:app:templatesGenerated是Nuxt.js的一个生命周期钩子,在模板编译到虚拟文件系统(VirtualFileSystem,VFS)之后被调用。这个钩子允许开发......
  • Nuxt.js 应用中的 app:templates 事件钩子详解
    title:Nuxt.js应用中的app:templates事件钩子详解date:2024/10/18updated:2024/10/18author:cmdragonexcerpt:app:templates是Nuxt.js中一个强大的生命周期钩子,它在NuxtApp生成过程中调用。这一钩子允许开发者自定义、修改或添加新文件到构建目录,提供了......
  • DreamMesh4D: Video-to-4D Generation with Sparse-Controlled Gaussian-Mesh HybridR
    目录一、概述二、前置知识1、分数蒸馏采样 2、LBS 3、DQS4、EucDist和GeoDist算法三、相关工作1、三维生成2、4D表示3、4D生成四、DreamMesh4D1、静态阶段 2、动态阶段-可变形图建立 3、动态阶段--自适应可变蒙皮算法 一、概述    该论文提出了......
  • 【Docker项目实战】使用Docker部署HumHub社交网络平台
    【Docker项目实战】使用Docker部署HumHub社交网络平台一、HumHub介绍1.1HumHub简介1.2HumHub特点1.3主要使用场景二、本次实践规划2.1本地环境规划2.2本次实践介绍三、本地环境检查3.1检查Docker服务状态3.2检查Docker版本3.3检查dockerco......
  • PyCharm2023版本之后使用本地conda已存在环境的步骤方法
    2023新版本的pycharm在创建新项目并导入本地conda环境时与以往版本稍有不同,具体步骤如下:1、在新建项目窗口点击Previouslyconfiguredinterpreter 2、点击右侧蓝色AddInterpreter后点击AddLocalInterpreter进入本地环境选择窗口 点击后进入如下界面 3、之后点击Co......
  • Android开发 registerForActivityResult 传值和申请动态权限
    前言  startActivityForResult()被弃用,现在可以通过registerForActivityResult进行Activity之间的传值和获取申请动态权限结果Activity向上传值MainActivitypackagecom.zh.demoimportandroid.content.Intentimportandroid.os.Bundleimportandroid.util.Logimport......
  • Springboot计算机毕业设计erpmes集成系统934a5
    Springboot计算机毕业设计erp本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表项目功能:部门,员工,产品分类,产品信息,入库登记,供应商,客户信息,出库登记,销售订单,采购订单开题报告内容一、课题背景与意义......
  • PBOOTCMS的水印功能如何使用?pbootcms设置的水印为何没生效?
    如果您希望为已有的图片添加水印,需要手动处理。以下是详细的操作步骤:开启水印功能进入后台管理:登录PBootCMS后台管理系统。进入系统设置:导航到“系统设置”>“基本设置”。启用水印功能:在“基本设置”页面中找到“水印设置”部分。勾选“启用水印”选项。......
  • PbootCMS附件上传失败报错UNKNOW: Code: 8192; Desc: stripos(): Non-string needles
    PbootCMS附件上传失败报错“UNKNOW:Code:8192;Desc:stripos():Non-stringneedleswillbeinterpretedasstringsinthefuture.”是由于PHP版本更新导致的兼容性问题。具体来说,stripos()函数在处理非字符串类型的第二个参数(即needle)时,未来版本的PHP将会将其视为字符串,而......
  • 使用 C++ 实现验证码识别与自动化登录
    安装所需依赖确保你已经安装以下库:libcurl:用于发送HTTP请求。OpenCV:用于图像处理。Tesseract:用于OCR识别。在Ubuntu系统中,你可以使用以下命令安装这些依赖:bashsudoapt-getinstalllibcurl4-openssl-devsudoapt-getinstalllibopencv-devsudoapt-getinstall......