根据营业时间有效确定企业是否开放

时间:2009-04-21 23:48:15

标签: python mysql performance solr

考虑到时间(例如,当前星期二下午4:24),我希望能够选择目前在一组业务中开放的所有业务。

  • 我有一周中每一天的每个业务的开放和关闭时间
  • 我们假设一个企业只能在每小时00,15,30,45分钟开启/关闭
  • 我假设每周都有相同的时间表。
  • 我最感兴趣的是能够快速查找在特定时间开放的一组业务,而不是数据的空间要求。
  • 请注意,有些我一天晚上11点开门,第二天凌晨1点关门。
  • 假期并不重要 - 我将另行处理

存储这些打开/关闭时间的最有效方法是什么,以便通过单个时间/星期几元组,我可以快速确定哪些商家是开放的?

我正在使用Python,SOLR和mysql。我希望能够在SOLR中进行查询。但坦率地说,我对任何建议和备选方案持开放态度。

7 个答案:

答案 0 :(得分:8)

如果您愿意一次只查看一周,您可以将所有开始/结束时间规范化为自本周开始以来设定的分钟数,例如周日0小时。对于每个商店,您创建了许多形式为[startTime,endTime,storeId]的元组。 (对于跨越周日午夜的小时数,你必须创建两个元组,一个到本周末,一个从本周开始)。这组元组将在startTime和endTime上编制索引(例如,使用您要预处理的树)。元组不应该那么大:一周只有大约10k分钟,可以容纳2个字节。这种结构在具有适当索引的MySQL表中是优雅的,并且对于常量插入非常有弹性。随着信息的变化删除记录。您的查询只是“select storeId where startTime< = time and endtime> = time”,其中time是自星期日午夜以来的规范化分钟。

如果信息不经常更改,并且您希望查找速度非常快,则可以预先解决所有可能的查询并缓存结果。例如,一周只有672个季度小时。有一个企业列表,每个企业都有一个开放和列表的列表。像Brandon Rhodes的解决方案关闭时间,您可以简单地,在一周内每隔15分钟迭代一次,找出谁打开,然后将答案存储在查找表或内存列表中。

答案 1 :(得分:5)

另一位受访者提到的位图字段效率会非常高,但如果您希望能够处理半小时或四分之一小时的时间,则会变得混乱,因为您必须在算术上增加位数和设计每当您遇到必须匹配的新分辨率时,该字段。

我会尝试将值作为日期时间存储在列表中:

openclosings = [ open1, close1, open2, close2, ... ]

然后,我会在其内置的“bisect”模块中使用Python的“bisect_right()”函数,在快速O(log n)时间内查找该列表中查询时间“适合”的位置。然后,查看返回的索引。如果它是偶数(0,2,4 ......),则时间介于“关闭”时间之一和下一个“打开”时间之间,因此商店关闭。相反,如果二分指数是一个奇数(1,3,5 ......),那么时间已经落在开盘和收盘时间之间,而且商店是开放的。

没有bitmaps那么快,但你不必担心解决方案,我不能想到另一个优雅的O(log n)解决方案。

答案 2 :(得分:4)

你说你正在使用SOLR,不关心存储,并希望查找速度快。然后,不是存储打开/关闭元组,而是为您需要的粒度级别(15分钟)索引每个打开的时间块的条目。对于编码本身,您可以只使用累积小时:分钟。

例如,星期一下午4点到5点开放的商店将为[40:00,40:15,40:30,40:45]添加索引值。星期一下午4:24的查询将被标准化为40:15,因此与该商店文档匹配。

乍一看这似乎效率低下,但对于索引速度和空间来说,这是一个相对较小的常数惩罚。并尽可能快地进行搜索。

答案 3 :(得分:3)

抱歉,我没有一个简单的答案,但我可以告诉你,作为90年代后期公司开发团队的经理,我们的任务就是解决这个问题而且很难。

这不是每周的艰难时刻,可以使用相对较小的位掩码(168位=每周1小时),诀窍是每周二交替关闭的业务。

从位掩码开始然后转到例外字段是我见过的最佳解决方案。

答案 4 :(得分:1)

在您的Solr索引中,不是将每个业务编入索引作为一个包含小时数的文档,而是在一周内为每个业务的每个“零售会话”编制索引。

例如,如果Joe的咖啡在周一至周六早上6点至晚上9点开放并在周日关闭,那么您将索引六个不同的文档,每个文档都有两个索引字段,“打开”和“关闭”。如果您的单位间隔为15分钟,则值的范围为0到7 * 24 * 4。假设您拥有每个企业的唯一ID,请将其存储在每个文档中,以便将会话映射到企业。

然后你可以在Solr中进行范围搜索:

打开:[*到N]并关闭:[N + 1 TO *]

其中N被计算为当前时间落入的第N个15分钟间隔。例如,如果是星期三上午10点10分,您的查询将是:

打开:[*至112]并关闭:[113 TO *]

又名“在星期三上午10:00或之前开始会议,并在星期三上午10点15分或之后结束”

如果要在搜索中包含其他条件(例如位置或产品),则还需要为每个会话文档编制索引。这有点多余,但如果你的索引不是很大,那应该不是问题。

答案 5 :(得分:0)

如果你可以很好地控制你的数据,我会看到一个简单的解决方案,类似于@ Sebastian的。遵循创建元组的建议,除了创建表单[time = startTime,storeId]和[time = endTime,storeId],然后在列表中对它们进行排序。要查明商店是否已打开,只需执行以下查询:

select storeId
from table
where time <= '@1'
group by storeId
having count(storeId) % 2 == 1

为了优化这一点,您可以在每个时间t构建一个查找表,存储在t处打开的商店,以及t和t + 1之间的商店开/关(对于任何t的分组)。

然而,这具有难以维护的缺点(重叠的开/关需要合并到更长的开闭期间)。

答案 6 :(得分:0)

您是否看过有多少独特的开/关时间组合?如果没有那么多,请创建唯一组合的参考表,并存储针对每个业务的相应条目的索引。然后,您只需要搜索参考表,然后找到包含这些索引的业务。