dot Redis 8 已发布,并且它是开源的

了解更多

关于短暂搜索的案例

假设您正在开发一个销售家居装修产品(如钉子、螺丝、木材、瓷砖、油灰刀等)的电商网站。这类商店(实体店或在线商店)通常销售种类繁多的产品。值得注意的是,当顾客从这类商店购买商品后,将来很可能还需要购买相同的物品——因为谁也不知道一个项目到底需要多少钉子?

提供快速易用的购买历史记录对于提供良好的用户体验至关重要,但细节决定成败。一种简单的方法是按时间倒序排列物品列表,但这在物品数量不多时尚可,但随着数量增加会令人沮丧。客户真正需要的是一种有效搜索单个用户购买历史记录的方法。 

一种方法是保留您库存过的所有产品列表,为每个物品关联数据库表中的一行,并在关系数据库系统上进行简单的全文搜索。遗憾的是,与真正的全文搜索引擎相比,关系数据库的全文搜索功能往往有所欠缺。 

另一种选择是使用真正的搜索引擎,它使用一个搜索索引来存储用户的姓名以及产品名称、描述和购买时间——每一项都作为一个文档。如果将搜索结果限定到特定用户,这将为您提供真正的全文搜索功能。不幸的是,这种方法很难实现,因为每一次购买都会在同一个索引中添加越来越多的内容,导致索引的大小迅速增长,而且每一次搜索都需要查询所有用户的所有购买记录。让我们评估一下索引会有多大

客户数量每位客户平均购买商品数量文档数量
500,00015075,000,000

即使用户数量相对适中,这种类型的索引也会迅速失控。当您拥有五百万用户时会发生什么?一千五百万用户呢? 

此功能的使用模式非常有趣——在所有用户中,任意给定时间的使用量可能呈相当正常的分布。不考虑清醒时间,可以假设它不会出现激增。横向思考,单个用户使用此功能的频率可能非常低。事实上,在大多数情况下,每个用户每周在您的电商平台花费的时间不超过几分钟。在任意给定时间,只有一小部分搜索索引正在被使用。虽然通用网站搜索可能应该随时向所有用户开放,但购买历史搜索本质上是一个仅限登录用户的功能。

那么,如果我们能为每个用户创建一个动态搜索索引会怎样——当用户登录网站时,从另一个数据存储中填充购买历史搜索数据,然后标记在特定时间后过期,就像他们的会话一样?如果用户手动退出登录,则可以安全地删除搜索索引。 

这种模式需要一个支持以下功能的搜索引擎:

  • 轻量级的索引创建和删除
  • 索引过期
  • 快速文档索引

如果您拥有所有这些功能,它能为您带来什么?让我们重新审视简单的数学计算,但再增加一个假设:在任意给定时间,有 2% 的用户已登录。 

500,000 的 2%每位客户平均购买商品数量文档数量
10,000 活跃用户1501,500,000

这个文档数量比原始策略更容易管理得多。此外,它基于您网站的实际使用量进行扩展,而不是累积购买历史记录。因此,如果您的网站变得更繁忙(通常是一件好事),那么您可以随着业务增长而相应扩展购买历史搜索功能。

由于购买历史记录不经常变化,图中的其他数据存储不需要非常复杂或高性能——您仅在用户登录或购买商品时访问它。它可以像一个平面文件一样简单。

在 Search and Query 中的短暂性

既然您正在 Redis 网站上阅读本文,您可能会想到可以使用 Search and Query 来实现这种模式。确实,Redis 有几个特性和功能非常适合此用例。首先,由于 Search and Query 是 Redis 的一项功能,它继承了 Redis 本身的大部分性能。与 Redis 一样,Search and Query 也是内存优先的,这意味着写入和读取的性能更加均衡,不像基于磁盘的系统那样修改或删除数据需要更长时间。将购买历史记录快速填充到 Search and Query 不会成为性能问题。此外,Search and Query 经过优化,可以快速创建索引以及删除或使索引过期。

更深入地探讨一下,让我们看看如何按用户创建索引

> FT.CREATE history:user:1234 TEMPORARY 3600 SCHEMA title TEXT description TEXT purchased NUMERIC

创建此索引唯一不寻常之处在于 TEMPORARY 参数。这告诉 Search and Query 使搜索索引成为短暂的,并在指定的 3600 秒后(或与您的会话超时时间一致的时间)删除它。任何时候使用搜索索引(添加/删除文档或查询)都会重置空闲计时器。时间一到期,索引就会被删除。另外,请注意索引名称包含用户标识符。

登录时,将使用来自其他数据源的 FT.ADD 填充索引。此处无需特殊操作——Search and Query 会自动将文档和键处理为临时性的,无需其他语法。添加文档将非常快速——对于大多数文档来说,延迟在几毫秒以内。这不必同步完成,因此当用户首次浏览网站时,购买历史可以在后台加载。 

关于 Search and Query 的一个一般性说明需要重申,尤其是在这种多索引上下文中:所有文档名称在所有索引中都应是唯一的,以防止哈希级别出现键冲突。最后,在某些情况下,您可以通过在 FT.ADD 上使用 NOSAVE 选项来节省空间。这不会存储文档本身,而只会对其进行索引,仅在 FT.SEARCH 时提供文档 ID,但这会使结果检索过程复杂化。

实现搜索功能本身很简单。将用户输入作为 FT.SEARCH 的查询参数。与任何 Search and Query 实现的唯一区别在于,索引名称将以某种方式从用户标识符派生。

当用户显式退出服务时,FT.DROP 命令会删除索引和文档。严格来说,这不是必需的操作,因为 TEMPORARY 索引会自动过期,但使用显式的 FT.DROP 可以更快地释放资源。

电商以外的短暂搜索应用

这种特定模式并不仅限于电商应用。任何时候,只要您需要为特定用户搜索一组个性化文档,这都是一种可行的模式。想象一下金融门户网站的发票或账单搜索。每个用户只会拥有少量与他们相关的文档,但搜索体验对于查找特定信息至关重要。同时,在消息应用中,您可能需要搜索聊天记录,这同样只有在使用应用时才需要,并且此搜索仅针对单个用户的聊天记录。

这种模式提供了一种优化用户体验的方法,而无需创建庞大、笨重的全局索引,这种索引可能难以维护和扩展。这种能力依赖于创建许多具有过期功能的轻量级索引以及快速即时索引文档的能力。 

要开始使用此模式,请在 redisearch.io 下载 Redis,或在 Redis University 学习 Redis Search and Query。