2016-09-30 50 views
1

我有一个应用程序(nodejs/express),需要根据一天中的时间和星期几查找要应用的路由规则。REDIS - 创建有意义的键来减少查询

因此,例如,我有以下业务规则:

    在星期一和星期二
  • 09:00 GMT和12:00 GMT之间,我需要路由对象农行“位置x”。
  • 周二13:00到13:30我需要将ABC路由到“位置y”。

(为了这个讨论的目的,真的没关系ABC是什么对象。)

我两个选择之间的辩论,据我应该如何设计我的Redis数据库我的钥匙

选项1

让天信息中的对象数据的一部分,是这样的:

HMSET routing_rules:objectABC_09:00_12:00 days 'mon tues' location X 
HMSET routing_rules:objectABC_13:00_13:30 days 'tues' location Y 
这种方法的

优势 - 当它的时间来更新天名单我可以简单地这样做:

HMSET routing_rules:objectABC_09:00_12:00 days 'mon tues thu' 

这里的缺点是,为了找到合适的规则,我必须让两个查询.. ..首先做一个SCAN命令来找到合适的时间范围......然后如果有匹配的话......做另一个查询来查找天数值。

选项2

包括周信息的一天的关键

HMSET routing_rules:objectABC_09:00_12:00_mt location X 
HMSET routing_rules:objectABC_13:00_13:30_t location Y 

的一部分,我会用像

m = monday 
t = tuesday 
w = wed 
r = thursday 
etc. 

优点命名约定来选择2是为了根据当前时间和日期找到正确的路由规则,我只需要运行一个SCAN命令(我们可以假设我的扫描命令将返回一杆的结果)

但缺点选项2的是,当我需要一个新的一天增加的关键,我认为我需要删除键和值。 ..然后重新创建它。它是否正确?

而现在,我知道如何删除的唯一方法是对对象中的每个值做一个HDEL,然后删除该键。 因此,举例来说,我一直在做这样的事情:

127.0.0.1:6379> HDEL routing_rules:objectABC_00:00_00:00 days 'mon tues' location x 

,我必须列出的所有对象的值删除整个键/值对。 在这个例子中,它并没有那么糟糕,因为我只有两个值 - 这个键 - 位置和天数字段。但是如果有更多的数据,它会有点麻烦。除了与此关键字相关的字段数外,我不确定是否还有其他因素需要考虑。

如果您对如何设计此按键以获得最佳性能和维护方面有任何建议,我完全理解。我看到它的方式,至少有一次无法避免运行扫描。但这是我的第一个redis数据库尝试,所以我提前为补救性问题/ noob错误道歉。

编辑1

假设我有足够的内存,并假设我只需要保存一个字段/每键值,让我们说我创造了我的钥匙是这样的:

SET routing_rules:objectABC_09:00_12:00_m X 
SET routing_rules:objectABC_09:00_12:00_t X 
SET routing_rules:objectABC_13:00_13:30_t Y 

而且现在请求进入对象ABC,星期一在UTC 11。因为我的键表示开始时间和结束时间(又名范围),所以我没有看到如何在没有执行扫描的情况下找到正确的键/值对。

我错过了什么吗?

回答

0

我不会在这种情况下(以及在大多数情况下)使用任何SCAN命令。您可能必须多次调用它才能扫描整个密钥空间,而有其他替代方法可以直接访问您正在查找的数据 - 这就是K/V存储性能的原因。

举例来说,在您的第一个解决方案中,将所有值放在散列中,并在HGETALL的一个请求中获取所有路由。然后,您将不得不遍历应用程序中的值以选择正确的值。

另一种解决方案,不需要在应用程序方面的任何迭代,是创建每天,每小时范围内的航线:

SET routing_rules:objectABC_09:00_12:00_m location X SET routing_rules:objectABC_13:00_13:30_t location Y ...

在一个 GET请求

然后你有你正在寻找的价值对于。 添加一天只需要一个SET。 与您的解决方案相比的缺点是内存使用量:它将条目数量倍增。你没有提供关于条目数量的任何线索,但是如果它非常高,这可能是一个问题。要减少所需的内存,可以使用较短的键名开始,如r:objectABC_09001200m而不是routing_rules:objectABC_09:00_12:00_m)。

更新

鉴于时间范围似乎没有恒定,并假设没有算法来推断出当前时间的时间范围内,第一个解决方案,基于使用哈希,似乎基于GET/SET,比第二个更好。不过,我会根据时间命名域范围:

HSET routing_rules:objectABC 09:00_12:00 X HSET routing_rules:objectABC 12:00_12:30是

然后,我会得到所有的字段对于给定对象使用HGETALL routing_rules:objectABC并迭代成员键以找到正确的。

+0

帕斯卡,什么会被视为条目数“高”值? – Happydevdays

+0

与服务器上的可用内存相比,它取决于每个键+值的内存大小。 –

+0

我认为我将有大约15 GB使用...和50,000个对象,每个对象最多有5个路由规则。 – Happydevdays

0

我会使用排序集解决方案,为每个对象设置一个值,值应该是位置*,并且分数应该是该规则到期的一周内的分钟数。

例如(周开始于周一00:00)

在09:00 GMT和12:00 GMT之间的周一和周二,我需要的路线 对象农行“位置x”。

周一12:00 => 720 周二12:00 => 2160

ZADD ABC_rules 720 x 2160 x

有两个问题在这里,你的第一个例子显示时间,有没有规则,因此必须应予以考虑。第二个和更主要的设置对象必须是唯一的,并且x不能被存储两次。两者同时是上面的*原因,解决它是通向apped /前面加上本周一分钟规则开始值:

周一9:00 => 540 周二9:00 => 1980年

ZADD ABC_rules 720 x:540 2160 x:1980

要查询,所有你需要的是使用ZRANGEBYSCORE在本周分钟,并确保你得到追加到位置的时间是你送的时间之前。

查询周一10:00(600):

ZRANGEBYSCORE ABC_rules 600 +inf LIMIT 1

其结果将是x:540既然540是低于600,你知道x是一个有效的答案。

查询周一13:00(780):

ZRANGEBYSCORE ABC_rules 780 +inf LIMIT 1

结果将是x:1980,并且自1980年以来比你大的查询(780)这个结果是无效的,你应该把你的默认路由(或任何你的解决方案是在你的时间表未映射的时间)。

要删除规则,你必须删除与开始时附加的位置:

ZREM ABC_rules x:540

您还可以使用ZRANGEBYSCORE获得在特定的一天应用所有的规则,你可以写一个LUA清除它们的脚本。