当ID是知识而非地址时会发生什么


地址什么都不知道

要在数据库中找到李舜臣,你需要一个ID。

在Wikidata中,李舜臣的ID是 Q8492

这个数字指向李舜臣。 但字符串 Q8492 本身什么都不知道。

它不知道这是一个人还是一座建筑。 它不知道这是韩国人还是法国公民。 它不知道这是16世纪的人物还是21世纪的人物。 它不知道此人是生是死。

Q8492 是一个地址。 送信的邮递员完全不知道信封里写了什么。 他只是看信封上的地址然后投递。

UUID也是如此。550e8400-e29b-41d4-a716-446655440000。 128位随机数。唯一性只是为了避免碰撞—— 它不告诉你任何关于所指对象的信息。

过去五十年来,数据库ID都是这样工作的。 ID是地址,要了解任何信息,你必须跟着地址去读取数据。


必须跟过去才能知道

为什么这是个问题?

假设你想找"19世纪出生的德国男性哲学家"。

在传统数据库中,流程是这样的:

1. 从persons表筛选 gender = 'male'
2. JOIN nationalities表并筛选 country = 'Germany'
3. JOIN birth_dates表并筛选 year BETWEEN 1800 AND 1899
4. JOIN occupations表并筛选 occupation = 'philosopher'

四次JOIN操作。 每次JOIN比较两个表的行。 如果表很大,需要遍历索引;如果没有索引,就执行全表扫描。 十亿条记录的情况下,这个过程需要数秒到数十秒。

为什么如此复杂?

因为ID什么都不知道。 看着 Q8492,你无法判断这是德国人还是韩国人, 所以必须去另一个表检索该信息。

每个问题都必须跟着ID指向的地方去查。 这就是数据库五十年来一直在支付的成本。


如果ID本身就知道呢?

让我们翻转前提。

如果ID本身就包含关键信息呢?

如果只需看ID, 就能判断它指的是人类、来自哪个国家、 属于哪个时代、如何分类呢?

要找"19世纪德国男性哲学家", JOIN变得不必要了。

扫描十亿个ID, 通过检查其比特就能立即判断每个是否匹配。

这就是语义对齐索引的核心思想。


将意义对齐到ID中

SIDX(语义对齐索引)是一个64位标识符。

这64位不是随机数。 每个比特的位置都被赋予了意义。

高位存放最重要的信息。 这是什么类型的实体?人、地点、事件还是概念?

接下来的比特存放分类信息。 如果是人,属于哪个时代?哪个地区?

低位携带越来越具体的信息。

关键原则是这样的:

比特的顺序就是信息重要性的顺序。

最基本的分类在最上面, 最细粒度的区分在最下面。

这不仅仅是排序。 这是一种设计哲学。


从十亿到一万,一次扫描

SIDX的实际威力体现在数字中。

WMS持有十亿个实体。 每个实体的SIDX是64位。 总大小:10亿 x 8字节 = 8 GB。

这8 GB完全放得进内存。

你想找"属于人类且来源于东亚的实体"。 高位包含"人类"标志和"东亚"编码, 因此可以用单个位掩码进行过滤。

mask   = 0xFF00_0000_0000_0000  (高8位:类型 + 地区)
target = 0x8100_0000_0000_0000  (人类 + 东亚)

for each sidx in 1_billion:
    if (sidx & mask) == target:
        add to candidates

这个操作可以用SIMD并行化。 使用AVX-512,单条指令同时比较8个SIDX。 扫描10亿条记录:约12毫秒。

在GPU上?不到1毫秒。

十亿条记录缩减到一万条。 详细过滤剩余的一万条是瞬间完成的。

零JOIN。 零索引树遍历。 只需一次按位AND。


为什么64位就够了

一开始,我以为需要更大的空间。

32字节(256位)。一个32维FP16向量。 我试图把实体的每个关键属性都塞进ID中。 是否是人、性别、国籍、时代、职业、地区、存活状态、分类路径……

但后来我意识到了。

ID不需要知道所有事情。

它只需要将十亿条记录缩减到一万条。 WMS处理其余的。

把它想象成检查站。 在高速公路收费站, 从车牌判断"这辆车正前往京畿道", 不需要知道后备箱里装了什么。

