Notion 的随机漫步公式解析
我在 Notion 上有一个和朋友们分享内容的 Workspace,我当时想设置一个随机漫步的模块在首页用以随机展示 10 个不同的内容,于是想到了根据随机数排序的方法,而要求则是自动生成随机数和随机数定时变化,在这些条件限制下很自然地就想到了时间戳,然后找到了这篇文章:
其中的方法解决了我的需求,具体步骤在这里就不重复写了,里面用到了一条很关键公式:
(((((timestamp(prop("Created time")) * 100011979) + 500067713) % 900066731) * ((((round(timestamp(now()) / 600000) * 600000) * 800067089) + 800068411) % 800053967)) + 900067309) % 900066571
这篇文章将会简单解析这条公式怎么运作。
公式分解
直接看公式有点乱,我先将它的书写优化一下:
- A = (创建时间戳 * 100011979 + 500067713) % 900066731
- B = ((时间窗口 * 800067089) + 800068411) % 800053967
- 时间窗口:将当前时间戳四舍五入到最近的10分钟(
round(当前时间戳 / 600000) * 600000
)。
- 时间窗口:将当前时间戳四舍五入到最近的10分钟(
- 最终结果 = (A * B + 900067309) % 900066571
为什么这个公式有效
线性同余方法(LCG )
把这个公式分解后,很容易看到公式的规律,这是 3 个 (A*X + B) % C
一样结构的公式组合,这个结构明显和伪随机数生成的其中一个经典方式线性同余方法(LCG) 有关。
以上是 LCG 的公式,这个方法保证了通过内容的时间戳生成随机 A 和 B 的值,这是前两次生成随机数。
多级混淆
公式里使用了多个 LCG 公式混合计算,主要是为了:
- 输入分离:静态与动态因子分开处理,避免单一时间戳的规律性影响全局;
- 乘积放大差异:即使 A 或 B 微小变化,乘积结果差异指数级增长,进一步被模运算打散;
大质数的选择
2023 年我用过多个 AI 都无法讲明白这个问题,最近借助 DeepSeek 又重新解析了一遍。
公式中所有乘数(100011979
, 800067089
)和模数(900066731
, 800053967
, 900066571
)均为大质数,推测原因:
- 均匀分布保证:m 为大质数,则每个输入 Xn 通过线性变换后,输出 Xn+1 在 [0, m−1] 范围内近似均匀分布;
- 长周期保证:LCG 的周期可达 m,即覆盖所有可能值后才重复,且乘数选择质数,确保与模数互质(如
100011979
和900066731
均为质数,必然互质),满足 LCG 周期最大化条件; - 减少碰撞概率:
900066731
属于“安全质数”,可增强抗碰撞性(不同输入得到相同输出); - 雪崩效应:即使输入 Xn 仅有微小变化(如时间戳相差 1 毫秒),经过大质数乘法和模运算后,输出差异会被显著放大,避免规律性。
- 计算效率优化:质数的二进制表示通常具有高位和低位混合(在高位和低位分布比较均匀)的特性,在处理器运算中可能更高效;
- 抗逆向工程:若攻击者试图从输出反推输入,大质数的乘数和模数增加了穷举难度(如暴力破解需遍历9亿个值)。质数间也无明显的数学关联(如非连续质数),避免通过数论分析快速破解。
模数和加法常数的选择
最后一步的模数是 900066571
,而前面的加法常数是 900067309
,比模数大一点,这样加上之后取模,可能会让数值分布更加均匀。
通常,在 (A * B) % m 形式的运算中,m 直接限制了输出范围,使得余数的分布可能受到 m 的影响,比如某些数字出现的频率更高。
但如果再加上一个 大于 m 的常数 C,即:(A * B + C) % m
由于 C 本身的取值不会影响 A * B 的结构(但会改变模运算的结果),可能会使某些原本较少出现的余数变得更常见,从而让结果的分布更均匀。
时间窗口
时间窗口的设计用于定时更新 B 的值,即使用当前时间除以十分钟再进行四舍五入,以计算当前时间靠近「第几个十分钟」,再乘以 10 分钟换算回时间戳格式。
注意公式里使用 6000000 是因为 Notion 的时间戳是毫秒级时间戳。
结果的排序
在最后一步,我们取用最终结果的正/倒序来进行随机漫步内容的展示,那么生成的随机数的的大小排序一定会变化吗?那是大概率的,不然也不会叫做随机数生成了,我们可以举很简单的例子验证一下:
初始计算1. (7 * 3+3)%5 =42. (11 * 3+3)%5=13. (13 * 3+3)%5=2
更新 B 的值4. (7 * 7+3)%5=25. (11 * 7+3)%5=06. (13 * 7+3)%5=4
可见以结果大小顺序排列的话,两次的顺序分别是:132 和 312。
其他疑问
创建时间相同导致随机数一样
由于从别的地方批量复制内容到 Database 中,以致于这批内容生成的随机数一样,在如何在 Notion 中实践 Zettelkasten 这篇文章的评论区提出了同样问题并给出了一个解决方案。
利用创建时间生成随机漫步的数值想法真的不错!
实际操作时我发现作为一个 creative user,我又遇到了问题。我的一部分笔记是从其他工作区复制汇总而得,这导致它们的创建时间都是一样的。在进一步调试的过程中,我发现由于Notion 页面的创建时间(以及最后编辑时间)仅精确到分,重复的概率还是不小的。
最后我的做法是把上述两个时间的 timestamp 值相加,希望多加一个变量能减少重复的概率。
自己回复自己~
在高人指点下(@SilentDepth 和 @niinjoy),将页面 ID 变为数字,替换原来公式里的timestamp 部分~
toNumber(replaceAll(id(), “[a-f]”, “0”))
修改刷新时间
修改公式中的 600000
数字,注意这个数字的单位是 ms。
能不能应用到其他地方
比如应用到飞书多维表格上,原理上应该可以,但未实践过。
参考链接
公式的原始来源大概是第一个链接。
- Can i generate random numbers in notion?
- 如何在Notion里生成固定、半固定和非固定随机数
- 如何在 Notion 中实践 Zettelkasten
- 我在 Notion 里为BOOOM 搭了个游戏库