【问题标题】:Filtering search results by operating hour with elasticsearch使用elasticsearch按营业时间过滤搜索结果
【发布时间】:2014-10-16 10:19:15
【问题描述】:

我正在使用 elasticsearch 来索引和搜索位置,我遇到了 1 个按营业时间过滤的特殊问题,我不知道如何解决

基本上,每个位置都会有营业时间(一周中的每一天),并且每天可能有超过 1 个“组”营业时间(我们现在使用 2 个)。

例如: 周一: 上午 9 点开门 / 中午 12 点关门 下午 1 点开门 / 晚上 9 点关门

鉴于当前时间和星期几,我需要搜索“开放”位置。

我不知道如何将这些营业时间与位置详细信息一起索引,以及如何使用它们来过滤结果,任何帮助,建议将不胜感激

问候

【问题讨论】:

    标签: time filtering elasticsearch


    【解决方案1】:

    更好的方法是使用nested 文档。

    首先:设置您的映射以指定应将hours 文档视为嵌套:

    curl -XPUT 'http://127.0.0.1:9200/foo/?pretty=1'  -d '
    {
       "mappings" : {
          "location" : {
             "properties" : {
                "hours" : {
                   "include_in_root" : 1,
                   "type" : "nested",
                   "properties" : {
                      "open" : {
                         "type" : "short"
                      },
                      "close" : {
                         "type" : "short"
                      },
                      "day" : {
                         "index" : "not_analyzed",
                         "type" : "string"
                      }
                   }
                },
                "name" : {
                   "type" : "string"
                }
             }
          }
       }
    }
    '
    

    添加一些数据:(注意开放时间的多个值)

    curl -XPOST 'http://127.0.0.1:9200/foo/location?pretty=1'  -d '
    {
       "name" : "Test",
       "hours" : [
          {
             "open" : 9,
             "close" : 12,
             "day" : "monday"
          },
          {
             "open" : 13,
             "close" : 17,
             "day" : "monday"
          }
       ]
    }
    '
    

    然后运行查询,按当前日期和时间过滤:

    curl -XGET 'http://127.0.0.1:9200/foo/location/_search?pretty=1'  -d '
    {
       "query" : {
          "filtered" : {
             "query" : {
                "text" : {
                   "name" : "test"
                }
             },
             "filter" : {
                "nested" : {
                   "path" : "hours",
                   "filter" : {
                      "and" : [
                         {
                            "term" : {
                               "hours.day" : "monday"
                            }
                         },
                         {
                            "range" : {
                               "hours.close" : {
                                  "gte" : 10
                               }
                            }
                         },
                         {
                            "range" : {
                               "hours.open" : {
                                  "lte" : 10
                               }
                            }
                         }
                      ]
                   }
                }
             }
          }
       }
    }
    '
    

    这应该可行。

    不幸的是,在 0.17.5 中,它抛出了 NPE - 这很可能是一个简单的错误,很快就会修复。我在这里打开了一个问题:https://github.com/elasticsearch/elasticsearch/issues/1263

    更新 奇怪的是,我现在无法复制 NPE - 这个查询似乎在 0.17.5 及更高版本上都能正常工作。一定是一些暂时的故障。

    克林特

    【讨论】:

    • 感谢 Clint,这看起来很整洁,我正在关注您在 ElasticSearch 上发布的问题。
    【解决方案2】:

    上述解决方案不起作用,因为如果您有一些在周一 2-4 和周二 6-8 开放的东西,那么在周一 6 点进行过滤将返回文档。下面是一些伪json来说明它应该如何完成。

    {
        "business_document": "...",
        "hours": {
            "1": [
                {
                    "open": 930,
                    "close": 1330
                },
                {
                    "open": 1530,
                    "close": 2130
                }
            ],
            "2": [
                {
                    "open": 1000,
                    "close": 2100
                }
            ],
            "3": [
                {
                    "open": 1000,
                    "close": 2100
                }
            ],
            "4": [
                {
                    "open": 1000,
                    "close": 2100
                }
            ],
            "5": [
                {
                    "open": 1000,
                    "close": 2100
                }
            ],
            "6": [
                {
                    "open": 1000,
                    "close": 2100
                }
            ],
            "7": [
                {
                    "open": 930,
                    "close": 1330
                },
                {
                    "open": 1530,
                    "close": 2130
                }
            ]
        }
    } 
    
    
    Sample Filter (can be applied to any query for a businesses): 
    { 
        "filter": { 
            "and": [ //Must match all following clauses 
                { 
                    "range": { 
                        "hours.1.open": { //Close Hour of Day 1 (current day) 
                            "lte": 1343 //Store open time is less than 13:43 (current time) 
                        } 
                    } 
                }, 
                { 
                    "range": { 
                        "hours.1.close": { //Close Hour of Day 1 (current day) 
                            "gte": 1343 //Store close time is greater than 13:43 (current time) 
                        } 
                    } 
                } 
            ] 
        } 
    } 
    

    所有时间都应采用标准时区 (GMT) 的 24 小时格式

    【讨论】:

    • 在一天内编辑了多次。应该很快就会发布。
    • 您的评论不正确,忽略了我使用的是“嵌套”字段类型,而不是普通的“对象”这一事实。 “嵌套”对象在内部被索引为单独的文档,正是为了避免您遇到的问题。
    • 嵌套对象不是免费的。如果你可以避免它们(在这种情况下你可以),那么你应该这样做。
    • 你将如何定义这个映射?
    【解决方案3】:

    最简单的方法是在位置打开时命名和索引时间段。首先,您需要提出一个模式,为可以打开位置的每个时间段分配一个名称。例如,thu17 可能代表星期四下午 5 点。然后,您的示例中的位置应使用包含以下值的几个“open”字段进行索引:mon09、mon10、mon11、mon13、mon14、mon15、mon16、mon17、mon18、mon19、mon20、tue09、tue10 等。要仅显示周四上午 7 点开放的位置,您只需将此过滤器添加到您的查询中:open:thu07。

    您不必使用这个特定的命名模式。例如,您可以只计算从一周开始的小时数。在这种情况下,周一上午 9 点将是 9 点,周一晚上 11 点 - 23 日,周二凌晨 2 点 - 26 日,依此类推。

    【讨论】:

    • 很有趣,但是例如 7:01 或 7:17 呢?我目前的(计划)解决方案是索引每天的开放时间/关闭时间(对),然后使用弹性查询或范围过滤(gte,lte)
    • 您真的有营业时间为 7:01 的地点吗?通常是一个小时或半小时,最坏的情况可能是四分之一。
    • 以下是有关数字范围查询如何工作的一些背景信息:lucene.apache.org/java/3_0_3/api/all/org/apache/lucene/search/… 这可能有助于做出最终决定。
    • 你说得对,我误解了它的工作原理。我正在考虑根据营业时间检查传入的当前时间(例如,在 7:01,用户可能想检查附近是否有任何营业地点)
    猜你喜欢
    • 2012-08-30
    • 2018-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-15
    相关资源
    最近更新 更多