如何压缩小字符串

时间:2009-01-26 09:27:00

标签: sqlite compression

我有一个充满大量URL的sqlite数据库,它占用了大量磁盘空间,访问它会导致许多磁盘搜索并且速度很慢。平均URL路径长度为97个字节(主机名重复很多,因此我将它们移动到外键表)。压缩它们有什么好方法吗?大多数压缩算法适用于大文档,而不是平均少于100字节的“文档”,但即使减少20%也非常有用。任何可行的压缩算法?没有任何标准。

7 个答案:

答案 0 :(得分:11)

使用压缩算法,但使用共享字典。

在使用Unix压缩命令使用的LZC / LZW算法之前,我已经做过类似的事情。

使用短字符串获得良好压缩的技巧是使用由您正在压缩的URL的标准样本组成的字典。

你应该很容易获得20%。

编辑:LZC是LZW的变种。您只需要LZW,因为您只需要一个静态字典。 LZC增加了对字典/表格填满时重置字词/表格的支持。

答案 1 :(得分:5)

我已尝试使用以下策略。它使用共享字典,但是解决方法python的zlib不能让你访问字典本身。

首先,通过运行一堆训练字符串来初始化预训练的压缩器和解压缩器。扔掉输出字符串。

然后,使用经过训练的压缩器的副本来压缩每个小字符串,并使用解压缩程序的副本对它们进行解压缩。

这是我的python代码(为丑陋的测试道歉):

import zlib
class Trained_short_string_compressor(object):
    def __init__(self,
                 training_set, 
                 bits = -zlib.MAX_WBITS,
                 compression = zlib.Z_DEFAULT_COMPRESSION,
                 scheme = zlib.DEFLATED):
        # Use a negative number of bits, so the checksum is not included.
        compressor = zlib.compressobj(compression,scheme,bits)
        decompressor = zlib.decompressobj(bits)
        junk_offset = 0
        for line in training_set:
            junk_offset += len(line)
            # run the training line through the compressor and decompressor
            junk_offset -= len(decompressor.decompress(compressor.compress(line)))

        # use Z_SYNC_FLUSH. A full flush seems to detrain the compressor, and 
        # not flushing wastes space.
        junk_offset -= len(decompressor.decompress(compressor.flush(zlib.Z_SYNC_FLUSH)))

        self.junk_offset = junk_offset
        self.compressor = compressor
        self.decompressor = decompressor

    def compress(self,s):
        compressor = self.compressor.copy()
        return compressor.compress(s)+compressor.flush()

    def decompress(self,s):
        decompressor = self.decompressor.copy()
        return (decompressor.decompress(s)+decompressor.flush())[self.junk_offset:]

测试它,我在一堆10,000个短的(50 - > 300个字符)unicode字符串上节省了30%以上。压缩和解压缩它们也需要大约6秒钟(相比之下,使用简单的zlib压缩/解压缩大约需要2秒)。另一方面,简单的zlib压缩节省了大约5%,而不是30%。

def test_compress_small_strings():
    lines =[l for l in gzip.open(fname)]
    compressor=Trained_short_string_compressor(lines[:500])

    import time
    t = time.time()
    s = 0.0
    sc = 0.
    for i in range(10000):
        line = lines[1000+i] # use an offset, so you don't cheat and compress the training set
        cl = compressor.compress(line)
        ucl = compressor.decompress(cl)
        s += len(line)
        sc+=len(cl)
        assert line == ucl

    print 'compressed',i,'small strings in',time.time()-t,'with a ratio of',s0/s
    print 'now, compare it ot a naive compression '
    t = time.time()
    for i in range(10000):
        line = lines[1000+i]
        cr = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,zlib.DEFLATED,-zlib.MAX_WBITS)
        cl=cr.compress(line)+cr.flush()
        ucl = zlib.decompress(cl,-zlib.MAX_WBITS)
        sc += len(cl)
        assert line == ucl


    print 'naive zlib compressed',i,'small strings in',time.time()-t, 'with a ratio of ',sc/s 

