indexing - 使用Redis排序集建立索引

标签 indexing nosql redis set sorted

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

情况和客观

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

我们想要的是能够进行搜索,例如“last_name ='Smith'AND first_name>'Joel'“,” last_name <'Aaronson'“,” last_name ='Smith'和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中的键index:people:last_name:first_name:last_updated下设置一个排序集,其中包含格式为last_name:first_name:last_updated:id的字符串。例如:

史密斯:joel:1372761839.444:0azbjZRHTQ6U8enBw6BJBw

(对于分隔符,我可以使用'::'而不是':'或其他可以更好地按字典顺序使用的方法,但现在暂时忽略它)

所有项目的评分都为0,因此排序后的集合将仅按字符串本身的字典顺序进行排序。然后,如果我想执行“last_name ='smith'AND first_name <'bob'”之类的查询,则需要获取列表中'smith:bob'之前的所有项目。

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

  • 没有Redis函数可根据字符串值选择范围。该功能称为ZRANGEBYLEX,是Salvatore Sanfilippo在https://github.com/antirez/redis/issues/324上提出的,但尚未实现,因此,我将不得不使用二进制搜索来找到端点,并自己获取范围(也许使用Lua,或者在应用程序级使用Python,是我们用来访问Redis的语言)。
  • 如果我们想为索引条目添加生存时间,似乎最简单的方法是执行一个定期计划的任务,该任务遍历整个索引并删除过期的项目。

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

    这种方法将是相似的,不同的是我们将有许多较小的排序集,每个集合都有类似时间的值,例如分数的last_updated。例如,对于相同的last_name,first_name,last_updated索引,我们将为每个last_name,first_name组合设置一个排序集。例如,键可能是index:people:last_name = smith:first_name = joel,并且对于我们称为Joel Smith的每个人都有一个条目。每个条目将以id作为其名称,并将last_updated值作为其分数。例如。:

    值:0azbjZRHTQ6U8enBw6BJBw;得分:1372761839.444

    这样做的主要优点是:(a)我们知道除last_updated之外的所有字段都非常容易,并且(b)使用ZREMRANGEBYSCORE实现生存时间将非常容易。

    缺点对我来说似乎很大:
  • 用这种方式进行管理和搜索似乎要复杂得多。例如,我们将需要索引来跟踪其所有键(例如,在某些情况下,我们希望进行清理)并以分层的方式进行。诸如“last_name <'smith'”之类的搜索将需要首先查看所有姓氏列表,以查找史密斯之前的名字,然后针对每个查看其包含的所有名字的人,然后针对每个名字从排序集中获取所有项目。换句话说,很多组件需要建立和担心。

  • 打包

    因此,在我看来,尽管有缺点,第一种选择还是会更好。非常感谢您对这两个或其他可能的解决方案的反馈(即使它们是我们应该使用Redis以外的其他方式)。

    最佳答案

  • 我强烈建议您不要使用Redis。您将存储大量额外的指针数据,并且,如果您决定要执行更复杂的查询,例如SELECT WHERE first_name LIKE 'jon%',您将遇到麻烦。如果您想同时搜索两个字段,则还需要设计跨多个列的额外的非常大的索引。从本质上讲,您将需要继续努力并重新设计搜索框架。您最好使用Elastic SearchSolr,或者已经建立用于执行您要执行的操作的任何其他框架。 Redis很棒,并且有很多很好的用途。这不是其中的一个。
  • 除了警告,还请回答您的实际问题:我认为最好使用第一个解决方案的变体为您服务。每个索引使用一个单独的排序集,但只需将字母转换为数字即可。将您的字母转换为十进制值。您可以使用ASCII值,也可以仅按字母顺序将每个字母分配给1-26值(假设您使用的是英语)。标准化,以使每个字母占用相同的数字长度(因此,如果26是您的最大数字,则将1写入“01”)。然后只需将它们加上前面的小数点,然后将其用作每个索引的分数(即“帽子”为“.080120”)。这将使您在单词和这些数字之间具有正确排序的1对1映射。搜索时,将字母转换为数字,然后您就可以使用Redis所有不错的排序集函数(例如ZRANGEBYSCORE),而无需重写它们。 Redis的功能非常非常理想地编写,因此最好在可能的情况下使用它们而不是编写自己的函数。
  • 关于indexing - 使用Redis排序集建立索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17431719/

    相关文章:

    mysql - MySQL 中是否可以有基于函数的索引?

    c++ - Boost multi_index unqiue 索引问题

    database - 存储时间序列数据的简单方法

    node.js - Mongoose 填充不填充嵌套数组数据

    mysql - 带 mysql 和 redis 的 Tornado websockets

    python - Pandas DataFrame 索引属于一个集合

    postgresql - PostgreSQL 的 pg_stat_all_indexes 表中的统计信息存储多长时间?

    nosql - 在 Elastic Search 上查询多级嵌套字段

    ruby redis 客户端扫描与 key

    symfony - 在 Symfony 上设置 Redis 缓存前缀键