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

IS0*_*S04 6 ruby-on-rails 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
Run Code Online (Sandbox Code Playgroud)

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

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


找到解决方案

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

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

    ((open_hour * 60 + open_minute)..(close_hour * 60 + close_minute)).to_a
    
    Run Code Online (Sandbox Code Playgroud)
  3. 添加过滤器进行搜索:

    filter :term, current_day_name => (current_hour * 60 + current_minutes)
    
    Run Code Online (Sandbox Code Playgroud)

这个解决方案也可以,但它看起来很麻烦,因为如果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 }
Run Code Online (Sandbox Code Playgroud)

And*_*fan 12

我会考虑这样做:

  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 }
]
Run Code Online (Sandbox Code Playgroud)
  1. 一周中的每一天(1 - > 7)表示一个值(要添加到分钟数):
Day 1 = addition 0
Day 2 = addition 2000
Day 3 = addition 4000
...
Day 7 = addition 10000
Run Code Online (Sandbox Code Playgroud)

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

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

"shop_name": "Shop 1",
"open_hours": [
  { "open": 6420, "close": 6810 },
  { "open": 6870, "close": 7080 }
]
Run Code Online (Sandbox Code Playgroud)
  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" }
          }
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)
  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}]}
Run Code Online (Sandbox Code Playgroud)
  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
                          }}}}}
                ]
              }}}}
            ]
}}}
Run Code Online (Sandbox Code Playgroud)

将输出Shop 4和Shop 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
              }
           ]
Run Code Online (Sandbox Code Playgroud)

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

{
  "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "path": "open_hours",
            "query": {
              "bool": {
                "filter": [
                  {
                    "range": {
                      "open_hours.open": {
                        "lte": 2400
                      }
                    }
                  },
                  {
                    "range": {
                      "open_hours.close": {
                        "gte": 2400
                      }
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)