学习

使用 Redis 进行索引和查询

Simon Prickett
作者
Simon Prickett, Redis 首席开发者布道师

我们选择将用户和位置数据存储在 Redis 哈希中。哈希非常适合存储领域对象。回想一下,我们选择将每个用户存储在一个键包含用户 ID 的哈希中。例如,这是在 RedisInsight 中看到的用户 852

如果你使用 redis-cli,可以使用 HGETALL 命令查看用户 852:

127.0.0.1:6379> hgetall ncc:users:852
 1) "id"
 2) "852"
 3) "firstName"
 4) "Dominik"
 5) "lastName"
 6) "Schiffmann"
 7) "email"
 8) "[email protected]"
 9) "password"
10) "$2b$05$xbkSwODz1tWqdE7xWb393eiYIQcdiEdbbvhK88.Xr9sW7WxdI26qi"
11) "numCheckins"
12) "9353"
13) "lastCheckin"
14) "1488517098363"
15) "lastSeenAt"
16) "124"

将数据存储在哈希中意味着,只要知道键,我们就可以轻松有效地检索哈希的内容。因此,查找用户 852 非常简单,但我们如何执行以下任何操作呢?

  • 获取邮箱地址为 [email protected] 的用户。
  • 查找最后出现在位置 124 的所有用户。
  • 查找签到次数在 1000 到 3000 之间的所有用户。
  • 查找给定经纬度坐标 10 英里半径范围内且评级至少为 3 星的所有位置。

Redis 是一个键值数据库。这意味着它的数据模型针对按键检索进行了优化。上面的查询仅知道哈希键无法解决 - 我们需要其他机制来索引数据。

在传统的键值数据库中,这意味着添加代码来创建和手动更新索引。例如,要解决“哪个用户拥有邮箱地址 [email protected]”的查询,我们可以创建一个包含该邮箱地址的新 String 键,其值为用户 ID

127.0.0.1:6379> set ncc:users:byemail:[email protected] 852
OK

现在,如果我们只知道 Dominik 的邮箱地址想要获取其用户详细信息,我们需要执行以下两个步骤

  1. 1.查找与我们拥有的邮箱地址关联的用户 ID。
  2. 2.使用该用户 ID 从用户的哈希中检索值。
127.0.0.1:6379> get ncc:users:byemail:[email protected]
"852"
127.0.0.1:6379> hgetall ncc:users:852
 1) "id"
 2) "852"
 3) "firstName"
 4) "Dominik"
 5) "lastName"
 6) "Schiffmann"
 7) "email"
 8) "[email protected]"
 9) "password"
10) "$2b$05$xbkSwODz1tWqdE7xWb393eiYIQcdiEdbbvhK88.Xr9sW7WxdI26qi"
11) "numCheckins"
12) "9353"
13) "lastCheckin"
14) "1488517098363"
15) "lastSeenAt"
16) "124"

我们还需要在应用代码中自行保持此信息与 ncc:users:852 的哈希更改同步并保持最新。

可以使用其他 Redis 数据类型创建其他类型的二级索引。例如,我们可以 使用 Redis Sorted Set 作为二级索引,允许我们执行范围查询,例如“查找签到次数在 1000 到 3000 之间的所有用户”。同样,我们必须在应用代码中自行填充和维护这个额外的数据结构。

Redis Stack 为我们解决了所有这些问题以及更多问题。它为 Redis 添加了一个索引、查询和全文搜索引擎,该引擎自动跟踪索引哈希中数据的变化。Redis Stack 提供了一种灵活的查询语言,可以回答诸如“查找加州奥克兰 10 英里范围内所有评级至少为 3 星且签到次数超过 200 次的健身房”之类的问题,而无需在应用中添加代码来构建或维护二级数据结构。

观看视频,了解如何在我们的 Node.js 示例应用中使用 Redis Stack。

编码练习#

在本练习中,你将完成实现一个使用 Redis 返回最后签到在给定位置的所有用户的路由。

使用你的 IDE 打开 node-js-crash-course 文件夹,并找到文件 src/routes/user_routes.js

在此文件中,你将看到一个部分实现的路由 /users/at/:locationId。要完成此练习,你需要替换此行

const searchResults = await redis.performSearch(
  redis.getKeyName('usersidx'),
  'TODO... YOUR QUERY HERE',
);

替换为包含正确查询的行,该查询返回其“lastSeenAt”字段设置为 locationId 值的用户。你需要为此使用“数字范围”语法,因为“lastSeenAt”字段被索引为数字。请务必查看 Redis 的 查询语法文档 以获取帮助。

要测试你的代码,请确保 API 服务器组件正在运行

$ npm run dev

(记住,这将使用 nodemon 在你保存代码更改时自动重启服务器)。

然后,在浏览器中访问 http://localhost:8081/api/users/at/33。如果你的查询正确,你应该会看到类似于以下的输出(实际用户可能不同,只需确保每个用户的 lastSeenAt 值与你提供的位置 ID 相符 - 在本例中为 33)

[
  {
    "id": "238",
    "firstName": "Jonas",
    "lastName": "Nielsen",
    "numCheckins": "7149",
    "lastCheckin": "1515248028256",
    "lastSeenAt": "33"
  },
  {
    "id": "324",
    "firstName": "Frans",
    "lastName": "Potze",
    "numCheckins": "8623",
    "lastCheckin": "1515976232073",
    "lastSeenAt": "33"
  },
  ...
]

为了帮助你开发查询,请使用 RedisInsight 工作台中的任一指南,或阅读更多关于 FT.SEARCH 命令 的信息。

外部资源#

使用 Express + Redis Stack 以 RESTful 方式查找大脚怪