如何通过REST查询获取Elasticsearch前10条高频访问最新文档
搞定Elasticsearch按「访问次数+最近时间」取Top10的需求
看起来你需要从Elasticsearch里拉取近30天内,访问次数最多且最近被访问的前10条结果对吧?先给你指出当前查询里的几个小问题,再给你一个能直接用的正确写法:
你的原查询踩了这些坑:
- 聚合(
aggs)放错位置啦!它得和query、size同级,不能嵌套在range查询里面 - 用
searchDate做terms聚合没啥意义,你应该按要统计访问次数的维度(比如你要保留的origin和destination组合)来聚合,不然统计的是每天的访问次数,不是你要的“搜索条目”的访问次数 - 没体现「访问次数多优先,同次数看最近时间」的排序逻辑
修正后的查询,完美匹配你的需求:
{ "size": 0, // 不用返回所有匹配的原始文档,只拿聚合结果就行,省资源 "query": { "range": { "searchDate": { "gte": "now-30d/d" // Elasticsearch自带的相对时间,比DateTime.Now.AddDays(-30)靠谱多了,自动对齐到天的起始 } } }, "aggs": { "top_search_entries": { "terms": { "field": "origin.keyword", // 如果origin是文本类型,必须加.keyword做精确聚合;要是想按origin+destination组合统计,后面我给你说方法 "size": 10, // 直接取访问次数Top10的条目 "order": [ {"_count": "desc"}, // 第一优先级:访问次数从高到低 {"latest_access_time": "desc"} // 第二优先级:同次数的,最近访问的排前面 ] }, "aggs": { "latest_access_time": { "max": { "field": "searchDate" // 先把每个条目最近的访问时间算出来,用来排序 } }, "latest_document": { "top_hits": { "size": 1, // 每个条目里只拿最新的那一条文档 "sort": [{"searchDate": "desc"}], // 组内按访问时间倒序,确保拿的是最新的 "_source": { "includes": ["origin", "destination", "searchDate"] // 只返回你需要的字段,减少数据传输 } } } } } } }
额外补充:按起终点组合统计的写法
如果你需要按origin和destination的组合来统计访问次数(比如相同的起终点算一个条目),可以把terms聚合改成composite聚合,写法如下:
"aggs": { "top_search_entries": { "composite": { "size": 10, "sources": [ {"origin": {"terms": {"field": "origin.keyword"}}}, {"destination": {"terms": {"field": "destination.keyword"}}} ], "order": [ {"_count": "desc"}, {"latest_access_time": "desc"} ] }, "aggs": { "latest_access_time": { "max": {"field": "searchDate"} }, "latest_document": { "top_hits": { "size": 1, "sort": [{"searchDate": "desc"}], "_source": {"includes": ["origin", "destination", "searchDate"]} } } } } }
要是你的需求不是分组取Top10,而是直接返回单个文档按访问次数+时间排序的Top10,那可能需要先给每个文档打上访问次数的分数,用function_score结合聚合结果,但这种场景一般分组聚合更符合“最大命中数”的需求哦。
内容的提问来源于stack exchange,提问作者vilas gurav
相关产品推荐
相关产品推荐

