使用Redis排序集进行索引

Or *_*man 6 indexing sorted set nosql redis

我想得到一些反馈和建议,我正在考虑使用Redis排序集实现可搜索索引的两种方法.

情况和目标

我们目前有一些我们存储在Cassandra中的键值表,我们希望它们有索引.例如,一个表将包含人员的记录,Cassandra表将id作为其主键,序列化对象作为值.该对象将具有诸如first_name,last_name,last_updated等字段.

我们想要的是能够进行搜索,例如"last_name ='Smith'AND first_name>'Joel'","last_name <'Aaronson'","last_name ='Smith'AND first_name ='Winston'"等等.搜索应该产生匹配的ID,以便我们可以从Cassandra中检索对象.我认为上述搜索可以使用单个索引完成,按字典顺序排序为last_name,first_name和last_updated.如果我们需要使用不同顺序的某些搜索(例如"first_name ='Zeus'"),我们可以使用类似的索引来允许那些(例如first_name,last_updated).

我们正在考虑使用Redis,因为我们需要能够每分钟处理大量的写入操作.我已经阅读了Redis排序集的一些常用方法,并提出了两种可能的实现:

选项1:每个索引的单个排序集

对于last_name,first_name,last_updated的索引,我们在Redis下的密钥索引下有一个有序集:people:last_name:first_name:last_updated,其中包含格式为last_name的字符串:first_name:last_updated:id.例如:

史密斯:乔尔:1372761839.444:0azbjZRHTQ6U8enBw6BJBw

(对于分隔符,我可能会使用'::'而不是':'或其他东西来更好地处理字典顺序,但是现在让我们忽略它)

这些项目都将被赋予得分0,以便排序的集合将按字典顺序按字符串本身排序.如果我想做一个像"last_name ='smith'AND first_name <'bob'"这样的查询,我需要获取列表中'smith:bob'之前的所有项目.

据我所知,这种方法有以下缺点:

  1. 没有Redis功能可根据字符串值选择范围.这个名为ZRANGEBYLEX的功能由Salvatore Sanfilippo在https://github.com/antirez/redis/issues/324上提出,但未实现,因此我必须使用二进制搜索找到端点并自行获取范围(可能使用Lua,或者在Python的应用程序级别,这是我们用来访问Redis的语言).
  2. 如果我们想要为索引条目包含生存时间,那么最简单的方法是使用定期计划的任务遍历整个索引并删除过期的项目.

选项2:小型排序集,按last_updated排序

这种方法是类似的,除了我们会有许多较小的有序集合,每个集合都有一个类似时间的值,例如分数的last_updated.例如,对于相同的last_name,first_name,last_updated索引,我们将为每个last_name,first_name组合设置一个有序集.例如,密钥可能是索引:people:last_name = smith:first_name = joel,它将为我们称为Joel Smith的每个人创建一个条目.每个条目的id都是id,其得分是last_updated值.例如:

值:0azbjZRHTQ6U8enBw6BJBw; 得分:1372761839.444

这方面的主要优点是(a)搜索我们知道除了last_updated之外的所有字段都非常容易,并且(b)使用ZREMRANGEBYSCORE实现生存时间非常简单.

对我来说似乎非常大的缺点是:

  1. 管理和搜索这种方式似乎更加复杂.例如,我们需要索引来跟踪其所有键(例如,我们希望在某些时候清理)​​并以分层方式执行此操作.诸如"last_name <'smith'"之类的搜索需要首先查看所有姓氏的列表以查找史密斯之前的那些,然后查找每个查找它包含的所有名字的人,然后查找每个姓氏.从排序集中获取所有项目.换句话说,很多组件需要建立和担心.

包起来

所以在我看来,尽管有其缺点,但第一种选择会更好.我非常感谢有关这两个或其他可能的解决方案的任何反馈(即使他们是我们应该使用除Redis之外的其他东西).

Eli*_*Eli 7

  1. 我强烈反对使用Redis.你将存储大量额外的指针数据,如果你决定要做更复杂的查询,SELECT WHERE first_name LIKE 'jon%'那么你将遇到麻烦.如果要同时搜索两个字段,还需要设计跨越多列的额外的非常大的索引.你基本上需要不断攻击并重新设计搜索框架.你最好使用Elastic SearchSolr,或者已经构建的任何其他框架来做你想要做的事情.Redis太棒了,有很多好的用途.这不是其中的一个.

  2. 除了警告,回答你的实际问题:我认为你最好使用你的第一个解决方案的变体.每个索引使用一个有序集,但只需将字母转换为数字.将您的字母转换为某个十进制值.您可以使用ASCII值,或者只是按照字典顺序将每个字母分配给1-26值,假设您使用的是英语.标准化,以便每个字母占用相同的数字长度(因此,如果26是您的最大数字,1将写为"01").然后将这些与前面的小数点一起追加,并将其作为每个索引的得分(即"hat"将为".080120").这将使您在单词和这些数字之间进行正确排序的一对一映射.搜索时,将字母转换为数字,然后您就可以使用所有Redis了ZRANGEBYSCORE无需重写它们.Redis的功能写得非常非常优秀,所以你最好尽可能地使用它们而不是自己编写.