当前位置: 首页 > article >正文

重生之我们在ES顶端相遇第 18 章 - Script 使用(进阶)

文章目录

      • 0. 前言
      • 1. 基本使用
      • 2. 读请求中访问文档字段
        • 2.1 遍历 List
        • 2.2 判断对象存不存在
        • 2.3 判断值是否为空
        • 2.4 总结
      • 3. 写请求中访问文档字段
        • 3.1 数字相加
        • 3.2 字符串相加
        • 3.3 将字符串转为数组

0. 前言

在前面部分,我们介绍了 ES 的基本使用和要掌握的基础性读写原理。
从本章开始,会开始介绍 ES 进阶使用。
本章要介绍的内容是 Script 的基本使用。
在日常开发中,读请求很少会用,写请求会使用比较多。
在读请求、写请求中,Script 访问文档值的方式有所不同,下面我将对 Script 在读写请求中使用进行介绍。

1. 基本使用

我们来看一个修改算分的例子。

写入文档

PUT test_18/_doc/1
{
  "counter": 1,
  "tags": ["red"],
  "scores": [1,2,3,4,5]
}

查询时,修改算分

GET test_18/_search
{
  "query": {
    "script_score": {
      "query": {
        "term": {
            "tags": "red"
        }
      },
      "script": {
        "lang": "painless",
        "source": "Math.log(_score * 2) + params['my_modifier'] * doc['counter'].value",
        "params": {
          "my_modifier": 2
        }
      }
    }
  }
}

script_score 是 ES 用于修改算分的查询,当然这不是我们的重点。

script 中包含 3 个属性

  • lang: 默认为 painless,非必填
  • source: 脚本,必填
  • params: 传递给脚本的参数,没有定义参数时,不用填

可以看到,在 Script 中我们可以使用 JAVA Api, 可以访问自定义的参数, 可以访问 ES 文档字段值。

2. 读请求中访问文档字段

painless script language 其实跟 JAVA 语法大相径庭。你可以简单认为就是在写 JAVA 代码。

在读请求中,ES 将文档映射为名为 doc 的 map。可以通过 doc['字段名'] 访问对应字段的对象。

2.1 遍历 List
GET test_18/_search
{
  "query": {
      "script_score": {
        "query": {
          "match_all": {}
        },
        "script": {
          "lang": "painless",
          "source": """
            int total = 0;
            for (int i = 0; i < doc['scores'].length; ++i) {
              total += doc['scores'][i];
            }
            return total;
          """
        }
      }
    }
}

代码解释

  • doc['scores'] 获取到文档对象,即 scores 字段
  • .lengthJAVA 数组的方法
  • doc['socere'][i] 访问数组中具体的值

script 中不允许访问 text 字段

GET test_18/_search
{
  "query": {
    "function_score": {
      "script_score": {
        "script": {
          "lang": "painless",
          "source": """
            int total = 0;
            for (int i = 0; i < doc['tags.keyword'].length; ++i) {
              total += doc['counter'].value;
            }
            return total;
          """
        }
      }
    }
  }
}

代码解释

  • doc['tags.keyword'],拿到 tags.keyword 对象。需要特别注意,这里不能使用 doc['tags']因为 ES 在 script 中不允许访问 text 字段
  • doc['counter'],获取 counter 对象。.value 获取 counter 对象的值
2.2 判断对象存不存在

doc.containsKey['field']

GET test_18/_search
{
  "query": {
    "script_score": {
      "query": {
        "match_all": {}
      },
      "script": {
        "lang": "painless",
        "source": """
          int total = 0;
          if (doc.containsKey('goals')) {
            return doc['goals'].value;
          } else {
            return (int)_score;
          }
        """
      }
    }
  }
}

代码解释

  • doc.containsKey('goals'): 判断是否包含 goals key。之前我们说过的。文档会被映射为一个 map。因此 doc 具备 map 的函数。
  • return (int)_score: _scorescript_score 中是一个特殊字段。(int) 是类型强转,和 JAVA 语法一致
2.3 判断值是否为空

doc['field'].size()

GET test_18/_search
{
  "query": {
    "script_score": {
      "query": {
        "match_all": {}
      },
      "script": {
        "lang": "painless",
        "source": """
          int total = 0;
          if (doc['counter'].size() == 0) {
            return 3;
          } else {
            return 2;
          }
        """
      }
    }
  }
}

