学习

使用 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) "dominik.schiffmann@example.com"
 9) "password"
10) "$2b$05$xbkSwODz1tWqdE7xWb393eiYIQcdiEdbbvhK88.Xr9sW7WxdI26qi"
11) "numCheckins"
12) "9353"
13) "lastCheckin"
14) "1488517098363"
15) "lastSeenAt"
16) "124"

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

  • 获取电子邮件地址为 dominik.schiffmann@example.com 的用户。
  • 查找最后出现在位置 124 的所有用户。
  • 查找签到次数在 1000 到 3000 之间的所有用户。
  • 查找给定经纬度坐标 10 英里半径范围内的所有位置,并且至少具有 3 星评级。

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

传统上,在键/值数据库中,这意味着添加代码以创建和手动更新索引。例如,要解决查询“哪个用户的电子邮件地址为 dominik.schiffmann@example.com”,我们可能会创建一个新的字符串键,其中包含该电子邮件地址,其值为用户 ID

127.0.0.1:6379> set ncc:users:byemail:dominik.schiffmann@example.com 852
OK

现在,如果我们只想根据 Dominik 的电子邮件地址获取他的用户详细信息,我们需要遵循两个步骤

  1. 1.查找与我们拥有的电子邮件地址关联的用户的用户 ID。
  2. 2.使用该用户 ID 从用户的哈希中检索值。
127.0.0.1:6379> get ncc:users:byemail:dominik.schiffmann@example.com
"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) "dominik.schiffmann@example.com"
 9) "password"
10) "$2b$05$xbkSwODz1tWqdE7xWb393eiYIQcdiEdbbvhK88.Xr9sW7WxdI26qi"
11) "numCheckins"
12) "9353"
13) "lastCheckin"
14) "1488517098363"
15) "lastSeenAt"
16) "124"

我们还需要使这些信息保持最新,并与应用程序代码中 ncc:users:852 处哈希的更改保持同步。

可以使用其他 Redis 数据类型创建其他类型的辅助索引。例如,我们可能会 使用 Redis 有序集合作为辅助索引,从而能够执行范围查询,例如“查找签到次数在 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 在每次保存代码更改时重新启动服务器)。

然后,将浏览器指向 https://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

Redis 中的查询、索引和全文搜索