重生之我们在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"
}
相关推荐
筱源源2 小时前
Elasticsearch-linux环境部署
linux·elasticsearch
Elastic 中国社区官方博客13 小时前
释放专利力量:Patently 如何利用向量搜索和 NLP 简化协作
大数据·数据库·人工智能·elasticsearch·搜索引擎·自然语言处理
Shenqi Lotus19 小时前
ELK-ELK基本概念_ElasticSearch的配置
elk·elasticsearch
yeye1989122421 小时前
10-Query & Filtering 与多字符串多字段查询
elasticsearch
Narutolxy1 天前
精准优化Elasticsearch:磁盘空间管理与性能提升技巧20241106
大数据·elasticsearch·jenkins
谢小涛2 天前
ES管理工具Cerebro 0.8.5 Windows版本安装及启动
elasticsearch·es·cerebro
LKID体2 天前
Elasticsearch核心概念
大数据·elasticsearch·搜索引擎
晨欣2 天前
Elasticsearch里的索引index是什么概念?(ChatGPT回答)
大数据·elasticsearch·jenkins
许苑向上2 天前
最详细【Elasticsearch】Elasticsearch Java API + Spring Boot集成 实战入门(基础篇)
java·数据库·spring boot·elasticsearch
笔墨登场说说2 天前
git sonar maven 配置
大数据·elasticsearch·搜索引擎