通过Elasticsearch / Tire的时间表查找开放式商店

我有模型Shop每个都与Timetable有关系,可能包含以下内容:

 shop_id: 1, day: 5, open_hour: 7, open_minutes: 0, close_hour: 13, close_minute: 30 shop_id: 1, day: 5, open_hour: 14, open_minutes: 30, close_hour: 18, close_minute: 00 

当然, Timetable可以有更优雅的格式,但问题是下一个:如何使用elasticsearch(轮胎)我可以找到开放的商店吗?

所有的想法都会被贬低! 谢谢!


找到解决方案

  1. 为每一天创建单独的索引(星期日,星期一,…)

  2. 每天从Timetable构建完整的分钟数:

     ((open_hour * 60 + open_minute)..(close_hour * 60 + close_minute)).to_a 
  3. 添加filter进行搜索:

     filter :term, current_day_name => (current_hour * 60 + current_minutes) 

这个解决方案同样有效,但看起来很麻烦,因为如果Shop每天工作8小时,我创建了大小为8 * 60 = 480数组(将其转换为字符串作为索引字段),这就是为什么这个问题是仍然开放,也许有人会找到更好的解决方案


@Andrei Stefan的轮胎部分回答:

 indexes :open_hours, type: :nested do indexes :open, type: 'integer' indexes :close, type: 'integer' end open_hours_query = Tire::Search::Query.new do filtered do query { all } filter :range, "open_hours.open" => { lte: current_time } filter :range, "open_hours.close" => { gte: current_time } end end filter :nested, { path: 'open_hours', query: open_hours_query.to_hash } 

我会考虑这样做:

  1. 开始和结束时间是Elasticsearch中嵌套对象数组的整数值:

例如:商店在07:00开业,在13:30关闭,然后在14:30开业,第1天在18:00关闭,将转换为ES:

 "shop_name": "Shop 1", "open_hours": [ { "open": 420, "close": 810 }, { "open": 870, "close": 1080 } ] 
  1. 一周中的每一天(1 – > 7)代表一个值(加到分钟数):
 Day 1 = addition 0 Day 2 = addition 2000 Day 3 = addition 4000 ... Day 7 = addition 10000 

因此,每天增加2000,因为每天最多包含1440分钟(24小时* 60分钟),并且能够将一天与单个数字区分开,这些数字不必相交。

因此,上面的示例在07:00开店将在第4天翻译为例如:

 "shop_name": "Shop 1", "open_hours": [ { "open": 6420, "close": 6810 }, { "open": 6870, "close": 7080 } ] 
  1. 查询这些文档时,您想要搜索的那一天需要遵守与上述相同的规则。 例如,如果您想在第4天13:45看到“商店1”打开,您将搜索(6000 + 13 * 60 + 45 = 6825)分钟。

  2. Elasticsearch中上面所有内容的映射都是这样的:

 { "mappings": { "shop" : { "properties": { "shop_name" : { "type" : "string" }, "open_hours" : { "type" : "nested", "properties": { "open" : { "type" : "integer" }, "close": { "type" : "integer" } } } } } } } 
  1. 测试数据:
 POST /shops/shop/_bulk {"index":{}} {"shop_name":"Shop 1","open_hours":[{"open":420,"close":810},{"open":870,"close":1080}]} {"index":{}} {"shop_name":"Shop 2","open_hours":[{"open":0,"close":500},{"open":1000,"close":1440}]} {"index":{}} {"shop_name":"Shop 3","open_hours":[{"open":0,"close":10},{"open":70,"close":450},{"open":900,"close":1050}]} {"index":{}} {"shop_name":"Shop 4","open_hours":[{"open":2000,"close":2480}]} {"index":{}} {"shop_name":"Shop 5","open_hours":[{"open":2220,"close":2480},{"open":2580,"close":3000},{"open":3100,"close":3440}]} {"index":{}} {"shop_name":"Shop 6","open_hours":[{"open":6000,"close":6010},{"open":6700,"close":6900}]} 
  1. 在当天(06:40)的第2,400分钟查询第2天开设的商店:
 { "query": { "bool": { "must": [ { "nested": { "path": "open_hours", "query": { "bool": { "must": [ { "filtered": { "filter": { "range": { "open_hours.open": { "lte": 2400 }}}}}, { "filtered": { "filter": { "range": { "open_hours.close": { "gte": 2400 }}}}} ] }}}} ] }}} 

将输出4号店和5号店:

  "shop_name": "Shop 4", "open_hours": [ { "open": 2000, "close": 2480 } ] "shop_name": "Shop 5", "open_hours": [ { "open": 2220, "close": 2480 }, { "open": 2580, "close": 3000 }, { "open": 3100, "close": 3440 } ] 

LATER EDIT:自从我添加了这个回复并且自那时以来许多事情都发生了变化以来,Elasticsearch已经采用了一种方式, filtered器(在我must使用的bool的上下文中)可以被bool filter替换,甚至是简单的must 。 此外,该string在6.x中不再存在,因此如果您需要使用分析器或keyword"shop_name" : { "type" : "text" }, )按商店名搜索,则可以使用text

 { "query": { "bool": { "must": [ { "nested": { "path": "open_hours", "query": { "bool": { "filter": [ { "range": { "open_hours.open": { "lte": 2400 } } }, { "range": { "open_hours.close": { "gte": 2400 } } } ] } } } } ] } } }