用于一组短字节串的高效存储数据结构 [英] Memory-efficient data structure for a set of short bytes-strings

查看:35
本文介绍了用于一组短字节串的高效存储数据结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种在Python中类似集合的数据结构,它允许对长度约为10的1亿个短字符串(或字节字符串)进行快速查找(集合为O(1))。

在10M字符串的情况下,这已经占用了Python3.7或3.10.2上的750MB内存(如果用字符串替换b字符串,则占用900MB):

S = set(b"a%09i" % i for i in range(10_000_000))  # { b"a000000000", b"a000000001", ... }
而";实际数据这里是10字节*10M~100MB。因此,由于集合结构、指针、存储桶,内存消耗系数为7.5倍。(有关列表情况下的研究,请参阅Memory usage of a list of millions of strings in Python的答案)。

在处理短字符串时,在内部结构中有指向字符串的指针(可能需要64位=8字节)可能已经是哈希表的2倍因素,也是哈希表的存储桶结构等。

是否有一些短字符串优化技术允许在Python中使用一组内存高效的短字节串?(或任何其他允许快速查找/成员资格测试的结构)

可能没有指向字符串的指针,但如果字符串长度<;=16个字符等,则直接将字符串存储在数据结构中。

或者使用bisect或排序列表帮助(在O(Logn)中查找可能是可以的),同时保持较小的内存使用量?(小于7.5倍的系数,如集合)

推荐答案

到目前为止,以下是我根据注释测试的方法,它们似乎起作用了。

排序列表+对分搜索(+Bloom Filter)

  • 按排序顺序插入标准列表L中的所有内容。这比集合占用的内存要少得多。

  • (可选)创建Bloom Filter,here是一段非常小的代码。

  • (可选)首先使用Bloom Filter测试成员身份(快速)。

  • 使用bisect检查真的是否与in_sorted_list()中的快速in_sorted_list()匹配(且不是假阳性),这比标准查找b"hello" in L快得多。

如果对分搜索足够快,我们甚至可以绕过Bloom Filter(步骤2和3)。它将是O(Log N)。

在我的100M字符串测试中,即使没有布隆过滤器,查找平均也需要2微秒。

sqlite3

正如@tomalak的评论所建议的那样,将所有数据插入到一个sqlite3数据库中非常有效。 在我的8 GB数据库上,即使没有任何索引,查询数据库中是否存在字符串平均只需50微秒。

添加索引使数据库增长到11 GB,但随后查询平均仍在约50微秒内完成,因此此处没有任何收益。

编辑:正如在评论中提到的,使用CREATE TABLE t(s TEXT PRIMARY KEY) WITHOUT ROWID;甚至缩小了数据库:3.3 GB,查询平均仍在约50微秒内完成。Sqlite3(一如既往)真的很棒。

在这种情况下,甚至可以使用How to load existing db file to memory in Python sqlite3?中的方法将其完全加载到RAM中,然后每次查询大约9微秒!

带排序行的文件中的二等分

工作,并且使用非常快的查询(每次查询约35微秒),而无需将文件加载到内存中!看见 Bisection search in the sorted lines of an opened file (not loaded in memory)

以前缀为键、以后缀串联为值的词典

这是此处介绍的解决方案:Set of 10-char strings in Python is 10 times bigger in RAM as expected

想法是:我们有一个词典D,对于给定的word

prefix, suffix = word[:4], word[4:]
D[prefix] +=  suffix + b' '

使用这种方法,使用的RAM空间比实际数据还要小(我测试了30M的平均长度为14的字符串,使用了349MB),查询速度看起来很快(2us),但DICT的初始创建时间有点高。

我也尝试了dictValues=后缀列表,但它更消耗内存。

这篇关于用于一组短字节串的高效存储数据结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