流行的 RediSearch 模块旨在通过添加具有超快速全文搜索功能的辅助索引来扩展 Redis 的功能。RediSearch 备受好评,获得了 150,000 多次 Docker 提取、2,000 个 GitHub 星星、230 次分叉和 10 种不同语言编写的 10 个驱动程序。客户们已经开始受益,请观看此 视频,了解 GAP 如何使用 Redis 将其规模扩大 100 倍。
今天,我们很自豪地宣布推出 RediSearch 1.6,它重构了原模块来提升性能并添加了一些重要的全新功能,包括别名、低级 API 和改进的查询验证,还将 Fork 垃圾回收设为模块的默认值,所有这些设计都旨在让使用 RediSearch 进行开发更加高效便捷。
我们最初创建 RediSearch 是为了支持通过扩展 Redis 来扩展的单一(或数量有限的)辅助索引。多年来,Redis 用户已转向 RediSearch 来满足各种用例,这些用例经常在查询索引时删除和重新创建同一索引,或创建数千个小型且生命周期较短的索引。 在 RediSearch 1.6 中,我们重构了代码库,以更好地支持这些用例。在此过程中,我们添加了更好的查询验证,并将 性能提升了高达 73%!我们还添加了两个主要新功能: 别名让 Redis 可以引用现有索引并轻松切换到另一个索引,而新的低级 API使 RediSearch 可用作库,供其他用 C 或 Rust编写的 Redis 模块使用。这意味着开发人员 无需学习其他搜索查询语言即可使用任何 Redis 模块。 借助此库,模块可以轻松添加辅助索引功能。RedisGraph 2.0 是第一个公开提供的 Redis 模块,它提供全文搜索功能,以此利用此功能。RediSearch v.1.6 中添加的全部功能列表可在 GitHub上找到。
根据使用我们的全文搜索基准 (FTSB) 进行的测试,RediSearch 1.6 与版本 1.4 相比带来了显著的性能优势。具体来说,RediSearch 1.6 将简单的全文搜索吞吐量提高了高达 63%,同时将延迟 (q50) 降低了高达 64%。对于聚合查询,吞吐量提高了 15% 至 64%。
(有关 RediSearch 1.6 中性能改进的更多信息,请参阅我们在 关于 RediSearch 1.6 提升性能至多 64%上的博客文章。)
RediSearch 最强大的功能之一是,对文档进行每次更新时都会以原子操作方式更新索引。与其他基于 Lucene 的搜索引擎不同,RediSearch 索引无需追赶数据。换句话说,您始终阅读自己的写入内容。
但在某些应用程序中,重新加载整个索引比追踪两次大量加载之间的差异更有效或更便捷。在运行时将您的应用程序更新为无停机连接到新加载的索引几乎是不可能的,所以我们引进了别名,使 RediSearch 变得更加灵活和强大。值得注意的是,ElasticSearch用户会发现向 RediSearch 添加别名会简化其向 Redis 迁移的路径,如下面的示例所示。
借助别名,您可以将应用程序查询从逻辑索引名称重定向到实际的基础索引。 更新别名让您可以透明地将应用程序查询重定向到另一个实际索引,而不会出现任何停机!
此简单示例解释了 RediSearch 命令中的别名如何工作
FT.ALIASADD movies idxAredis:6379> FT.CREATE idxA SCHEMA title TEXT
OK
redis:6379> FT.ADD idxA a:doc1 1.0 FIELDS title "plump fiction"
OK
redis:6379>
plump
OK
redis:6379> FT.SEARCH movies "@title:fiction"
1) (integer) 1
2) "a:doc1"
3) 1) "title"
2) "
FT.ALIASUPDATE movies idxB fiction"
redis:6379> FT.CREATE idxB SCHEMA title TEXT
OK
redis:6379> FT.ADD idxB b:doc1 1.0 FIELDS title "pulp fiction"
OK
redis:6379>
pulp
OK
redis:6379> FT.SEARCH movies "@title:fiction"
1) (integer) 1
2) "b:doc1"
3) 1) "title"
2) " fiction"
未来,有机会通过为多个索引创建别名的功能增强此特性,例如,用于解决查询负责一组不同文档的两个索引的问题。
自创建 Redis 的模块 API 以来,Redis 和 Redis 社区创建了一大批模块。某些模块会向 Redis 添加全新的数据库模型,某些模块允许你配合数据执行代码,而有些模块会向 Redis 添加新的数据结构。但我们注意到,有几款模块开始构建其编制数据索引的专有方式。例如,在 RedisGraph 中,图表中节点属性上的索引在压缩列表中维护,而 RedisTimeSeries 利用有序集合查询符合特定标签条件的时间序列数据。
这些实现提供基本搜索功能,但对于 RediSearch 1.6,我们希望在关键使用案例中消除代码复制并通过 通用的查询语言 增强搜索功能。例如,在图表数据库中,针对节点属性开展模糊搜索以启用图表辅助搜索是比较常见的。与此同时,时间序列使用案例通常涉及所有时间序列,其中某个标签匹配某个前缀。其他 Redis 模块能够从二级编制索引支持中受益。试想一下,如果 RedisJSON 具备全文本搜索功能,你能做些什么!
所以,对于 RedisSearch 1.6,我们创建了一个低级别 API,供其他 Redis 模块使用。RedisGraph v2.0 是第一个使用此模块的通用 Redis 模块。图表辅助搜索让你能够在图表中查找与全文本搜索查询匹配的属性的节点,并根据这些节点在图表中的连接情况对它们进行排名。
LinkedIn 的搜索功能 是图表辅助搜索的一个优秀示例:与你在网络中关系较为密切的人和公司在搜索结果中显示的排名更高。我们继续开展 RedisTimeSeries 的低级别 API 开发工作,你已经可以试用 RedisJSON 2.0 的预览版,其中嵌入了 RediSearch。
与大多数基于反向索引的搜索引擎类似,当您删除或更新文档时,RediSearch 会有效地将该文档标记为要删除。垃圾回收流程定期运行以回收用于存储已删除文档的内存。将文档标记为已删除并使物理删除成为异步过程可减少命令执行时间,同时保留查询的正确性。
在 RediSearch 1.4 中,默认行为是锁定主线程,这会在垃圾回收过程中导致读取延迟高峰。为了克服这个问题,RediSearch 1.4 提供了一个可选的Fork GC,它与主查询进程并行运行,允许扫描所有已删除的文档而不会中断。这种方法为高流量环境(发出大量查询和/或执行大量写入)提供了卓越的性能,因此我们已将此行为设为 RediSearch 1.6 中的默认行为。
您可以在此两阶段测试中看到Fork GC的好处。在第一阶段,我们插入 1000 万份新文档。在此阶段之后,我们将删除索引。在第二阶段,流量是混合的:插入和更新 500 万份文档。但是,对于每项写入操作,也存在更新操作(更新率为 50%),因此这总计也为 1000 万项操作。
该图表清楚地显示了更新率为 50% 时传统垃圾回收性能如何快速下降。总体而言,我们观察到,使用新的Fork 垃圾回收,在低更新率下性能提升了 8%,在高更新率下性能提升了 70%。
最后,RediSearch 1.6 还改进了查询验证。如果确定查询包含逻辑或语法错误,则会向用户返回适当的错误消息,而不是让查询在不产生结果的情况下执行。当提交无法识别的关键字时,RediSearch 1.6 也会返回错误。此查询验证将增强开发人员体验,并降低 RediSearch 的学习曲线。同时请注意,RediSearch 1.6 受我们最近宣布的基于浏览器的 Redis 部署管理界面RedisInsight支持。
展望未来,我们在路线图中有许多有趣的功能,例如支持多边形搜索和为单个分片上的读取查询创建更高的并行性。这将帮助我们在不增加分片数量的情况下实现更高的聚合查询吞吐量。
除了新功能之外,最重要的便是,1.6 版是 RediSearch 迄今为止最快速的版本(在此了解 RediSearch 1.6 性能改进的更多信息)。在所有类型的查询中,你的应用程序都会带来更稳定的延迟,并且峰值更少。
最后,我们要感谢 Redis 社区成员,他们的帮助让 RediSearch 1.6 更加强大,方法是在早期候选版本中发现 bug。