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

文章目录

      • [0. 前言](#0. 前言)
      • [1. 基本使用](#1. 基本使用)
      • [2. 读请求中访问文档字段](#2. 读请求中访问文档字段)
        • [2.1 遍历 List](#2.1 遍历 List)
        • [2.2 判断对象存不存在](#2.2 判断对象存不存在)
        • [2.3 判断值是否为空](#2.3 判断值是否为空)
        • [2.4 总结](#2.4 总结)
      • [3. 写请求中访问文档字段](#3. 写请求中访问文档字段)
        • [3.1 数字相加](#3.1 数字相加)
        • [3.2 字符串相加](#3.2 字符串相加)
        • [3.3 将字符串转为数组](#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"
}
相关推荐
Mephisto.java3 小时前
【大数据学习 | Spark】Spark的改变分区的算子
大数据·elasticsearch·oracle·spark·kafka·memcache
mqiqe3 小时前
Elasticsearch 分词器
python·elasticsearch
小马爱打代码3 小时前
Elasticsearch简介与实操
大数据·elasticsearch·搜索引擎
java1234_小锋12 小时前
Elasticsearch是如何实现Master选举的?
大数据·elasticsearch·搜索引擎
梦幻通灵18 小时前
ES分词环境实战
大数据·elasticsearch·搜索引擎
Elastic 中国社区官方博客18 小时前
Elasticsearch 中的热点以及如何使用 AutoOps 解决它们
大数据·运维·elasticsearch·搜索引擎·全文检索
小黑屋说YYDS1 天前
ElasticSearch7.x入门教程之索引概念和基础操作(三)
elasticsearch
Java 第一深情1 天前
Linux上安装单机版ElasticSearch6.8.1
linux·elasticsearch·全文检索
KevinAha2 天前
Elasticsearch 6.8 分析器
elasticsearch
wuxingge2 天前
elasticsearch7.10.2集群部署带认证
运维·elasticsearch