我是Redis DB的新手。在阅读了一些文档,查看了互联网上的一些示例,并浏览了www.example.com之后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术语说)。
这种解决方案的缺点是,它比我的占用空间大得多,并且电话号码的起始数字只知道,无法搜索。
感谢两个答案。
4条答案
按热度按时间htrmnn0y1#
Redis适用于需要以非常高的频率访问和更新数据的用例,并且您可以从数据结构(哈希,集合,列表,字符串或排序集合)的使用中受益。它是为了满足非常具体的用例而设计的。如果你有一个通用的用例,比如非常灵活的搜索,你会更好地为这个目的而构建的东西,比如ElasticSearch或SOLR。
也就是说,如果你必须在Redis中这样做,下面是我的方法(假设用户可以共享姓名和电话号码):
字符串
在本例中,我们为每个姓名(前缀为“name:”)和每个电话号码(前缀为“phone:”)创建一个新键。每个key都指向一组id,其中包含您想要的用户的所有信息。例如,当您搜索电话时,您将执行以下操作:
型
然后循环遍历结果,并以您选择的语言返回每个(在我们的示例中是名称)的任何信息(如果您愿意,您可以在Redis框上的服务器端Lua中完成整个事情,以更快地完成并避免网络来回):
型
这里的成本是
O(m)
,其中m
是给定电话号码的用户数,这在Redis上是一个非常快的操作,因为它是如何优化速度的。在您的情况下,这将是矫枉过正,因为您可能不需要事情进行得如此之快,并且您更喜欢灵活的搜索,但这就是您如何做到这一点。kzmpq1sx2#
redis很棒,但它不是为搜索键以外的任何东西而构建的。如果不构建额外的数据集来存储项以方便查询,您就无法查询值,但即使这样,您也无法获得真正的搜索,只是更多的维护,内存的低效使用,yada,yada...
这个问题已经解决了,你有一些阅读要做:-D
要搜索字符串,在redis和其他很酷的东西中构建自动完成...
How do I search strings in redis?
为什么在搜索文档时使用MongoDB而不是redis是明智的... What's the most efficient document-oriented database engine to store thousands of medium sized documents?的
s4n0splo3#
Redis原始二级指数
这里公认的答案是正确的,因为在Redis中处理搜索的传统方式是通过围绕集合和排序集合构建的secondary indices。
例如,在
字符串
您将维护二级索引,因此必须调用
型
这使您现在可以执行类似搜索的操作
例如,在
型
变成:
型
这种方法的关键挑战是,除了设置相对复杂(它确实迫使你考虑你的模型)之外,原子地维护变得非常困难,特别是在分片环境中(跨分片键约束可能会成为问题),因此键和索引可能会漂移,迫使你定期循环并重建索引。
RediSearch新增二级索引
警告:这使用RediSearch一个Redis模块,该模块在Redis Source Available许可证下可用
有一个新的模块可以插入Redis,它可以为你做所有这些,叫做RediSearch,它可以让你声明二级索引,然后在你插入的时候为你索引所有的东西。对于上面的示例,您只需要运行
型
这将声明索引,之后你需要做的就是将内容插入Redis,例如。
型
然后你可以运行:
型
要返回与模式匹配的所有项,请参阅query syntax以了解更多详细信息
qij5mzcb4#
zeeSQL
是一个新颖的Redis模块,具有SQL和二级索引功能,允许通过Redis键的值进行搜索。您可以将其设置为跟踪所有散列的值并将它们放入标准SQL表中。
对于通过电话号码和姓名搜索人员的示例,您可以执行以下操作。
字符串
此时,
zeeSQL
将跟踪所有以customer
开头的散列,并将它们放入SQL表中。它将字段id
存储为整数,name
存储为字符串,phone
存储为字符串。您可以简单地将哈希值添加到Redis中来填充表,
zeeSQL
将保持所有内容同步。型
此时,您可以查看客户表,您将找到所需的结果。
型
结果首先指定列的名称,然后指定列的类型,最后指定实际的结果集。
zeeSQL基于SQLite,它支持用于过滤和聚合的所有SQLite语法。
例如,您可以搜索只知道其电话号码前缀的人。
型
您可以在教程中找到更多示例:https://doc.zeesql.com/tutorial#using-secondary-indexes-or-search-by-values-in-redis