代码解释

  • doc['counter'].size() 获取 counter 对象长度
2.4 总结
  1. 读请求中,可以使用 doc['字段名'] 访问对应字段的对象
  2. script 读请求中,无法访问 text 字段
  3. painless 语法与 JAVA 语法类似
  4. 关于 painless 更多可阅读 ES painless 官网
  5. painless 中可以使用哪些 API,可以参考 painless 支持的 API 文档

3. 写请求中访问文档字段

在写请求中使用脚本,我们大部分情况下是结合 Ingest Pipeline 一起使用。
Ingest pipeline 中,通过 ctx.xxx 就可以访问到文档字段。

注:Ingest pipeline:可以在文档写入前对文档进行预处理。

下面,我们来看几个例子

3.1 数字相加

将 math_score + verbal_score 赋值给 total_score

创建索引

PUT test_18_write_01
{
  "mappings": {
    "properties": {
      "math_score": {
        "type": "integer"
      },
      "verbal_score": {
        "type": "integer"
      },
      "total_score": {
        "type": "integer"
      }
    }
  }
}

创建 ingest pipeline

PUT _ingest/pipeline/test_18_write_01_pipeline
{
  "description": "Calculates the total test score",
  "processors": [
    {
      "script": {
        "source": "ctx.total_score = (ctx.math_score + ctx.verbal_score)"
      }
    }
  ]
}

写入时,指定 pipeline

PUT test_18_write_01/_doc/1?pipeline=test_18_write_01_pipeline
{
  "math_score": 99,
  "verbal_score": 89
}

查看结果

GET test_18_write_01/_search

在这里插入图片描述

已经为我们自动写入了 total_score

3.2 字符串相加

将 lastName、firstName 相加,赋值给 fullName

创建 ingest pipeline

PUT _ingest/pipeline/test_18_write_02_pipeline
{
  "description": "String concatenation test",
  "processors": [
    {
      "script": {
        "source": """
          if (ctx.containsKey('lastName') && ctx.containsKey('firstName')) {
            ctx.fullName = ctx.lastName + ' ' + ctx.firstName;
          }
        """
      }
    }
  ]
}

写入文档,并指定 pipeline

PUT test_18_write_02/_doc/1?pipeline=test_18_write_02_pipeline
{
  "firstName": "hello",
  "lastName": "elasticsearch"
}
3.3 将字符串转为数组

将 name 转换为数组,并赋值给 names

创建 pipeline

PUT _ingest/pipeline/test_18_write_03_pipeline
{
   "description": "string to array",
   "processors": [
      {
        "script": {
          "source": """
            ctx.names = ctx.name.splitOnToken(',')
          """
        }
      }
    ]
}

写入数据,并指定 pipeline

PUT test_18_write_03/_doc/1?pipeline=test_18_write_03_pipeline
{
  "name": "hello,elasticsearch"
}

http://www.kler.cn/news/330338.html

相关文章:

  • 【系统架构设计师】专题:测试基础知识
  • 力扣题解1870
  • [Linux#57][HTTP] URL结构 | 原理 | 请求与响应 | postman | fiddler
  • 活动公司都是怎么去寻找客户的
  • MySQL--数据库约束(详解)
  • Eclipse 快捷键:提高开发效率的利器
  • 计算机网络:计算机网络体系结构 —— 专用术语总结
  • Spring Boot+VUE《班级综合测评管理系统》
  • 无人机之视觉导航算法篇
  • CSS | 响应式布局之媒体查询(media-query)详解
  • 使用 vite 快速初始化 shadcn-vue 项目
  • 初步认识产品经理
  • 基于Spring Boot的IT互动平台解决方案
  • 第三弹:C++ 中的友元机制与运算符重载详解
  • Laravel Admin 中的 “Array to String Conversion“ 问题及其解决方法
  • 本地化测试对游戏漏洞修复的影响
  • 云原生(四十一)| 阿里云ECS服务器介绍
  • MongoDB 的基本使用
  • 【C++】树形结构的关联式容器:set、map、multiset、multimap的使用
  • Jenkins的安装