Elasticsearch 8 中 Nested 数据类型的使用方法
Nested 数据类型的使用方法,包括完整的示例和最佳实践
1. Nested 数据类型简介
在 Elasticsearch 8 中,nested
类型用于处理对象数组,确保数组中的每个对象都能被独立索引和查询,解决了对象数组扁平化的问题。
为什么需要 Nested?
普通对象数组会被扁平化,失去对象内部字段的关联性
Nested 保持数组中每个对象的独立性
支持对嵌套对象进行精确查询和聚合
2. 创建包含 Nested 字段的索引
基本映射定义:
json
PUT /ecommerce_products {"mappings": {"properties": {"name": {"type": "text"},"description": {"type": "text"},"price": {"type": "float"},"variants": {"type": "nested", // 定义 nested 类型"properties": {"color": {"type": "keyword"},"size": {"type": "keyword"},"stock": {"type": "integer"},"price": {"type": "float"}}},"reviews": {"type": "nested", // 另一个 nested 字段示例"properties": {"user": {"type": "keyword"},"rating": {"type": "integer"},"comment": {"type": "text"},"created_at": {"type": "date"}}}}} }
3. 插入包含 Nested 数据的文档
json
POST /ecommerce_products/_doc/1 {"name": "Premium T-Shirt","description": "High quality cotton t-shirt","price": 29.99,"variants": [{"color": "red","size": "M","stock": 50,"price": 29.99},{"color": "blue","size": "L","stock": 25,"price": 29.99},{"color": "red","size": "S","stock": 0,"price": 29.99}],"reviews": [{"user": "user123","rating": 5,"comment": "Excellent quality!","created_at": "2023-10-01T10:00:00Z"},{"user": "user456","rating": 4,"comment": "Good but runs a bit large","created_at": "2023-10-02T14:30:00Z"}] }POST /ecommerce_products/_doc/2 {"name": "Denim Jeans","description": "Classic blue jeans","price": 59.99,"variants": [{"color": "blue","size": "32","stock": 15,"price": 59.99},{"color": "black","size": "34","stock": 8,"price": 59.99}],"reviews": [{"user": "user789","rating": 3,"comment": "Average quality","created_at": "2023-10-03T09:15:00Z"}] }
4. Nested 查询
4.1 基本 Nested 查询
json
GET /ecommerce_products/_search {"query": {"nested": {"path": "variants", // 指定 nested 字段路径"query": {"bool": {"must": [{"term": {"variants.color": "red"}},{"term": {"variants.size": "M"}}]}},"score_mode": "avg" // 评分模式:avg, max, min, sum, none}} }
4.2 多条件 Nested 查询
json
GET /ecommerce_products/_search {"query": {"bool": {"must": [{"match": {"name": "T-Shirt"}},{"nested": {"path": "variants","query": {"bool": {"must": [{"term": {"variants.color": "red"}},{"range": {"variants.stock": {"gt": 0}}}]}}}}]}} }
5. Nested 聚合
5.1 基本 Nested 聚合
json
GET /ecommerce_products/_search {"size": 0,"aggs": {"variants_agg": {"nested": {"path": "variants" // 必须先指定 nested 路径},"aggs": {"color_stats": {"terms": {"field": "variants.color"},"aggs": {"avg_stock": {"avg": {"field": "variants.stock"}}}}}}} }
5.2 多个 Nested 聚合
json
GET /ecommerce_products/_search {"size": 0,"aggs": {"variants_agg": {"nested": {"path": "variants"},"aggs": {"available_variants": {"filter": {"range": {"variants.stock": {"gt": 0}}},"aggs": {"by_color": {"terms": {"field": "variants.color"}}}}}},"reviews_agg": {"nested": {"path": "reviews"},"aggs": {"avg_rating": {"avg": {"field": "reviews.rating"}}}}} }
6. 反向嵌套聚合(Reverse Nested)
json
GET /ecommerce_products/_search {"size": 0,"aggs": {"variants_agg": {"nested": {"path": "variants"},"aggs": {"colors": {"terms": {"field": "variants.color"},"aggs": {"back_to_root": {"reverse_nested": {}, // 返回到根文档"aggs": {"avg_price": {"avg": {"field": "price"}}}}}}}}} }
7. Nested 排序
json
GET /ecommerce_products/_search {"query": {"nested": {"path": "variants","query": {"term": {"variants.color": "red"}}}},"sort": [{"variants.stock": {"order": "desc","nested": {"path": "variants","filter": {"term": {"variants.color": "red"}}}}}] }
8. 嵌套对象更新
8.1 使用脚本更新嵌套对象
json
POST /ecommerce_products/_update/1 {"script": {"source": """// 找到特定颜色的变体并更新库存for (int i = 0; i < ctx._source.variants.length; i++) {if (ctx._source.variants[i].color == params.color && ctx._source.variants[i].size == params.size) {ctx._source.variants[i].stock += params.quantity;}}""","params": {"color": "red","size": "M","quantity": 10},"lang": "painless"} }
8.2 添加新的嵌套对象
json
POST /ecommerce_products/_update/1 {"script": {"source": """// 添加新的变体ctx._source.variants.add(params.newVariant)""","params": {"newVariant": {"color": "green","size": "L","stock": 20,"price": 29.99}},"lang": "painless"} }
9. 性能优化和最佳实践
9.1 映射优化
json
PUT /optimized_products {"mappings": {"properties": {"variants": {"type": "nested","properties": {"color": {"type": "keyword","doc_values": true // 确保聚合性能},"size": {"type": "keyword"},"stock": {"type": "integer","index": false // 如果不查询,可以禁用索引}}}}} }
9.2 查询优化建议
限制 nested 字段数量:避免过多的 nested 字段
使用 filter 上下文:对不需要评分的查询使用 filter
合理使用 score_mode:根据需求选择合适的评分模式
监控性能:nested 查询和聚合可能比较消耗资源
10. 实际应用场景示例
场景:电商产品搜索和过滤
json
GET /ecommerce_products/_search {"query": {"bool": {"must": [{"match": {"name": "T-Shirt"}}],"filter": [{"nested": {"path": "variants","query": {"bool": {"must": [{"term": {"variants.color": "red"}},{"term": {"variants.size": "M"}},{"range": {"variants.stock": {"gt": 0}}}]}}}},{"nested": {"path": "reviews","query": {"range": {"reviews.rating": {"gte": 4}}}}}]}},"aggs": {"available_colors": {"nested": {"path": "variants"},"aggs": {"colors": {"filter": {"range": {"variants.stock": {"gt": 0}}},"aggs": {"color_count": {"terms": {"field": "variants.color"}}}}}}} }
11. 常见问题解决
问题1:nested 字段查询不到数据
检查:确保使用了 nested
查询而不是普通查询
问题2:聚合结果不正确
解决:确保在聚合前正确使用 nested
聚合包装
问题3:性能问题
优化:
限制 nested 数组的大小
对不需要查询的字段设置
"index": false
使用 filter 上下文减少评分计算
问题4:映射修改
注意:nested 字段的映射修改可能需要重建索引