我有一些产品数据需要在Redis缓存中存储多个版本。数据由JSON序列化的对象组成。获取纯(基本)数据的过程很昂贵,将其自定义为不同版本的过程也很昂贵,因此我想缓存所有版本以尽可能进行优化。数据结构如下所示:
BaseProduct
/\
/ \
/ \
/ \
/ \
CustomisedProductA CustomisedProductB
/ \ / \
CustomisedProductA1 CustomisedProductA2 CustomisedProductB1 CustomisedProductB2
这里的总体思路是:
数据以这种方式存储,因为数据检索/计算过程的每个步骤都很昂贵。第一次为某个区域检索特定产品时,将执行一组定制以使其成为特定于区域的产品。第一次为商店检索特定产品时,我需要根据区域产品执行定制以生成特定于商店的产品。
之所以出现此问题,是因为我可能需要通过以下几种方法来使数据无效:
HDEL key field
(例如HDEL product CustomisedProductA:CustomisedProductA1
)来实现此目的。 因此,我的问题是:是否有一种表示这种类型的多级数据结构的方法,以允许将数据存储在多个级别中,同时仅使树的一部分无效?或者,我是否仅限于使整个树(
DEL key
)或特定节点(HDEL key field
)失效,而两者之间什么也没有? 最佳答案
至少有3种不同的方式,每种方式各有利弊。
第一种方法是对树使用非原子性的临时扫描,以识别和取消(删除)树的第二级(第一组自定义设置)。为此,请为您的Hash字段使用层级命名方案,并使用 HSCAN
遍历它们。例如,假设哈希的键名是产品的ID(例如ProductA),则将第一个自定义版本的第一个版本的字段名使用“0001:0001”,将其第二个版本的字段使用“0001:0002”,等等。同样,'0002:0001'将是第二个自定义的第一个版本,以此类推...然后,确实找到所有自定义42的版本,使用HSCAN ProductA 0 MATCH 0042:*
, HDEL
答复中的字段,并重复直到光标归零。
相反的方法是主动“索引”每个定制的版本,以便您可以高效地获取它们,而不用执行哈希的完整扫描。解决方法是使用Redis的集合-您保留一个集合,其中包含给定产品版本的所有字段名称。版本可以是顺序的(例如在我的示例中),也可以是其他任何版本,只要它们是唯一的即可。维护这些索引的代价是-每当您添加或删除产品的自定义和/或版本时,都需要保持与这些集合的一致性。例如,创建版本将类似于:
HSET ProductA 0001:0001 "<customization 1 version 1 JSON payload"
SADD ProductA:0001 0001
请注意,这两个操作应该在单个事务中(即使用
MULTI\EXEC
块或 EVAL
Lua脚本)。进行此设置后,使自定义无效即可,只需在相关Set上调用 SMEMBERS
并从哈希(以及Set本身)中删除其中的版本即可。但是,需要特别注意的是,从大型Set中读取所有成员可能很耗时-1 K成员并没有那么糟糕,但是对于大型Set来说,存在 SSCAN
。最后,您可以考虑使用排序集而不是哈希。尽管在此用例中可能不太直观,但排序集将使您执行所需的所有操作。但是,使用它的代价是与Hash的O(1)相比,用于添加/删除/读取的O(logN)的复杂性增加了,但是给定的数字并不明显。
要释放排序集的功能,您将使用字典顺序,因此所有排序集的成员都应具有相同的分数(例如,使用0)。就像哈希一样,每种产品都将以有序集表示。 Set的成员与Hash字段的等效项,即自定义版本。 “技巧”以允许您执行范围搜索(或如果可能的话,则为2级无效)的方式构造成员。这是一个看起来像的示例(请注意,这里的键ProductA不是哈希,而是排序集):
ZADD ProductA 0 0001:0001:<JSON>
要读取自定义版本,请使用
ZRANGEBYLEX ProductA [0001:0001: [0001:0001:\xff
并从回复中拆分JSON,并使用 ZREMRANGEBYLEX
删除整个自定义。