Redis - 有序集合,按属性值查找项目

7

在redis中,我将对象存储在一个有序集合中。 在我的解决方案中,能够按日期运行范围查询非常重要,因此我将项目存储为分数为每个项目时间戳的项,例如:

#   Score   Value
0   1443476076  {"Id":"92","Ref":"7ADT","DTime":1443476076,"ATime":1443901554,"ExTime":0,"SPName":"7ADT33CFSAU6","StPName":"7ADT33CFSAU6"}
1   1443482969  {"Id":"11","Ref":"DAJT","DTime":1443482969,"ATime":1443901326,"ExTime":0,"SPName":"DAJTJTT4T02O","StPName":"DAJTJTT4T02O"}

然而,在其他情况下,我需要根据ID在集合中找到单个项目。 我知道不能像查询nosql数据库那样查询这个数据结构,但是我尝试使用ZSCAN,但不起作用。

ZSCAN MySet 0 MATCH Id:92 count 1

它返回:"空列表或集合"

也许我需要使用不同的序列化方式?我已经使用了Json.Net进行序列化。

如果可能的话,我该如何实现这个目标:使用日期作为分数,并仍然能够通过ID查找项目?

谢谢,

Lars

编辑:

假设这是不可能的,但任何想法或意见都是可以接受的:

参考:http://openmymind.net/2011/11/8/Redis-Zero-To-Master-In-30-Minutes-Part-1/

在Redis中,数据只能通过其键来查询。即使我们使用哈希表,我们也不能说“获取键的值等于sayan的字段”。

编辑2:

我尝试过:

ZSCAN MySet 0 MATCH *87*

127.0.0.1:6379> ZSCAN MySet 0 MATCH *87*
1) "192"
2) 1) "{\"Id\":\"64\",\"Ref\":\"XQH4\",\"DTime\":1443837798,\"ATime\":1444187707,\"ExTime\":0,\"SPName\":\"XQH4BPGW47FM\",\"StPName\":\"XQH4BPGW47FM\"}"
   2) "1443837798"
   3) "{\"Id\":\"87\",\"Ref\":\"5CY6\",\"DTime\":1443519199,\"ATime\":1444172326,\"ExTime\":0,\"SPName\":\"5CY6DHP23RXB\",\"StPName\":\"5CY6DHP23RXB\"}"
   4) "1443519199"

它找到了所需的项目,但还发现另一个属性ATime中有87的出现次数。拥有更多独特且更长的ID可能会以这种方式起作用,我需要在代码中过滤结果以找到具有其属性中精确值的那个。

仍然可以接受建议。

1个回答

13

我认为这很简单。

解决方案1(较差,不建议使用)

你的ZSCAN MySet 0 MATCH Id:92 count 1方法行不通,因为存储的字符串是"{\"Id\":\"92\"...而非"{\"Id:92\"...。该字符串已被转换为另一种格式。因此,请尝试使用MATCH Id\":\"64或类似的方式来匹配redis中的json序列化数据。我不熟悉json.net,实际字符串留给你自己去发现。

顺便问一下,你是否用ZSCAN MySet 0 MATCH Id:92 count 1返回了一个游标?我怀疑你的ZSCAN使用方式有误。

解决方案2(更好,强烈推荐使用)

当你的有序集合不大且知道如何通过Redis的Lua事务节省网络延迟时,ZSCAN是不错的选择。但这仍然会让“按ID查找”操作的时间复杂度为O(n)。因此,更好的解决方案是按以下方式更改数据模型:

将有序集合更改为

#   Score   Value
0   1443476076 {"Id":"92","Ref":"7ADT","DTime":1443476076,"ATime":1443901554,"ExTime":0,"SPName":"7ADT33CFSAU6","StPName":"7ADT33CFSAU6"}
1   1443482969 {"Id":"11","Ref":"DAJT","DTime":1443482969,"ATime":1443901326,"ExTime":0,"SPName":"DAJTJTT4T02O","StPName":"DAJTJTT4T02O"}

#   Score   Value
0   1443476076 Id:92
1   1443482969 Id:11

将剩余详细数据移动到另一组哈希类型的键中:

#   Key   field-value field-value ...
0   Id:92 Ref-7ADT DTime-1443476076 ...
1   Id:11 Ref-7ADT DTime-1443476076 ...

然后,你可以通过 hgetall id:92 来定位到ID为92的内容。至于按日期进行范围查询,则需要执行 ZRANGEBYSCORE sortedset mindate maxdate ,然后逐个使用 hgetall 命令获取每个ID的内容。最好使用lua将这些命令封装在一个函数中,这样仍然非常快!

NoSql数据库中的数据需要像上面那样进行冗余组织。这可能会使一些常规操作涉及多个命令和往返,但redis的lua功能可以解决这个问题。我强烈推荐redis的lua功能,因为它将命令封装成一个网络往返,并且所有命令都在redis服务器端执行,是原子性和超级快速的!

如果有任何不清楚的地方,请回复。


嗨,感谢您抽出时间写下非常好的答案。看起来解决方案2是这里走的路。我从未接触过lua,我会去了解一下。非常感谢! :) - Lars Anundskås
我建议删除解决方案1,因为它明显比解决方案2差,特别是它不是一个答案,而更像是一条可能需要提问者自己解决更多问题的路线。 - The Real Bill
@TheRealBill,我认为解决方案1更容易解决问题。解决方案2需要重新建模数据结构。虽然解决方案1只是指出了问题的关键,但可能会帮助提问者找到答案,而不需要给出详细的方法。 - Murphy Ng
如果你是通过字段进行查找,那么应该使用HGET而不是HGETALL,对吗? - philraj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接