使用Redis在有限范围内生成唯一ID

时间:2018-12-06 12:50:27

标签: algorithm redis sparse-matrix

我有一些数据库项目,除了它们的主键外,还需要一个对于项目所属的组唯一的索引。我们将其称为属性nbr,并将该属性分组在一起并定义唯一的nbr:s的范围的属性称为groupnbr必须在[1-N]范围内,并且从外部来源导入项目时可以设置 。由于所有项目都必须具有nbr,因此任务将变成如何跟踪使用哪些值的功能,以便为手动添加的新项目选择免费的nbr

我正在使用DynamoDB和Redis。我在nbr上没有DynamoDB索引。到目前为止,我的想法是使用Redis跟踪用于特定组的数字,以便对于Redis键(例如<MYGROUP>-item-nbrs),我可以存储所有使用的nbr:s并实现查找下一个空闲nbr的逻辑。可接受的nbr范围内的孔是可接受的,但是在考虑用完的数字之前,应先填充孔。

基本上,我想查找最大大小为N的稀疏数组的未使用索引。

在Redis中存储此信息以快速找到免费的nbr的良好结构是什么?到目前为止,我的想法包括:

  • 所有用过的nbr的单个逗号分隔字符串(按排序顺序)?为了找到一个免费的nbr,发出GET命令并解析该字符串,直到找到一个空洞或列表的末尾,然后将选择的数字插入该字符串中,然后替换整个字符串。当N大时,这似乎效率很低。

  • 哈希,其中每个使用的nbr都存储为自己的字段,并使用例如HSCAN遍历散列的字段以找到空闲的nbr。当N很大时,HSCAN必须扫描很多字段。

  • 将我的nbr:s划分为称为p1-20,p21-40,p41-60等的字段,每个字段都包含一组已使用的nbr:s仅在该分区内,并且当分区用尽时(不再有空闲的nbr:s),请将其完全移除以加快进一步的迭代速度。使用HSCAN进行迭代,然后使用HSET启动新分区。

  • 存储所有可用的nbr而不是所有的空闲nbr,并使用已排序的集合和ZPOPMIN或常规列表和LPOP,并可能划分为子集。不过,使用所有免费的function getFreeNbr() { while (true) { send "WATCH numbers" nbr = send "BITPOS numbers 0" if nbr < N send "MULTI" send "SETBIT numbers $nbr 1" if send "EXEC" != NULL return nbr end if else send "UNWATCH numbers" return -1 end if } } 1-N预先填充Redis似乎很丑。

假设N的大小为65536。

出于性能或其他原因,上述任何解决方案是否更好/更糟?有没有更好/更聪明的方法,也许是利用了我不知道的Redis的一些巧妙方面?

编辑:

凯文的答案导致了以下解决方案(伪代码):

{{1}}

1 个答案:

答案 0 :(得分:1)

如何使用Bitmaps记录每个可能的nbr是否使用该值?

要记录使用的值,请使用SETBIT

SETBIT key [nbr] 1

要找到免费的nbr,请使用BITPOS

BITPOS key 0

为避免出现竞争状况,您需要确保获取和设置是原子的。 [OP在follow-up question中解决了这个问题。]

这将需要很少的内存(用于65536个可能值的8K字节)。 BITPOS是O(n),但这不太可能是一个真正的问题。