如何在Redis中进行反向查找?

6

Redis能否通过键或值进行查找?我需要存储电子邮件地址的主列表,并为每个地址分配UUID,但需要能够通过使用另一条数据查找ID或ADDRESS。我没有找到明确的“是”或“否”的答案。任何示例将不胜感激。

3个回答

4

您需要创建2个哈希映射表:

  1. 从UUID到电子邮件的哈希映射表(uuid_to_email)
  2. 从电子邮件到UUID的哈希映射表(email_to_uuid)

例如:

> hset uuid_to_email 39315120-9581-11e3-9c4e-0002a5d5c51b foo@bar.com
> hset email_to_uuid foo@bar.com 39315120-9581-11e3-9c4e-0002a5d5c51b

然后,要检索值,请使用从您拥有的值映射的哈希表。如果您有UUID,请使用uuid_to_email:

> hget uuid_to_email 39315120-9581-11e3-9c4e-0002a5d5c51b
"foo@bar.com"

如果您有电子邮件,请使用email_to_uuid:

> hget email_to_uuid foo@bar.com
"39315120-9581-11e3-9c4e-0002a5d5c51b"

2
哈希表并不适合存储大量的数据,因此只有在使用情况涉及几百个地址时,这种方法才是有效的。 - Itamar Haber
2
@ItamarHaber 这是完全不正确的。例如,Instagram 正在使用HashMaps存储数亿条记录。从那篇博客文章中可以看到,“我们需要保留大约3亿张照片与创建它们的用户ID之间的映射...我们向Redis核心开发人员之一Pieter Noordhuis寻求帮助,并建议我们使用Redis哈希。”这不仅是可能的,而且是存储如此多数据的最有效方式。 - uberdog
另外,@ItamarHaber,hset和hget的已发布时间复杂度为O(1),那你是在说这个不正确吗? - uberdog
2
@uberdog 不好意思我的英文,Instagram在哈希映射中不会存储超过1000条记录,他们将记录ID除以1000(并丢弃余数),使用结果值设置哈希名称。 - mzalazar
1
@mzalazar 没错,谢谢你指出来。对于他们的使用场景,他们需要尽可能小的内存占用,并且在检索时负载最少,他们愿意将数据分片存储在多个键中。对于普通的Redis用户来说,我认为这样的实现是过早的优化。我仍然坚持认为,说哈希不适合存储大量数据是不正确的。Redis使用的存储哈希表的算法会根据数据的数量而变化,这是有意设计的。你可以在这里了解更多关于这种权衡的细节。 - uberdog

2
您可以将键和值作为两者组合存储
redis 127.0.0.1:6379> SET XXX:abc@yahoo.com XXX:abc@yahoo.com
OK
redis 127.0.0.1:6379> SET YYY:xyz@gmail.com YYY:xyz@gmail.com
OK
redis 127.0.0.1:6379> keys YYY:*
1) "YYY:xyz@gmail.com"
redis 127.0.0.1:6379> keys *:xyz@gmail.com
1) "YYY:xyz@gmail.com"
redis 127.0.0.1:6379> keys XXX:*
1) "XXX:abc@yahoo.com"
redis 127.0.0.1:6379> keys *:abc@yahoo.com
1) "XXX:abc@yahoo.com"

缺点:: 虽然这种方法非常快,但它会在那段时间内阻塞服务器,并且你还必须在应用程序中进行拆分。

更好的方法: : 存储两个密钥,这样你的查询将非常快,O(1),并且你不需要在应用程序级别上进行拆分。

redis 127.0.0.1:6379> SET XXX abc@gmail.com
OK
redis 127.0.0.1:6379> SET abc@gmail.com XXX
OK
redis 127.0.0.1:6379> SET YYY xyz@gmail.com
OK
redis 127.0.0.1:6379> SET xyz@gmail.com YYY
OK
redis 127.0.0.1:6379> GET XXX 
"abc@gmail.com"
redis 127.0.0.1:6379> GET abc@gmail.com
"XXX"
redis 127.0.0.1:6379> GET YYY
"xyz@gmail.com"
redis 127.0.0.1:6379> GET xyz@gmail.com
"YYY"

缺点:需要更多的空间


3
使用KEYS不是推荐的做法。第二种方法是正确的做法。 - Itamar Haber
我不同意这是最好的方法。这两种方法都会污染你的根级命名空间,并且没有提供一种检索完整电子邮件地址集或UUID集合的方式。 - uberdog

0

实现这个功能的方法是利用Redis集合的威力。由于您希望能够保留空间,因此使用哈希键以及它们的值作为反向查找集来保存索引是有意义的。

在下面的示例中,我想存储有关用户姓名、喜好和居住地的信息。然后,我希望能够进行搜索,例如“谁住在英国并喜欢威士忌?”:

> incr key:user
(integer) 1

> hmset user:1 name lloyd likes whisky lives uk
OK

> sadd user:name:lloyd 1
(integer) 1

> sadd user:likes:whisky 1
(integer) 1

> sadd user:lives:uk 1
(integer) 1

> incr key:user
(integer) 2

> hmset user:2 name ivan likes whisky lives uk
OK

> sadd user:name:ivan 2
(integer) 1

> sadd user:like:whisky 2
(integer) 1

> sadd user:likes:whisky 2
(integer) 1

> sadd user:lives:nyc 2
(integer) 1

> hmset user:2 name ivan likes whisky lives nyc
OK

> hget user:2 name
"ivan"

> sunion user:likes:whisky user:lives:uk
1) "1"
2) "2"

> sinter user:likes:whisky user:lives:uk
1) "1"

> sdiff user:likes:whisky user:lives:uk
1) "2"

> sort user:likes:whisky by weight-* GET user:*->name
1) "lloyd"
2) "ivan"

> sort user:likes:whisky by weight-* GET user:*->name GET user:*->lives
1) "lloyd"
2) "uk"
3) "ivan"
4) "nyc"

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