在 ElasticSearch 6 中按子聚合过滤、排序和分页

Posted

技术标签:

【中文标题】在 ElasticSearch 6 中按子聚合过滤、排序和分页【英文标题】:Filtering, sorting and paginating by sub-aggregations in ElasticSearch 6 【发布时间】:2019-12-02 21:57:00 【问题描述】:

我有一组文件,其中每个文件都指明了给定酒店和日期的可用房间,以及当天的费用:


    "hotel_id": 2016021519381313,
    "day": "20200530",
    "rooms": [
        
            "room_id": "00d70230ca0142a6874358919336e53f",
            "rate": 87
        ,
        
            "room_id": "675a5ec187274a45ae7a5fdc20f72201",
            "rate": 53
        
    ]

作为映射:


    "properties": 
        "day": 
            "type": "keyword"
        ,
        "hotel_id": 
            "type": "long"
        ,
        "rooms": 
            "type": "nested",
            "properties": 
                "rate": 
                    "type": "long"
                ,
                "room_id": 
                    "type": "keyword"
                
            
        
    

我试图弄清楚,如何进行查询,我可以在其中获得总成本低于给定金额的一组天的可用房间,按总成本升序排列并分页。

到目前为止,我想出了在这组天数内获得可用房间的方法以及它们的总成本。基本上按天过滤,并按酒店和房间 ID 分组,要求聚合中的最小计数是我要查找的天数。


    "size" : 0,
    "query": 
        "bool":  
            "must": [
                
                    "terms" : 
                        "day" : ["20200423", "20200424", "20200425"]
                    
                
            ]
         
     ,
    "aggs" : 
        "hotel" : 
            "terms" :  
                "field" : "hotel_id"
            ,
            "aggs" : 
                "rooms" : 
                    "nested" : 
                        "path" : "rooms"
                    ,
                    "aggs" : 
                        "rooms" : 
                            "terms" : 
                                "field" : "rooms.room_id",
                                "min_doc_count" : 3
                            ,
                            "aggs" : 
                                "sum_price" :  
                                    "sum" :  "field" : "rooms.rate"  
                            
                        

                    
                
            
        
    

所以现在我很感兴趣的是根据“房间”子聚合的值在“酒店”级别按降序对结果桶进行排序,并过滤不包含足够文档或哪些“ sum_price" 大于给定预算。但我无法管理如何做到这一点。

我一直在查看“bucket_sort”,但我找不到对子聚合进行排序的方法。我也一直在看“bucket_selector”,但是当它们不适合谓词时,它会给我空桶。在我的情况下,我可能没有正确使用它们。

哪种方法是正确的?

【问题讨论】:

【参考方案1】:

这里是查询没有分页


   "size":0,
   "query":
      "bool":
         "must":[
            
               "terms":
                  "day":[
                     "20200530",
                     "20200531",
                     "20200532"
                  ]
               
            
         ]
      
   ,
   "aggs":
      "rooms":
         "nested":
            "path":"rooms"
         ,
         "aggs":
            "rooms":
               "terms":
                  "field":"rooms.room_id",
                  "min_doc_count":3,
                  "order":
                     "sum_price":"asc"
                  
               ,
               "aggs":
                  "sum_price":
                     "sum":
                        "field":"rooms.rate"
                     
                  ,
                  "max_price":
                     "bucket_selector":
                        "buckets_path":
                           "var1":"sum_price"
                        ,
                        "script":"params.var1 < 100"
                     
                  
               
            
         
      
   

请注意,应更改以下变量以获得所需的结果:

天 min_doc_count max_price 中的脚本

【讨论】:

哇,谢谢!我对 ES 很陌生,你能解释一下我在查询中出错的地方吗? 首先,您根据酒店 ID 创建了额外的存储桶。 其次,您需要根据总成本进行过滤。为此,添加了存储桶选择器。 三、按总成本排序,使用order。 进一步阅读,可以搜索管道聚合。

以上是关于在 ElasticSearch 6 中按子聚合过滤、排序和分页的主要内容,如果未能解决你的问题,请参考以下文章

在javascript中按子数组属性值对对象数组进行排序

使用多个字段在 MongoDB 聚合框架中按相关性排序

使用多个字段在 MongoDB 聚合框架中按相关性排序

Laravel Query Builder 在按 ID 分组的查询中按子查询减去 COUNT

二维数组中按子数组首个元素值去重

如何通过Elasticsearch 6.x中的动态或未知字段进行聚合