【Elasticsearch】脚本(Script)
脚本
- 1.什么是 Elasticsearch 脚本
- 2.为什么需要有脚本
- 3.常用的脚本类型
- 4.Painless 脚本语言
- 5.实际案例
- 5.1 创建索引并插入产品数据
- 5.2 创建索引并插入销售数据
- 5.3 执行脚本
- 5.3.1 通过脚本:自定义字段(Script Fields)
- 5.3.2 通过脚本:排序(Script Sort)
- 5.3.3 通过脚本:更新字段(Update by Query)
- 5.3.4 条件查询(Conditional Script)
- 5.3.5 聚合
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/_countGET /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/_countGET /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 提供了强大的灵活性,使得在 不重新索引数据 的情况下实现复杂业务逻辑成为可能。