【问题标题】:Find open Shops through Timetable with Elasticsearch/Tire使用 Elasticsearch/Tire 通过时间表查找开放的商店
【发布时间】:2014-11-07 12:37:25
【问题描述】:

我的模型 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(tire) 找到营业的 Shop?

所有的想法都会被欣赏!谢谢!


找到解决方案:

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

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

    ((open_hour * 60 + open_minute)..(close_hour * 60 + close_minute)).to_a
    
  3. 为搜索添加过滤器:

    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 }

【问题讨论】:

    标签: ruby-on-rails elasticsearch tire


    【解决方案1】:

    我会考虑这样做:

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

    示例:商店在 07:00 开店 13:30 关店,然后在第 1 天 14:30 开店和 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 是否打开了“Shop 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. 查询第 2 天在当天第 2400 分钟 (06:40) 开业的商店:
    {
      "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
                              }}}}}
                    ]
                  }}}}
                ]
    }}}
    

    会输出 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
                  }
               ]
    

    后期编辑:自从我添加此回复以来,Elasticsearch 已经走过了漫长的道路,并且从那时起许多事情发生了变化,filtered 过滤器(在 bool must 的上下文中,我used) 可以替换为bool filter 甚至是简单的must。此外,string 不再存在于 6.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
                          }
                        }
                      }
                    ]
                  }
                }
              }
            }
          ]
        }
      }
    }
    

    【讨论】:

    • 感谢您的回答和花费时间!
    • 谢谢Andrei,除了回答,您对elasticsearch 前端快速更新架构有什么建议吗?我一直在休息客户端上做这件事,而且非常耗时
    • @wolfgang :-) 我相信你之前问过这个问题,不,我仍然没有推荐。
    • @AndreiStefan 好吧,你会用什么?我可以看到您是 elasticsearch 的工程师。任何比 REST 客户端更好的东西都将不胜感激!
    • 您自己的应用程序使用其中一种客户端集成(Java、Scala、python 等)。
    猜你喜欢
    • 2012-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-07
    • 2013-08-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多