【发布时间】:2017-12-07 06:49:47
【问题描述】:
我正在使用 this marisa trie 库的自定义 Cython 包装器作为键值多映射。
我的 trie 条目看起来像 key 0xff data1 0xff data2 以将 key 映射到元组 (data1, data2)。 data1 是一个可变长度的字符串,但 data2 始终是一个 4 字节的无符号整数。 0xff 是一个分隔字节。
我知道从理论的角度来看,trie 并不是最佳的数据结构,但各种实际考虑使其成为最佳选择。
在这个用例中,我有大约 10-2000 万个键,每个键平均有 10 个数据点。 data2 对于许多条目来说是多余的(在某些情况下,data2 对于给定键的所有数据点总是相同的),所以我想到了使用最频繁的 data2 条目并添加一个 ("", base_data2)数据指向每个键。
据我所知,由于 MARISA trie 没有后缀压缩,并且对于给定的键,每个 data1 都是唯一的,我假设这将节省每个使用冗余键的数据元组 4 个字节(加上添加每个键的单个 4 字节“值”)。重建特里树后,我检查了冗余数据是否不再被存储。我预计序列化和内存大小都会大幅减少,但实际上磁盘上的 trie 从 566MB 变为 557MB(并且加载的 trie 的 RAM 使用量也有类似的减少)。
由此我得出结论,没有后缀压缩我一定是错的。我现在将带有冗余data2 编号的条目存储为key 0xff data1 0xff,因此为了测试这个理论,我删除了尾随的0xff 并调整了使用trie 的代码来应对。新的 trie 从 557MB 减少到 535MB。
因此,与删除相同数量的 4 字节序列相比,删除单个冗余尾随字节的改进提高了 2 倍,因此要么后缀压缩理论大错特错,要么它以一些非常复杂的方式实现方式。
我剩下的理论是,在 trie 的较高点添加 ("", base_data2) 条目会以某种可怕的方式抛出压缩,但当我删除更多字节时,它应该只添加 4 个字节。那是从下层开始的。
我对修复并不乐观,但我非常想知道为什么我会看到这种行为!感谢您的关注。
【问题讨论】:
-
这闻起来很像内存对齐/填充,但我在 MARISA 代码库中找不到确凿证据。 (虽然我还没有检查过 python 包装器)。