ElasticSearch嵌套对象数组索引的分类统计查询及结构优化问询
索引结构设计
核心设计目标是兼顾时间过滤效率、聚合准确性和查询性能,推荐的索引mapping如下:
{ "mappings": { "properties": { "id": { "type": "keyword" }, "title": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "created_at": { "type": "date" }, "categories": { "type": "nested", "properties": { "name": { "type": "keyword" }, "image": { "type": "keyword" } } } } } }
设计要点说明:
created_at设为date类型,原生支持毫秒级时间范围过滤,且ES会自动对filter类型的范围查询做缓存,重复查询相同时间范围的效率极高。categories设为nested类型,保留数组中每个分类对象内name和image的关联关系,避免ES默认扁平化存储导致的字段关联错乱问题。- 分类name和image都设为keyword类型,无需分词,完全适配聚合统计的需求。
如果你的分类体系是全局固定的(同一个分类name对应的image永远唯一),可以简化设计,不用nested类型,直接把categories.name存为keyword数组,分类和图片的对应关系单独存在业务层的缓存/字典里,能进一步降低聚合开销。
最优查询语句实现
{ "size": 0, // 不需要返回原始文档,仅返回聚合结果,大幅降低传输开销 "query": { "bool": { "filter": [ { "range": { "created_at": { "gte": 1672531200000, // 起始时间戳,按需替换 "lte": 1704067199000 // 结束时间戳,按需替换 } } } ] } }, "aggs": { "all_categories": { "nested": { "path": "categories" }, "aggs": { "group_by_category": { "terms": { "field": "categories.name", "size": 1000 // 按你的分类总数量调整,确保能返回全部分类 }, "aggs": { "category_image": { "top_hits": { "size": 1, "_source": ["categories.image"] } } } } } } } }
查询逻辑说明:
- 用
filter而不是must做时间过滤,不会计算相关性评分,同时支持查询缓存,相同时间范围的重复查询可以直接命中缓存,耗时能降到毫秒级。 - 先做nested聚合进入分类嵌套结构,再按分类name做terms聚合统计关联文档数,子聚合top_hits取对应分类的图片地址,因为同一个分类name的图片固定,取第一条即可。
- 数十万级数据量下,该查询的耗时通常在几十毫秒级别,调整时间过滤条件后重新执行即可拿到更新后的统计结果,完全满足实时性要求。
内容的提问来源于stack exchange,提问作者James Parker
相关产品推荐
相关产品推荐

