搜索redis数据库的值

Tam*_*mas 18 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...}
Run Code Online (Sandbox Code Playgroud)

解决方案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.
Run Code Online (Sandbox Code Playgroud)

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

此外,这使用了比所需更多的空间,并且KEY命令恶化了访问性能.(http://redis.io/commands/keys)

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

也请提前感谢,问候,Tamas

答案摘要: 实际上,两个回复都说明Redis不是设计用于搜索键的值.如果这个用例是必要的,那么需要根据我的原始解决方案或下面的解决方案中的方法实现任何变通方法.

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

这种解决方案的缺点是,它比我的消耗更多的空间,并且无法搜索起始数字只知道的电话号码.

感谢您的回复.

Eli*_*Eli 24

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...}
Run Code Online (Sandbox Code Playgroud)

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

HGETALL 'phone:123-456-7891'
Run Code Online (Sandbox Code Playgroud)

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

for id in results:
    HGET id 'name'
Run Code Online (Sandbox Code Playgroud)

你在这里的成本将O(m)在那里m与给定的电话号码用户的数量,这将是因为如何优化它是速度上的Redis一个非常快的操作.在你的情况下它会有点过分,因为你可能不需要事情这么快,你更喜欢灵活的搜索,但这就是你要做的.


raf*_*ian 8

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

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

要搜索字符串,请在redis和其他很酷的东西中构建自动完成 ...
如何在redis中搜索字符串?

在内部文档中搜索时,为什么在redis上使用MongoDB是明智的 ... 什么是最有效的面向文档的数据库引擎来存储数千个中等大小的文档?


slo*_*llo 3

Redis 中的原始二级索引

这里接受的答案是正确的,因为在 Redis 中处理搜索的传统方法是通过围绕集合和排序集构建的二级索引。

例如

HSET Person:1 firstName Bob lastName Marley age 32 phoneNum 8675309
Run Code Online (Sandbox Code Playgroud)

您将维护二级索引,因此您必须致电

SADD Person:firstName:Bob Person:1
SADD Person:lastName:Marley Person:1
SADD Person:phoneNum:8675309 Person:1
ZADD Person:age 32 Person:1
Run Code Online (Sandbox Code Playgroud)

这允许您现在执行类似搜索的操作

例如

SELECT p.age
FROM People AS p
WHERE p.firstName = 'Bob' and p.lastName = 'Marley' and p.phoneNum = '8675309'
Run Code Online (Sandbox Code Playgroud)

变成:

ids = SINTER Person:firstName:Bob Person:lastName:Marley Person:phoneNum:8675309

foreach id in ids:
   age = HGET id age
   print(age)
Run Code Online (Sandbox Code Playgroud)

这种方法的主要挑战是,除了设置相对复杂(它确实迫使您考虑您的模型)之外,原子维护也变得极其困难,特别是在分片环境中(在这种环境中,跨分片键约束可能会变得复杂)有问题的)因此,键和索引可能会分开,迫使您必须定期循环并重建索引。

使用 RediSearch 的新二级索引

警告:这使用 RediSearch,这是 Redis 源可用许可证下提供的 Redis 模块

有一个插入 Redis 的新模块,可以为您完成所有这些工作,称为RediSearch。这可以让您声明二级索引,然后在您插入时为您索引所有内容。对于上面的例子,你只需要运行

FT.CREATE person-idx ON HASH PREFIX 1 Person: SCHEMA firstName TAG lastName TAG phoneNumber TEXT age NUMERIC SORTABLE
Run Code Online (Sandbox Code Playgroud)

这将声明索引,之后您需要做的就是将内容插入到 Redis 中,例如

HSET Person:1 firstName Bob lastName Marley phoneNumber 8675309 age 32
Run Code Online (Sandbox Code Playgroud)

然后你可以运行:

FT.SEARCH person-idx "@firstName:{Bob} @lastName:{Marley} @phoneNumber: 8675309 @age:[-inf 33]"
Run Code Online (Sandbox Code Playgroud)

要返回与模式匹配的所有项目,请参阅查询语法以获取更多详细信息