代码之家  ›  专栏  ›  技术社区  ›  Rad'Val

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

  •  2
  • Rad'Val  · 技术社区  · 6 年前

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

    000000
    000001
    000003
    ...
    000020
    ...
    999999
    

    010000 - second node
    020001 - third node
    010003 - second node again
    150004 - 16th node
    ...
    

    10^6 - 15

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

    EDIT2:之所以必须使用6位数字的字符串表示,是因为我使用的API需要这样做。很不幸,没办法。

    4 回复  |  直到 6 年前
        1
  •  1
  •   Andriy Berestovskyy    6 年前

    我失去了很多可能的身份证限制自己基本上10^4而不是10^6。

    10^4 * 16 身份证 总计 .

    有没有一个聪明的方法来编码15个唯一的节点而不限制可能的数目?

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

    实现键空间分区的最简单方法是确保每个节点生成这样一个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...
    

    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种可能性。

    独特的 身份证件。

    基本上,这意味着我们以这样或那样的方式在节点之间划分我们的id,即每个节点得到平均值 10^6 / 15 ,这是远远不够理想的 10^6 - 15 .

    使用上述方法,我们仍然可以 10^6 ID,但它们将在Vnode之间进行分区,Vnode又将映射到物理节点。这是目前解决你问题的最好的实际办法。

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

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

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

        2
  •  0
  •   RaffleBuffle    6 年前

    n

    nodeId = n % 16 
    

    也:

    highDigit = n / 16
    

    在哪里? / 表示整数除法。对于16个节点,高位=[0..6]

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

    orderId = highDigit*10^5 + m
    

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

        3
  •  0
  •   Patrick87    6 年前

    您可以将10^6个可能的ID拆分为几乎相等的块,其中每个块的起始索引等于10^6除以块数(向下舍入)乘以块索引,块大小等于10^6除以块数(向下舍入)。在您的示例中,有16个块:

    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)
    

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

        4
  •  0
  •   גלעד ברקן    6 年前

    既然您选择使用数字(而不是位,在这里我们可以将整个练习压缩为32位数字),那么下面是一种对节点id进行编码的方法。也许其他人能想出更多的主意。

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

    0 -> A
    1 -> B
    2 -> C
    ...
    9 -> J
    

    {759243, 5} -> 759C4D