学习以 JSON 格式存储、读取和搜索会话

最后更新时间:2024 年 4 月 23 日

目标

了解如何使用 JSON 数据类型对存储在 Redis 中的会话进行建模。

解决方案

Redis 提供了许多选项来有效地存储和检索数据;传统上,生态系统利用字符串和哈希数据类型。但是,会话存储不同类型的数据:元数据、列表、地理位置和整个对象。在高并发环境中找到正确的数据结构、使用低复杂度的数据访问模式以及管理会话过期可能会很困难。本文档将介绍使用 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 文档的二级索引。我们可以按如下方式索引会话

  • NUMERIC SORTABLE 用于 lastAccessedTimecreationTime
  • TAG 用于已访问 URL 的集合
  • TAG 用于 itemId
  • 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 支持