【Elasticsearch】脚本(Script)

发布于:2025-06-22 ⋅ 阅读:(21) ⋅ 点赞:(0)

1.什么是 Elasticsearch 脚本

Elasticsearch 脚本Script)是一种在 查询聚合更新文档 时执行自定义逻辑的方式。它允许用户在查询时动态计算值、修改文档或实现复杂的业务逻辑,而无需预先处理数据。

2.为什么需要有脚本

脚本在 Elasticsearch 中有几个重要用途:

  • 动态计算:在 查询时 计算字段值,而不是 索引时
  • 复杂逻辑:实现简单的 if-else、循环等编程结构。
  • 字段转换:将存储的字段转换为查询所需的格式。
  • 自定义评分:实现更复杂的相关性评分算法。
  • 批量更新:基于条件或计算更新多个文档。

3.常用的脚本类型

Elasticsearch 支持多种脚本语言,最常用的包括:

  • Painless:Elasticsearch 默认的安全脚本语言(推荐使用)。
  • Expression:简单的表达式语言,性能较好但功能有限。
  • Mustache:主要用于模板。
  • Java:直接使用 Java 代码(高权限,不推荐)。

4.Painless 脚本语言

Painless 是 Elasticsearch 专门设计的脚本语言,具有以下特点:

  • 安全:限制了可能有害的操作。
  • 高性能:编译执行,接近原生性能。
  • 简单易用:语法类似 Java / JavaScript。
  • 强类型:支持类型检查。
  • 内置 Elasticsearch API:可以直接访问文档字段和特殊变量。

5.实际案例

5.1 创建索引并插入产品数据

创建 products 索引。

PUT /products
{
  "mappings": {
    "properties": {
      "name": { "type": "text" },
      "category": { "type": "keyword" },
      "price": { "type": "double" },
      "quantity": { "type": "integer" },
      "is_premium": { "type": "boolean" }
    }
  }
}

插入测试数据。

POST /products/_bulk
{"index":{}}
{"name":"4K Smart TV","category":"electronics","price":899.99,"quantity":50,"is_premium":true}
{"index":{}}
{"name":"Wireless Headphones","category":"electronics","price":199.99,"quantity":120,"is_premium":false}
{"index":{}}
{"name":"Laptop","category":"electronics","price":1299.99,"quantity":30,"is_premium":true}
{"index":{}}
{"name":"Coffee Maker","category":"home","price":79.99,"quantity":200,"is_premium":false}
{"index":{}}
{"name":"Blender","category":"home","price":49.99,"quantity":150,"is_premium":false}
{"index":{}}
{"name":"Smartphone","category":"electronics","price":699.99,"quantity":80,"is_premium":true}
{"index":{}}
{"name":"Desk Chair","category":"office","price":149.99,"quantity":75,"is_premium":false}
{"index":{}}
{"name":"Monitor","category":"electronics","price":249.99,"quantity":60,"is_premium":false}

在这里插入图片描述

查询验证。

GET /products/_count

GET /products/_search
{
  "query": { "match_all": {} },
  "size": 5
}

在这里插入图片描述

5.2 创建索引并插入销售数据

创建 sales 索引。

PUT /sales
{
  "mappings": {
    "properties": {
      "product_id": { "type": "keyword" },
      "product_name": { "type": "text" },
      "quantity": { "type": "integer" },
      "unit_price": { "type": "double" },
      "is_premium": { "type": "boolean" },
      "sale_date": { "type": "date" }
    }
  }
}

插入测试数据。

POST /sales/_bulk
{"index":{}}
{"product_id":"P1001","product_name":"4K Smart TV","quantity":2,"unit_price":899.99,"is_premium":true,"sale_date":"2023-01-15"}
{"index":{}}
{"product_id":"P1002","product_name":"Wireless Headphones","quantity":5,"unit_price":199.99,"is_premium":false,"sale_date":"2023-01-16"}
{"index":{}}
{"product_id":"P1003","product_name":"Laptop","quantity":1,"unit_price":1299.99,"is_premium":true,"sale_date":"2023-01-17"}
{"index":{}}
{"product_id":"P1004","product_name":"Coffee Maker","quantity":3,"unit_price":79.99,"is_premium":false,"sale_date":"2023-01-18"}
{"index":{}}
{"product_id":"P1005","product_name":"Blender","quantity":2,"unit_price":49.99,"is_premium":false,"sale_date":"2023-01-19"}
{"index":{}}
{"product_id":"P1006","product_name":"Smartphone","quantity":4,"unit_price":699.99,"is_premium":true,"sale_date":"2023-01-20"}
{"index":{}}
{"product_id":"P1007","product_name":"Desk Chair","quantity":1,"unit_price":149.99,"is_premium":false,"sale_date":"2023-01-21"}
{"index":{}}
{"product_id":"P1008","product_name":"Monitor","quantity":2,"unit_price":249.99,"is_premium":false,"sale_date":"2023-01-22"}

在这里插入图片描述

查询验证。

GET /sales/_count

GET /sales/_search
{
  "query": { "match_all": {} },
  "size": 5
}

在这里插入图片描述

5.3 执行脚本

5.3.1 通过脚本:自定义字段(Script Fields)

GET /products/_search
{
  "query": { "match_all": {} },
  "script_fields": {
    "discounted_price": {
      "script": {
        "source": "doc['price'].value * 0.9"
      }
    }
  }
}

在这里插入图片描述

5.3.2 通过脚本:排序(Script Sort)

GET /products/_search
{
  "query": { "match_all": {} },
  "sort": {
    "_script": {
      "type": "number",
      "script": {
        "source": "doc['price'].value * params.discount",
        "params": {
          "discount": 0.8
        }
      },
      "order": "asc"
    }
  }
}

在这里插入图片描述

5.3.3 通过脚本:更新字段(Update by Query)

POST /products/_update_by_query
{
  "script": {
    "source": "ctx._source.price *= params.discount",
    "params": {
      "discount": 0.9
    }
  },
  "query": {
    "range": {
      "price": { "gte": 100 }  
    }
  }
}

在这里插入图片描述

只更新价格 ≥100 的商品。

  • gte 操作符:表示 greater than or equal to)。
  • 其他常用操作符
    • gt:大于(>
    • lte:小于或等于(
    • lt:小于(<

5.3.4 条件查询(Conditional Script)

GET /products/_search
{
  "query": {
    "bool": {
      "filter": {
        "script": {
          "script": {
            "source": """
              def category = doc['category'].value;
              def price = doc['price'].value;
              return category == 'electronics' && price > 500 && price < 1000;
            """
          }
        }
      }
    }
  }
}

在这里插入图片描述

5.3.5 聚合

计算销售记录的总金额,并根据是否为 Premium(高级/优质) 商品进行额外加成。

GET /sales/_search
{
  "aggs": {
    "total_sales": {
      "sum": {
        "script": {
          "source": """
            def total = doc['quantity'].value * doc['unit_price'].value;
            if (doc['is_premium'].value) {
              total *= 1.1; // 10% premium
            }
            return total;
          """
        }
      }
    }
  }
}

在这里插入图片描述

Painless 脚本为 Elasticsearch 提供了强大的灵活性,使得在 不重新索引数据 的情况下实现复杂业务逻辑成为可能。


网站公告

今日签到

点亮在社区的每一天
去签到