学习以 JSON 格式存储、读取和搜索会话
最后更新时间:2024 年 4 月 23 日
目标
了解如何使用 JSON 数据类型建模存储在 Redis 中的会话。
解决方案
Redis 提供了许多高效存储和检索数据的选项;传统上,生态系统利用字符串(string)和哈希(hash)数据类型。然而,会话存储不同类型的数据:元数据、列表、地理位置和整个对象。在高并发环境中找到合适的数据结构、使用低复杂度的数据访问模式以及管理会话过期可能具有挑战性。本文档将介绍使用 JSON 数据类型实现可靠会话数据管理策略的一些想法。哈希和 JSON 数据结构经过适当转换后都可以存储对象,但对于存储多个嵌套对象而言,JSON 是一个自然的选择。在索引和搜索方面,JSON 也更灵活。
考虑以下会话数据,其中存储了会话元数据、购物车、访问过的网站列表和位置信息。
{
"lastAccessedTime":1673354843,
"creationTime":1673354843,
"cart":[
{
"itemId":"hp-2341",
"itemCost":1990.99,
"quantity":3
},
{
"itemId":"MacBook",
"itemCost":2990.99,
"quantity":15
}
],
"location":"34.638,31.79",
["www.redis.com","www.google.com"]
}
Redis 可以高效地管理 JSON 文档并支持搜索。让我们考虑一个包含某些用户数据的两个会话的示例。
JSON.SET session:a30d0c64-4cad-4088-a9ef-f1889d182df4 $ '{"lastAccessedTime":1672475765650,"creationTime":1672475765649,"user":{"name":"John","last":"Doe"},"visited":["www.redis.io","www.mortensi.com"], "location": "34.638,31.79", "cart":[{"itemId":"hp-2341","itemCost":1990.99,"quantity":2},{"itemId":"MacBook","itemCost":2990.99,"quantity":1}]}'
JSON.SET session:18920ac6-a2f0-4019-8250-e0036d17d015 $ '{"lastAccessedTime":1672475765645,"creationTime":1672475765549,"user":{"name":"Jane","last":"Appleseed"},"visited":["www.redis.io","www.microsoft.com"], "location": "35.178,31.768", "cart":[{"itemId": "invicta-jolly","itemCost":68.99,"quantity":1},{"itemId":"MacBook","itemCost":2990.99,"quantity":1}]}'
Redis 支持对 JSON 文档进行二级索引。我们可以按如下方式对会话进行索引
- 为
lastAccessedTime
和creationTime
设置NUMERIC SORTABLE
- 为访问过的 URL 集合设置
TAG
- 为 itemId 设置
TAG
- 为用户位置设置
GEO
创建索引的语法将使用 FT.CREATE 命令
FT.CREATE session_idx ON JSON PREFIX 1 session: SCHEMA $.lastAccessedTime AS lastAccessedTime NUMERIC SORTABLE $.creationTime AS creationTime NUMERIC SORTABLE $.visited[*] AS visited TAG $.cart[*].itemId AS itemid TAG $.location AS loc GEO
验证索引已创建并已索引两个文档:检查以下命令的输出
FT.INFO session_idx
并查找 num_docs
的值。
现在,我们可以使用索引对会话进行搜索。以下是搜索购物车中包含 MacBook 的所有会话的示例
FT.SEARCH session_idx '@itemid:{MacBook}' RETURN 0
1) (integer) 2
2) "session:a30d0c64-4cad-4088-a9ef-f1889d182df4"
3) "session:18920ac6-a2f0-4019-8250-e0036d17d015"
检查单个购物车中是否存在某个产品的搜索(使用 JSONPath 语法)
JSON.GET session:a30d0c64-4cad-4088-a9ef-f1889d182df4 '$.cart[?(@.itemId=="MacBook")]'
"[{\"itemId\":\"MacBook\",\"itemCost\":2990.99,\"quantity\":1}]"
搜索给定位置附近(40 公里半径范围内)会话的示例,该搜索利用了
FT.SEARCH session_idx '@loc:[34.5 31.5 40 km]' return 0
1) (integer) 1
2) "session:a30d0c64-4cad-4088-a9ef-f1889d182df4"
搜索返回最后创建的会话
FT.SEARCH session_idx "@creationTime:[-inf, +inf]" RETURN 1 creationTime LIMIT 0 1 SORTBY creationTime DESC
1) (integer) 2
2) "session:a30d0c64-4cad-4088-a9ef-f1889d182df4"
3) 1) "creationTime"
2) "1672475765649"
对于需要为集合、对象和地理位置提供紧凑会话表示,并能够执行高效的会话内和跨会话查询及搜索的用例,JSON 数据类型是一个有效且高性能的解决方案。
参考资料
阅读更多关于 Redis 对 JSON 的支持 的信息