如何在处理给定的数据集时找到一个好的/最佳的 zlib 'setDictionary' 字典?

29

我有一组(庞大的)相似数据文件,这组文件不断增长。每个文件的大小约为10K。必须对每个文件进行单独压缩,使用的压缩库是zlib,该库由java.util.zip.Deflater类使用。当使用setDictionary将字典传递给Deflate算法时,可以改善压缩比率。

是否有一种方法(算法)可以找到“最优”字典,即具有最佳总体压缩比率的字典?

请参见zlib手册

1个回答

19

John Reiser 在comp.compression上解释道

对于字典:制作一个短子字符串的直方图,按回报排序(出现次数乘以压缩时节省的位数),并将最高回报的子字符串放入字典中。例如,如果k是可以压缩的最短子字符串的长度(通常为3==k或2==k),则制作长度为k、1+k、2+k和3+k的所有子字符串的直方图。当然,将这些子字符串放入字典中有一定的技巧,利用子字符串、重叠、靠近高地址端的短字符串等等。

Linux内核使用类似的技术来压缩用于打印子程序调用堆栈回溯的符号名称。请参见文件scripts/kallsyms.c。例如,https://code.woboq.org/linux/linux/scripts/kallsyms.c.html

zlib手册建议将最常见的出现放在字典的末尾。

字典应该由在压缩数据中可能遇到的字符串(字节序列)组成,最常用的字符串最好放在字典的末尾。使用字典对于要压缩的数据较短且可以有很高的预测准确性时最有用;此时,与默认空字典相比,数据可以被更好地压缩。
这是因为LZ77具有滑动窗口算法,因此后面的子字符串将比前几个更容易到达您的数据流。
我会尝试使用支持字符串的高级语言生成字典。以下是一个简单的JavaScript示例:
var str = "The dictionary should consist of strings (byte sequences) that"
    + " are likely to be encountered later in the data to be compressed,"
    + " with the most commonly used strings preferably put towards the "
    + "end of the dictionary. Using a dictionary is most useful when the"
    + " data to be compressed is short and can be predicted with good"
    + " accuracy; the data can then be compressed better than with the "
    + "default empty dictionary.";
// Extract words, remove punctuation (extra: replace(/\s/g, " "))
var words = str.replace(/[,\;.:\(\)]/g, "").split(" ").sort();
var  wcnt = [], w = "", cnt = 0; // pairs, current word, current word count
for (var i = 0, cnt = 0, w = ""; i < words.length; i++) {
    if (words[i] === w) {
        cnt++; // another match
    } else {
        if (w !== "")
            wcnt.push([cnt, w]); // Push a pair (count, word)
        cnt = 1; // Start counting for this word
        w = words[i]; // Start counting again
    }
}
if (w !== "")
    wcnt.push([cnt, w]); // Push last word
wcnt.sort(); // Greater matches at the end
for (var i in wcnt)
    wcnt[i] = wcnt[i][1]; // Just take the words
var dict = wcnt.join("").slice(-70); // Join the words, take last 70 chars

然后,dict是一个包含70个字符的字符串,其中包含:

rdsusedusefulwhencanismostofstringscompresseddatatowithdictionarybethe

你可以尝试复制粘贴运行这里(添加:"print(dict)")
这只是整个单词,而不是子字符串。此外,还有一些方法可以重叠常见的子字符串,以节省字典空间。

排序不适用于整数,请参见https://dev59.com/NXNA5IYBdhLWcg3wL6oc。 - Fabien
9
能否“导出”通过压缩文件创建的字典以便将其应用于后续文件,即自动“训练”字典的方式? - rustyx
3
@RustyX,你可以使用infgen来查看你的压缩数据结构,并从中了解哪些数据字面值被引用最频繁。通过使用自定义字典,你可以确保更长的匹配子序列存在,从而获得更好的压缩比。 - Chris Hunt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接