注意,如果删除它并不是持久的。如果你想要持久性,你必须记住训练集。

答案 2 :(得分:4)

您是否考虑过使用 static Huffman coding

您可以使用现有的网址来根据网址的频率计算网址中出现的所有字节的霍夫曼代码。然后,您可以存储该组代码一次,并使用它对所有URL进行编码。我认为应该给予适当的压缩。

答案 3 :(得分:3)

您的网址格式是什么?

如果任何URL共享一个或多个域,并且您已经足够使用大约20亿个域名,则可以为域名创建池。如果你有共享的相对路径,你可以将它们汇集到一起。

对于数据库中的每个URL,将每个URL拆分为三个部分。方案和领域,例如http://mydomain.com实际网址/ my / path /然后是其余的mypage.html?id = 4(如果您有查询字符串参数)

这样,您应该将每个域和相对路径的开销减少到大约8个字节。如果您想查找部分URL,那应该更好,更快。

注意:只是“http”方案字符串本身是4个字节,您将在每个域条目上保存除此之外的任何内容。如果每个网址都以“http://www”开头。你会保存“:// www。”每次7个字节。

关于如何分割和构造URL的实验,我打赌这是你会发现你的压缩。现在,剩下的字符串不是一个普通的域或相对路径,你可以用它做什么?

压缩网址

通用压缩此类方法源自算术编码。信息理论之父香农在60年代写了一篇关于此事的论文。我一直在使用压缩一段时间,而且我总是发现的一件事是,通用压缩从未解决实际问题。

您很幸运,因为网址具有结构和结构,您应该利用它来更好地存储您的网址。

如果您想应用压缩算法(我认为应该更改主题以反映URL压缩,因为它是特定于域的),您必须检查数据的熵。因为它会告诉你一些关于存储产量的信息。 URL是ASCII字符,任何不在ASCII范围0x20-0x7E内的字符都不会发生并丢失区分大小写,你只有63个不同的状态。 !“#%&'()* +, - 。/ 0123456789:;< =>?@ abcdefghijklmnopqrstuvwxyz {|}〜包括空格。

您可以创建剩余字符的频率表并执行算术编码。你知道你最多需要6位,这意味着对于你的URL数据库中的每个字符你现在都在浪费2位,如果你只是将东西转移到位并使用查找表,你就会得到你的20%压缩。就像那样;)

因为数据是如此具体,所以用通用方法压缩真的不是一个好主意。最好将信息结构化并将其拆分为可以更有效存储的数据。您对该域了解很多,使用该知识来压缩您的数据。

答案 4 :(得分:2)

<强>摘要:

大规模搜索引擎和网络蜘蛛的常见问题是如何处理大量遇到的URL。传统的搜索引擎和网络蜘蛛使用硬盘来存储URL而不进行任何压缩。这导致性能降低和空间需求增加。本文描述了一种简单的URL压缩算法,可以实现高效的压缩和解压缩。压缩算法基于增量编码方案来提取共享公共前缀的URL和AVL树以获得有效的搜索速度。我们的结果表明,实现了50%的尺寸减小。 1。

- Kasom Koht-arsa计算机工程系。

<强> Resource

答案 5 :(得分:0)

是97个字节,还是97个8位ASCII字符,或97个16位Unicode字符?

假设您的所有网址都是http://www.w3.org/Addressing/URL/url-spec.txt的合法网址,那么您应该只有ASCII字符。

如果97个16位Unicode字符只是存储每个字符的低字节,将自动节省50%。

如果是97个8位字符,请注意您只需要7位。您可以简单地将7位一次传入比特流并将该比特流存储到数据库中;使用一些较旧的7位传输协议;或者想出你自己的特殊方式,将每个第8个字符的位存储在前7个字符的高位中。

答案 6 :(得分:0)

如何使用网址表?

您通常只进行“范围扫描”或唯一ID查找吗?

如果你不做WHERE url like "/xxxx/question/%"之类的事情。您可以使用散列索引而不是varchar()上的b树索引来减少磁盘搜索次数。