使用elasticsearch以小时为单位过滤搜索结果

时间:2011-08-17 15:16:41

标签: time filtering elasticsearch

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

基本上,每个地点都有营业时间(一周中的每一天),每天可能有超过1套“营业时间”(我们现在使用2个)。

例如: 星期一: 上午9点开放/关闭12点 开放时间为下午1点/晚上9点

鉴于当前时间和当周的当天,我需要搜索“开放”位置。

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

此致

3 个答案:

答案 0 :(得分:4)

更好的方法是使用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 - 它很可能是一个简单的bug,很快就会修复。我在这里打开了一个问题:https://github.com/elasticsearch/elasticsearch/issues/1263

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

答案 1 :(得分:1)

上述解决方案不起作用,因为如果你有一些在星期一开放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) 
                    } 
                } 
            } 
        ] 
    } 
} 

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

答案 2 :(得分:0)

最简单的方法是在位置打开时命名和索引时隙。首先,您需要提供一个模式,在可以打开位置时为每个时隙分配一个名称。例如,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,依此类推。