搜索redis数据库的值

时间:2013-06-19 13:56:21

标签: redis

我是使用Redis DB的新手。在阅读了一些文档并查看了互联网上的一些示例以及扫描stackoverflow.com之后,我可以看到Redis速度非常快,扩展性很好,但这需要我们考虑我们的数据将如何定价的代价。在设计时访问它们以及它们将要经历的操作。我可以理解这一点,但我对使用普通的旧SQL在数据中搜索什么是如此简单,无论多么缓慢感到困惑。我可以用KEY命令以一种方式完成它,但它是O(N)操作而不是O(log(N))。所以我会失去Redis的一个优点。

更有经验的同事在这里说什么?

让我们举个例子:我们需要存储大约的个人数据。需要按姓名,电话号码

搜索100.000人和这些数据

为此,我将使用以下结构:

1. SET for storing all persons' ids {id1, id2, ...} 
2. HASH for each person to store personal data and name it 
like map:<id> e.g. map:id1{name:<name>, phone:<number>, etc...}

解决方案1:

1. HASH for storing all persons' ids but the key should be the phone number
2. Then with the command KEY 123* all ids could be retrieved who have a phone number 
sarting with 123. On basis of the ids also the other personal data could be retrieved.
3. So forth for each data to be searched for a separate HASH should be created.

但此解决方案的主要缺点是属性值也必须是唯一的,因此电话号码和HASH中的ID的分配将是毫不含糊。另一方面, O(N)运行时并不理想。

此外,这会占用更多空间,而 KEY命令会降低访问性能。http://redis.io/commands/keys

应该如何以正确的方式完成?我还可以想象,这些ID会进入ZSET,所需的搜索数据可能是得分,但这只能用于不使用seraches的范围。

也提前感谢,问候,Tamas

答案摘要: 实际上,两个响应都声明Redis不是设计用于搜索键的值。如果需要此用例,则需要实施变通办法,如我原始解决方案或以下解决方案中所示。

Eli的以下解决方案比原来的具有更好的性能,因为对密钥的访问可以被认为是常量,只需要迭代ID列表,以便访问这将给出 O(const)运行时。此数据模型还允许一个人可能拥有与其他人相同的电话号码等等也可以用于姓名等...所以 1-n关系也是可能的(我会说旧的ERD术语)。

此解决方案的缺点是,消耗的空间比我的起始数字仅知道的电话号码,无法搜索< /强>

感谢您的回复。

3 个答案:

答案 0 :(得分:23)

Redis适用于需要以非常高的频率访问和更新数据的用例,以及使用数据结构(散列,集合,列表,字符串或有序集)的情况。它是为了填补非常具体的用例。如果你有一个非常灵活的搜索的一般用例,你可以通过弹性搜索或SOLR为此目的提供更好的服务。

那就是说,如果你必须在Redis中这样做,我就是这样做的(假设用户可以共享姓名和电话号码):

name:some_name -> set([id1, id2, etc...])
name:some_other_name -> set([id3, id4, etc...])

phone:some_phone -> set([id1, id3, etc...])
phone:some_other_phone -> set([id2, id4, etc...])

id1 -> {'name' : 'bob', 'phone' : '123-456-7891', etc...}
id2 -> {'name' : 'alice', 'phone' : '987-456-7891', etc...}

在这种情况下,我们为每个名称(前缀为“name:”)和每个电话号码(前缀为“phone:”)创建一个新密钥。每个键指向一组id,其中包含用户所需的所有信息。例如,当您搜索电话时,您将执行以下操作:

HGETALL 'phone:123-456-7891'

然后遍历结果并以您选择的语言返回每个(我们示例中的名称)的任何信息(您可以在Redis框中的服务器端Lua中执行此操作,以更快地进行,并避免网络返回 - 如果你愿意的话):

for id in results:
    HGET id 'name'

此处的费用为O(m),其中m是具有给定电话号码的用户数量,这对Redis来说是一个非常快速的操作,因为它对速度的优化程度如何。在你的情况下它会有点过分,因为你可能不需要事情这么快,你更喜欢灵活的搜索,但这就是你要做的。

答案 1 :(得分:8)

redis非常棒,但它并不是为了搜索键以外的任何东西而构建的。您只是无法查询值而无需构建额外的数据集来存储项目以方便此类查询,但即便如此,您也无法获得真正的搜索,只需更多维护,内存使用效率低下,yada,yada ......

这个问题已经解决,你有一些阅读要做:-D

要搜索字符串,请在redis和其他很酷的东西中构建自动完成 ...
How do I search strings in redis?

在搜索内部文档时,为什么在redis上使用MongoDB很聪明 ... What's the most efficient document-oriented database engine to store thousands of medium sized documents?

答案 2 :(得分:1)

zeeSQL 是一个新颖的 Redis 模块,具有 SQL 和二级索引功能,允许按 Redis 键的值进行搜索。

您可以将其设置为跟踪所有哈希值并将其放入标准 SQL 表中。

对于通过电话号码和姓名搜索人员的示例,您可以执行类似的操作。

> ZEESQL.CREATE_DB DB
"OK"
> ZEESQL.INDEX DB NEW PREFIX customer:* TABLE customer SCHEMA id INT name STRING phone STRING

此时 zeeSQL 将跟踪所有以 custumer 开头的哈希并将它们放入 SQL 表中。它将字段 id 存储为整数,name 存储为字符串,phone 存储为字符串。

您只需将哈希值添加到 Redis 即可填充表,zeeSQL 将使所有内容保持同步。

> HMSET customer:1 id 1 name joseph phone 123-345-2345
> HMSET customer:2 id 2 name lukas phone 234-987-4453
> HMSET customer:3 id 3 name mary phone 678-443-2341 

此时您可以查看客户表,您将找到您要查找的结果。

> ZEESQL.EXEC DB COMMAND "select * from customer"
1) 1) RESULT
2) 1) id
2) 2) name
2) 3) phone
3) 1) INT
3) 2) STRING
3) 3) STRING
4) 1) 1
4) 2) joseph
4) 3) 123-345-2345
5) 1) 2
5) 2) lukas
5) 3) 234-987-4453
6) 1) 3
6) 2) mary
6) 3) 678-443-2341

结果首先指定列的名称,然后是列的类型,最后是实际的结果集。

zeeSQL 基于 SQLite,它支持所有用于过滤和聚合的 SQLite 语法。

例如,您可以搜索只知道电话号码前缀的人。

> ZEESQL.EXEC DB COMMAND "select name from customer where phone like 678%"
1) 1) RESULT
2) 1) name
3) 1) STRING
4) 1) mary

您可以在教程中找到更多示例:https://doc.zeesql.com/tutorial#using-secondary-indexes-or-search-by-values-in-redis