这可能吗?我听说 cassandra 也有类似的东西:https://datastax.github.io/python-driver/api/cassandra/util.html
我一直在使用ISO timestamp
与uuid4
的连接,但结果太大(58个字符),可能是矫枉过正。
在我的上下文中保留序号不起作用(DynamoDB NoSQL)
值得注意的是,对于我的应用程序来说,只要uid
不崩溃,在同一秒内批量创建的项是否以随机顺序排列并不重要。
我对最大长度没有具体的限制,理想情况下我希望看到不同长度的不同碰撞机会,但它需要小于58(我最初的尝试)
这将与DynamoDB(NoSQL数据库)一起用作排序键
4条答案
按热度按时间fkaflof61#
为什么uuid.uuid1不是连续的
uuid.uuid1(node=None, clock_seq=None)
实际上是:1582-10-15 00:00:00
之后的100 ns间隔数)如果不提供任何参数,则调用System函数生成uuid。在这种情况下:
clock_seq
是否可以在不同的进程中重复使用?)。在Python 3.7中,这个信息现在是可用的。如果您提供
clock_seq
或node
,则“使用纯Python实现”。在这种情况下,即使clock_seq
为“固定值”:clock_seq
部分是随机生成的。但这并不重要,因为时间戳是连续且唯一的。clock_seq, node
的uuid1
的进程,则可能返回冲突的值)重用
uuid.uuid1
的解决方案很容易看出,你可以通过提供
clock_seq
或node
参数(使用python实现)来使uuid1
序列化。多个进程问题
但是如果您在同一台计算机上运行一些并行进程,则:
uuid.get_node()
的node
对于所有进程都是相同的;clock_seq
有很小的机会相同(机会为1/16384)这可能会导致冲突!这是在同一台机器上的并行进程中使用
uuid.uuid1
时的常见问题,除非您可以从Python3.7访问SafeUUID。如果您还确保为运行此代码的每个并行进程将
node
设置为唯一值,则应该不会发生冲突。即使您使用SafeUUID并设置了唯一的
node
,如果它们是在不同的进程中生成的,那么仍然有可能具有非顺序的(但唯一的)id。如果一些与锁相关的开销是可以接受的,那么可以将
clock_seq
存储在一些外部原子存储中(例如在"locked"文件中),并随着每次调用而递增:这允许所有并行进程上的node
具有相同的值,并且还将使id-s连续。对于所有并行进程都是使用multiprocessing
创建的子进程的情况:可以使用multiprocessing.Value
“共享”clock_seq
因此,您始终必须记住:
node
的唯一性.此问题为:您不能确保在相同的100 ns间隔内生成来自不同进程的连续id。但这是在进程启动时执行一次的非常“轻”的操作,通过以下方式实现:向默认节点“添加”某些内容,例如int(time.time()*1e9) - 0x118494406d1cc000
,或者通过添加来自机器级原子数据库的某个计数器。clock_seq
“和同一台机器上所有进程的相同node
。这样,您将有一些开销用于“锁定”clock_seq
,但可以保证id是连续的,即使在相同的100 ns间隔内在不同的进程中生成(除非您从同一进程中的多个线程调用uuid)。减小id的大小
生成UUID的一般方法非常简单,因此很容易从头开始实现类似的操作,例如,
node_info
部分使用较少的位:备注:
碰撞几率
clock_seq
或唯一node
:不可能发生冲突node
的多个进程(48位,时间“固定”):node
碰撞的机会:node
冲突的机会:uuid.uuid1
,在我代码中为timestamp_multiplier == 1e7
):与3.72e-19 * avg_call_frequency²
成比例timestamp_multiplier == 1e8
)“时间戳”间隔:与3.72e-21 * avg_call_frequency²
成比例cigdeys32#
在您链接的文章中,cassandra.util.uuid_from_time(time_arg,node=None,clock_seq=None)[source]似乎正是您要查找的内容。
cassandra 并没有特别针对第一类UUID...
cclgggtu3#
您应该能够用32位编码精确到秒的时间戳,时间范围为135年。这将只需要8个字符来表示十六进制。添加到uuid的十六进制表示(32个十六进制字符),将总共只有40个十六进制字符。
以这种方式编码时间戳需要选择一个基准年(例如2000年),并计算到当前日期(时间戳)的天数。将此天数乘以86400,然后加上从午夜开始的秒数。这样给予的值将小于2^32,直到达到2135年。
如果时间戳中多了几位,就可以增加时间范围和/或精度。如果多了8位(两个十六进制字符),就可以达到270年,精度达到百分之一秒。
请注意,您不必以10为基数来模拟秒的小数部分。对于相同的字符数,您可以将其分解为128而不是100,从而获得最佳的位使用率。在年份范围加倍的情况下,这仍然适合8位(2个十六进制字符)
在时间精确度(例如每秒或每100或128秒)内的恩怨几率是由uuid的范围所决定,因此对于所选的精确度而言,恩怨几率为1/2^128。增加时间戳记的精确度对减少恩怨几率的影响最大。它也是对索引键总大小影响最小的因素。
更有效的字符编码:27至29个字符键
您可以通过以base 64而不是16进行编码来显著减小密钥的大小,这样会给予27到29个字符(取决于您选择的精度)
请注意,对于时间戳部分,您需要使用一个编码函数,该函数将整数作为输入,并保留数字字符的排序序列。
例如:
您可以在编码前将时间戳记和uuid结合成单一数字,而不是将两个编码值串连起来,以保存更多的字符。
encode 64()函数每6位需要一个字符。
所以,135年来精确到秒:(32+128)/6 = 26.7 --〉27个字符
而不是(32/6 = 5.3 --〉6)+(128/6 = 21.3 --〉22)==〉28个字符
以270年的时间跨度和128分之一秒的精度:(40+128)/6 =28个字符
使用29个字符,可以将精度提高到1024秒,将年份范围提高到2160年。
UUID屏蔽:17至19个字符的按键
为了提高效率,你可以去掉uuid的前64位(它已经是一个时间戳了),然后把它和你自己的时间戳组合在一起,这样你给予的密钥的长度就可以是17到19个字符,而实际上不会损失冲突避免(取决于你选择的精度)。
整数/数字键?
最后要注意的是,如果数据库支持非常大的整数或数字字段(140位或更多)作为键,则不必将组合数字转换为字符串。只需将其直接用作键即可。
timeStamp<<128 | int(uid)
的数字序列将遵循时间顺序。ehxuflar4#
The uuid6模块(
pip install uuid6
)解决了这个问题,它的目的是实现一个新的uuid变体标准的相应草案,参见here。示例代码:
软件包建议使用
uuid6.uuid7()
:如果可能的话,实现应该使用UUID版本7,而不是UUID版本1和6。
UUID版本7具有一个时间顺序值字段,该字段源自广泛实现且广为人知的Unix纪元时间戳源,自1970年1月1日午夜以来的毫秒秒数(不包括闰秒)。