获取可用的公寓查询

Get available apartments query

概览

我有预订的公寓。我的索引有 嵌套字段 的保留,日期字段为 start_date 和 end_date。

我正在使用耐嚼的 ruby gem - 但我认为此时这并不重要。只需要让我的查询正确。

目标

我想获取在给定日期没有预订或根本没有预订的所有可用公寓。

当前查询

很遗憾returns所有公寓:

:query => {
  :bool => {
    :must_not => [
      {
        :range => {:"reservations.start_date" => {:gte => "2017-02-10"}}
      }, 
      {
        :range => {:"reservations.end_date" => {:lte => "2017-02-12"}}
      }
    ]
  }
}

索引设置

{
  "apartments" : {
    "aliases" : { },
    "mappings" : {
      "apartment" : {
        "properties" : {
          "city" : {
            "type" : "string"
          },
          "coordinates" : {
            "type" : "geo_point"
          },
          "email" : {
            "type" : "string"
          },
          "reservations" : {
            "type" : "nested",
            "properties" : {
              "end_date" : {
                "type" : "date",
                "format" : "yyyy-MM-dd"
              },
              "start_date" : {
                "type" : "date",
                "format" : "yyyy-MM-dd"
              }
            }
          },
          "street" : {
            "type" : "string"
          },
          "zip" : {
            "type" : "string"
          }
        }
      }
    },
    "settings" : {
      "index" : {
        "creation_date" : "1487289727161",
        "number_of_shards" : "5",
        "number_of_replicas" : "1",
        "uuid" : "-rM79OUvQ3qkkLJmQCsoCg",
        "version" : {
          "created" : "2040499"
        }
      }
    },
    "warmers" : { }
  }
}

首先,我认为你必须使用nested query

我不熟悉 chewy-gem 但查询看起来像这样:

:query => {
  :nested: => {
    :path: => "reservations",
    :query => {
      :bool => {
        :must_not => [ 
          {
            :range => {:"reservations.start_date" => {:gte => "2017-02-10"}}
          }, 
          {
            :range => {:"reservations.end_date" => {:lte => "2017-02-12"}}
          }
        ]
      }
    }
  }
}

但它也可能无法正常工作,因为如果在 2018 年有预订,第一个 bool 查询将为真(因为开始日期将 > 2017-02-10),因此不会退还公寓,如果我是正确的。

我会做类似的事情:

:query => {
  :nested: => {
    :path: => "reservations",
    :query => {
      :bool => {
        :must_not => [ 
          {
            :range => {:"reservations.start_date" => {:gte => "2017-02-10", :lte => "2017-02-12"}}
          }, 
          {
            :range => {:"reservations.end_date" => {:gte => "2017-02-10", :lte => "2017-02-12"}}
          }
        ]
      }
    }
  }
}

这意味着您想要的范围内没有开始日期,您想要的范围内没有结束日期。

这是我提出的查询,应该考虑所有条件,即:

  • 要么没有预订(1st top-level bool/should
  • 或至少有一项预订且预订开始和结束日期与请求日期不重叠。

在这里,我们要求在 2017-02-102017-02-12

之间提供免费公寓
{
  "bool": {
    "minimum_should_match": 1,
    "should": [
      {
        "nested": {
          "path": "reservations",
          "query": {
            "bool": {
              "must_not": {
                "exists": {
                  "field": "reservations.start_date"
                }
              }
            }
          }
        }
      },
      {
        "bool": {
          "must": [
            {
              "nested": {
                "path": "reservations",
                "query": {
                  "bool": {
                    "minimum_should_match": 1,
                    "should": [
                      {
                        "range": {
                          "reservations.start_date": {
                            "gt": "2017-02-10"
                          }
                        }
                      },
                      {
                        "range": {
                          "reservations.end_date": {
                            "lt": "2017-02-10"
                          }
                        }
                      }
                    ]
                  }
                }
              }
            },
            {
              "nested": {
                "path": "reservations",
                "query": {
                  "bool": {
                    "minimum_should_match": 1,
                    "should": [
                      {
                        "range": {
                          "reservations.start_date": {
                            "gt": "2017-02-12"
                          }
                        }
                      },
                      {
                        "range": {
                          "reservations.end_date": {
                            "lt": "2017-02-12"
                          }
                        }
                      }
                    ]
                  }
                }
              }
            }
          ]
        }
      }
    ]
  }
}

我们必须列出免费公寓和那些将在所需时间段内可用的公寓(start_date、end_date 变量)

所以它应该是一个或查询:free_aparments or available_aparments

免费公寓(那些在预订字段中没有任何值的公寓)应该很容易通过缺少过滤器来查询,但这是一个嵌套字段,我们必须处理。
如果我们在缺少过滤器的情况下执行查询,将返回所有文档。这很奇怪,但确实发生了。这里有解释的解决方案:https://gist.github.com/Erni/7484095 and here is the issue: https://github.com/elastic/elasticsearch/issues/3495 gist snnipet 适用于所有 elasticsearch 版本。

or 查询的另一部分是可用的公寓。
我已经解决了这部分执行非查询。 Return 我是那些没有预订的公寓,想了一个与那些有预订的公寓相匹配的范围列表,然后使用 must_not 过滤器

否定结果
elasticsearch_query = {
    "query": {
        "filtered": {
            "filter": {
                "bool": {
                    "should": [
                        {
                            "nested": {
                                "filter": {
                                    "bool": {
                                        "must_not" : [
                                            {
                                                "range": {
                                                    "start_date": {
                                                        "gte" : start_date, 
                                                        "lt" :end_date
                                                    }
                                                }
                                            },
                                            {
                                                "range": {
                                                    "end_date": {
                                                        "gte" : end_date, 
                                                        #"lte" :end_date
                                                    }
                                                }
                                            }
                                        ]
                                    }
                                }, 
                                "path": "reservations"
                            }
                        },
                        {
                            #{ "missing" : { "field" : "reservations"} }
                            "not": {
                                "nested": {
                                    "path": "reservations",
                                    "filter": {
                                        "match_all": {}
                                    }
                                }
                            }
                        }
                    ],
                }
            }
        },
    }, 
    "sort" : {"id":"desc"}
}

你可以在this notebook
中查看我的解决方案 我创建了一个示例,填充了一个示例索引并使用此查询搜索所需的公寓

评论回答:

  1. Prefix: 由于执行了嵌套过滤器设置路径将被查询,所以根本不需要前缀(至少在我测试的版本中)。是的,您可以在文档级别或另一个嵌套字段

  2. 添加字段名称 start_date
  3. 公寓匹配:是的,它与 91 个样本公寓匹配,但由于我使用默认 size 参数执行了 search,因此仅返回 10 个(我没有指定它的值,它的默认值)。如果您需要获取所有这些,请使用 scroll search


(已修改笔记本以阐明这一点)