64位就够了。 用高位捕获类型和粗略分类, 用低位进行更细的分类。 64位足以将十亿条记录缩减到一万条。

而且64位 = 四个16位字。 它们在流中自然流动。 32字节的ID会使流变得沉重, 但64位SIDX轻巧且快速。


优雅降级:比特截断后意义依然存在

语义对齐的另一个优势是其降级特性。

因为SIDX的比特按从重要到次要的顺序排列, 即使低位损坏或被截断, 高位中的核心信息依然被保留。

完整64位:  "李舜臣,16世纪朝鲜海军将领"
48位:      "16世纪朝鲜军事将领"
32位:      "16世纪东亚人类"
16位:      "人类"
8位:       "物理实体"

随着信息被截断,具体性丧失, 但最基本的分类保留到了最后。

这是"优雅降级"原则在比特层面的实现。

即使网络中断只传递了部分数据, 系统知道"我不确定这是谁,但至少这是一个关于人类的故事" 并可以继续推理。

模糊的轮廓胜过完全的沉默。 部分理解胜过完全失败。


查询变成ID

语义对齐索引开启的最引人注目的可能性是: 自然语言查询可以被转换为临时SIDX。

用户问:“壬辰战争中击败日本海军的将军是谁?”

编码器分析这个问题。 人类。东亚。16世纪。军事相关。 将这些属性组装成比特,就产生一个临时SIDX。

这个临时SIDX在WMS中扫描十亿个SIDX。 比特模式最相似的实体浮现为候选。 李舜臣、元均、权栗、李亿祺……

将候选者的详细信息进行交叉比对,得出最终答案。

这将搜索和实体链接统一为单一机制。 不需要单独的搜索引擎。 不需要单独的NER(命名实体识别)流水线。 一次SIDX比较就够了。


为什么不用B树?

传统数据库使用B树索引。

B树擅长在排序数据中以O(log n)找到特定值。 对于"查找Q8492",它们是最优的。

但对于"查找所有属于人类且来源于东亚的实体",它们很弱。 复合条件搜索需要交叉多个索引, 交叉的成本随数据规模急剧增长。

SIDX + SIMD穷举扫描采用了根本不同的方法。

如果B树是快速回答"谁住在这个地址"的电话簿, SIDX扫描就是快速回答"谁具有这些特征"的画像分析。

问题的性质不同,最优的数据结构也不同。

查询类型B树SIDX扫描
按特定ID查找O(log n),最优不必要(用哈希)
复合条件过滤需要JOIN,慢一次按位AND,快
相似实体搜索不可能可通过向量相似度实现
插入O(log n),需要再平衡O(1),追加
实现复杂度

WMS不使用B树。 它将十亿个SIDX加载到内存中 并使用SIMD位掩码进行穷举扫描。

简单。暴力。快速。


霍夫曼的智慧

SIDX的比特分配结构遵循霍夫曼编码的原则。

在霍夫曼编码中,出现频率高的符号获得较短的编码, 出现频率低的符号获得较长的编码。

在SIDX中,最常需要的分类信息占据高位, 很少需要的细节占据低位。

同样的原则也支配着这种语言的数据包类型前缀。 出现频率最高的Tiny Verb Edge获得最短的前缀。 出现频率低的Event6 Edge获得较长的前缀。

霍夫曼的智慧贯穿于这个设计的每一层。 没有一个比特被浪费。 最重要的事情付出最低的成本。


总结

传统ID是地址。地址什么都不知道。

  1. 当ID不携带意义时,每次都必须跟着它去数据那里。那就是JOIN。
  2. 对十亿条记录进行四次JOIN很慢。
  3. SIDX通过语义对齐将意义直接编码到ID中。
  4. 一次位掩码AND将十亿条记录缩减到一万条。零JOIN。
  5. 64位就够了。ID不需要知道所有事情——它只需要缩小候选范围。
  6. 因为最重要的信息占据高位,即使比特被截断,核心意义依然存在。
  7. 将自然语言查询转换为临时SIDX,搜索就变成了向量运算。

当ID不再是地址而成为知识的那一刻, 数据库的规则就改变了。