今天要写一个需求,需要根据一个字段去做聚合,并且要展示其他索引内的字段。我们都知道如果是在mysql的话,单次查询也是无法被实现的,我们select的内容必须跟随在group的后面。但是为了保证ES的查询效率,我们需要在查询一次的情况下同时展示其他字段,那我们该怎么去做呢? 因为我们使用的表结构不是nested结构,并且这个表结构修改会涉及很多代码,所以我首先排除了通过innerHits去解决这个问题的方式,在这里我选用了Top Hits来解决眼下的这个问题,首先我们分析一下我们的场景,根据一个字段去聚合,并且获取出其他的字段,前提条件肯定是其他字段和当前聚合字段的关系必须是一对一的,并且我们得知道Top Hits它的作用是什么,作用是获取聚合后的其他字段或者可以理解为关联数据,而这个TopHits的size,为了性能考虑我们可以直接设置为1,也就是说比如你根据某一维度去进行聚合,你只需要在TopHits中新增其他你想要展示的字段即可,并且给它取个别名,在java代码中我们可以通过获取具体的别名来获取里面的值,这样我们就可以取到根据某个维度聚合之后的其他字段,这里你可能会有疑惑,为什么咱不像MySQL一样再次去查询一下而使用TopHits这种方式,因为咱ES的数据量很大,并且我们都知道ES的上限是1W条,假设你要遍历的数据不在这1W条之内呢,那你就肯定获取不到对应的值了,所以采用了TopHits的方式去进行取值。
在这里我们还需要考虑一下ES的版本,当初我们ES是升级成了6.8.4版本才可以使用,低于此版本的建议去参考一下官方文档看TopHits这个特性是哪个版本出的,并且当前业务是否兼容升级。在Nested的解决方式以及ES版本之间做一个取舍。
聚合DSL语句
{ "size": 1, "aggregations": { "eventName": { "terms": { "field": "eventname.keyword", "size": 10, "min_doc_count": 1, "shard_min_doc_count": 0, "show_term_doc_count_error": false, "order": [ { "_count": "desc" }, { "_key": "asc" } ] }, "aggregations": { "field": { "top_hits": { "from": 0, "size": 1, "version": false, "seq_no_primary_term": false, "explain": false, "_source": { "includes": [ "alert_level", "alert_time", "phase", "mod" ], "excludes": [] }, "sort": [ { "alert_time": { "order": "asc" } } ] } } } } } }