Algorithm 以紧凑的方式用后缀或前缀对数字进行编码

Algorithm 以紧凑的方式用后缀或前缀对数字进行编码,algorithm,language-agnostic,uniqueidentifier,Algorithm,Language Agnostic,Uniqueidentifier,假设我有6位数的订单ID: 000000 000001 000003 ... 000020 ... 999999 假设每个节点都来自分布式系统中的不同节点,我想将节点id编码到顺序中。 最简单的方法是只保留节点id的前2位,如下所示: 010000 - second node 020001 - third node 010003 - second node again 150004 - 16th node ... 这工作得有点好,但因为我确定我只期望少量节点(比如16个),我丢失了很多可能的

假设我有6位数的订单ID:

000000
000001
000003
...
000020
...
999999
假设每个节点都来自分布式系统中的不同节点,我想将节点id编码到顺序中。 最简单的方法是只保留节点id的前2位,如下所示:

010000 - second node
020001 - third node
010003 - second node again
150004 - 16th node
...
这工作得有点好,但因为我确定我只期望少量节点(比如16个),我丢失了很多可能的ID,将自己基本限制在10^4而不是10^6。有没有一种聪明的方法可以在不限制可能数量的情况下对15个唯一节点进行编码?理想情况下,我会有
10^6-15
的可能性

编辑:我正在寻找一种解决方案,它不会将一个范围平均分配给每个节点id。我正在寻找一种方法,将节点id编码为一个已经存在的唯一id,而不会丢失(理想情况下)更多可能的节点数


EDIT2:之所以必须是6位数字的字符串表示形式,是因为我正在使用的API需要它。不幸的是,没有办法解决这个问题。

n
为6位输入的前2位数字。假设您有16个节点,我们可以执行以下操作:

nodeId = n % 16 
此外:

其中,
/
表示整数除法。对于16个节点,highDigit=[0..6]

如果
m
是由输入的最后4位数字表示的数字,则我们可以通过以下方式恢复原始订单id:

orderId = highDigit*10^5 + m

使用此方案和16个节点,您可以表示6*10^5+10^4顺序ID。

您可以将10^6个可能的ID拆分为几乎相等的块,其中每个块的开始索引等于10^6除以块数,向下取整,乘以块索引,块大小为10^6除以块数,向下取整。在您的示例中,有十六个块:

10^6 / 16 = 62,500
chunk1:  [     0,   62500)
chunk2:  [ 62500,  125000)
chunk3:  [125000,  187500)
chunk4:  [187500,  250000)
chunk5:  [250000,  312500)
chunk6:  [312500,  375000)
chunk7:  [375000,  437500)
chunk8:  [437500,  500000)
chunk9:  [500000,  562500)
chunk10: [562500,  625000)
chunk11: [625000,  687500)
chunk12: [687500,  750000)
chunk13: [750000,  812500)
chunk14: [812500,  875000)
chunk15: [875000,  937500)
chunk16: [937500, 1000000)
要从节点X上的本地ID计算全局ID,请计算62500*X+本地ID。要从节点确定节点和本地ID,请计算节点=全局ID/62500四舍五入,本地ID=全局ID mod 62500


这样做,您可以使用基本上所有可用的索引,直到舍入误差。与节点之间的I/O相比,整数的除法和模运算应该相对较快。

因为您选择使用数字(而不是位,我们可以将整个练习压缩为32位数字),所以这里有一种编码节点ID的方法。也许其他人可以想出更多的想法

将数字字母表扩展到
J
。假设节点ID的位分布在六位数字上。对于每个设置位,将订单ID的十进制数字映射为一个字母:

0 -> A
1 -> B
2 -> C
...
9 -> J
例如:

{759243, 5} -> 759C4D
现在,您可以将所有10^6个订单ID与6位节点ID一起编码

我失去了很多可能的ID,将自己限制在10^4而不是10^6

我们总共还有
10^4*16
id

有没有一种聪明的方法可以在不限制可能数量的情况下对15个唯一节点进行编码

这个问题类似于键空间分区。该问题最著名的解决方案是创建大量虚拟节点,在这些虚拟节点之间划分密钥空间,然后以特定方式(循环、随机、按需等)将这些虚拟节点分配给物理节点

实现键空间分区的最简单方法是确保每个节点生成这样一个id,即:

vnode_id = order_id % total_number_of_vnodes
例如,如果我们只有3个V节点[0,1,2],那么:

vnode 0 must generate ids: 0, 3, 6, 9...
vnode 1 must generate ids: 1, 4, 7, 10...
vnode 2 must generate ids: 2, 5, 7, 11...
如果我们有7个V节点[0,1,2,3,4,5,6],那么:

vnode 0 must generate ids: 0, 7, 14, 21... 
vnode 1 must generate ids: 1, 8, 15, 22... 
vnode 2 must generate ids: 2, 9, 16, 23... 
...
vnode 6 must generate ids: 6, 13, 20, 27... 
然后,所有物理节点必须以已知和常见的方式映射到虚拟节点,例如1:1映射:

physical node 0 takes vnode 0
physical node 1 takes vnode 1
physical node 2 takes vnode 2
按需映射:

physical node 0 takes vnode 0, 3, 7 (many orders)
physical node 1 takes vnode 1, 4 (less orders)
physical node 2 takes vnode 2 (no orders) 
我希望你能理解这个想法

理想情况下,我会有10^6-15种可能性

不幸的是,这是不可能的。考虑这一点:我们有一个10 ^ 6的可能的ID和15个不同的节点,每个都生成唯一的ID。 基本上,这意味着我们以这样或那样的方式在节点之间划分ID,即每个节点的平均值
10^6/15
,远低于理想值
10^6-15

使用上面描述的方法,我们仍然总共有
10^6
id,但是它们将在vnode之间进行分区,而vnode又将映射到物理节点。这是目前解决你的问题的最好的切实可行的办法

我正在寻找一种解决方案,它不会将一个范围平均分配给每个节点id。我正在寻找一种方法,将节点id编码为一个已经存在的唯一id,而不会丢失(理想情况下)更多可能的节点数

不要期待奇迹。可能还有很多其他的技巧值得尝试

例如,如果服务器和所有客户端都知道下一个订单id必须是235,但假设客户端5生成订单id 240(235+5)并将其发送到服务器

服务器需要订单id 235,但收到订单id 240。所以现在服务器知道这个订单来自客户机5(240-235)

或者我们可以尝试使用另一个字段来存储客户端id。例如,如果您有一个时间字段(HH:MM.SS),我们可能会使用秒来存储客户端id


举几个例子,我想你明白了…

如果你考虑的是位而不是数字,你可以用4位编码15个节点。你是否在任何时候将这些数字存储或显示为6位十进制数?因为存储最大为9999999的整数所需的32位整数有12个未使用的位,您可以用来存储其他信息。@m69听起来很愚蠢,一些API设计师认为6位数字就足够了,所以我实际上必须将6位数字的代表作为字符串发送。所以不,我不能使用任何剩余的位,不幸的是:(@juvian,我试过了。问题是,一个6位数字的最接近的表示是2^20。所以,20位。但是,它在7位区域稍微高了一点。我现在正试图找出一种方法来限制它。感谢你在评论中的澄清(我把这个位放在
physical node 0 takes vnode 0, 3, 7 (many orders)
physical node 1 takes vnode 1, 4 (less orders)
physical node 2 takes vnode 2 (no orders)