我正在构建一个小型应用程序,以使用Elasticsearch 6.8.0查找诸如booking.com这样的酒店客房可用性。

基本上,我每天和每个房间都有一个文档,其中指定了是否可用以及当天的价格。我需要运行具有以下要求的查询:

输入:

  • 所需住宿的日子。
  • 我愿意花费的最大金额。
  • 我要查看的结果页面。
  • 每页的结果数。

  • 输出:
  • 符合要求的每家酒店最便宜的报价 list ,按ASC顺序订购。

  • 文件架构:
    {
      "mappings": {
        "_doc": {
          "properties": {
            "room_id": {
              "type": "keyword"
            },
            "available": {
              "type": "boolean"
            },
            "rate": {
              "type": "float"
            },
            "hotel_id": {
              "type": "keyword"
            },
            "day": {
              "type": "date",
              "format": "yyyyMMdd"
            }
          }
        }
      }
    }
    

    我每个月都有一个索引,此刻我仅在同一个月内进行搜索。

    我想出了这个查询:
    GET /hotels_201910/_search?filter_path=aggregations.hotel.buckets.min_price.value,aggregations.hotel.buckets.key
    {
      "size": 0,
      "query": {
        "bool": {
          "filter": [
            {
             "range": {
                "day": { "gte" : "20191001", "lte" : "20191010" }
              }
            },
            {
              "term": {
                "available": true
              }
            }
          ]
        }
      },
      "aggs": {
        "hotel": {
          "terms": {
            "field": "hotel_id",
            "min_doc_count": 1,
            "size" : 1000000
          },
          "aggs": {
            "room": {
              "terms": {
                "field": "room_id",
                "min_doc_count": 10,
                "size" : 1000000
              },
              "aggs": {
                "sum_price": {
                  "sum": {
                    "field": "rate"
                  }
                },
                "max_price": {
                  "bucket_selector": {
                    "buckets_path": {
                      "price": "sum_price"
                    },
                    "script": "params.price <= 600"
                  }
                }
              }
            },
            "min_price": {
              "min_bucket": {
                "buckets_path": "room>sum_price"
              }
            },
            "sort_by_min_price" : {
              "bucket_sort" :{
                "sort": [{"min_price" : { "order" : "asc" }}],
                "from" : 0,
                "size" : 20
              }
            }
          }
        }
      }
    }
    

    它有效,但是有几个问题。
  • 太慢了。每天有10万个房间,在没有其他查询正在运行的计算机上返回大约需要500毫秒。因此,在实时系统中,这将非常糟糕。
  • 在术语聚合中,我需要将"size"设置为大量,否则,不会考虑所有酒店和房间。

  • 有没有办法改善这种聚合的性能?我试图将索引拆分为多个分片,但这没有帮助。

    我几乎可以肯定这种方法是错误的,这就是为什么速度很慢。关于在这种情况下如何实现更快的查询响应时间的任何建议?

    最佳答案

    在找到答案之前,我不明白您为什么使用以下条件/汇总

    "min_price": {
              "min_bucket": {
                "buckets_path": "room>sum_price"
              }
            }
    

    您能否进一步说明为什么需要此服务。

    现在,回答您的主要问题:

    为什么要同时用room_id和hotel_id来表示。您可以获取搜索的所有房间,然后在应用程序端按hotel_id对其进行分组。

    以下逻辑将为您提供按room_id分组并具有总和指标的所有文档。您可以对> 600个条件使用相同的脚本过滤器。
       {
          "size": 0,
          "query": {
            "bool": {
              "filter": [
                {
                 "range": {
                    "day": { "gte" : "20191001", "lte" : "20191010" }
                  }
                },
                {
                  "term": {
                    "available": true
                  }
                }
              ]
            }
          },
          "by_room_id": {
                "composite" : {
                  "size": 100,
                    "sources" : [
                        {
                          "room_id": {
                            "terms" : {
                              "field": "room_id"
                            }
                          }
                        }
                    ]
                },
                "aggregations": {
                    "price_on_required_dates": {
                        "sum": { "field": "rate" }
                    },
                    "include_source": {
                        "top_hits": {
                    "size": 1,
                    "_source": true
                  }
                },
                "price_bucket_sort": {
                    "bucket_sort": {
                            "sort": [
                              {"price_on_required_dates": {"order": "desc"}}
                            ]
                        }
                    }
                }
            }
         }
    

    另外,为了提高搜索效果,
    https://www.elastic.co/guide/en/elasticsearch/reference/current/tune-for-search-speed.html

    10-07 17:08