Python 高效(时间和空间)字典数据库(uniq id的唯一单词和唯一单词)
我正在寻找一种解决方案,它能够:Python 高效(时间和空间)字典数据库(uniq id的唯一单词和唯一单词),python,c,database,encoding,dictionary,Python,C,Database,Encoding,Dictionary,我正在寻找一种解决方案,它能够: 存储任意大小的唯一字及其唯一的64位无符号整数标识符和32或64位无符号整数引用计数 使用以下模式快速访问数据: 要查找单词,请返回其uint64标识符 要查找标识符,请返回单词 插入新记录,最好具有自动递增的标识符和原子递增的引用计数,最好在批提交中插入(不是指逐字插入,每个记录在单独的事务中,而是在一个提交的事务中插入多个字) 原子地删除引用计数为零的记录(即使在速率受限的全表扫描中也可以这样做,方法是迭代所有记录并删除事务中引用计数为0的记录) 在传
- 存储任意大小的唯一字及其唯一的64位无符号整数标识符和32或64位无符号整数引用计数
- 使用以下模式快速访问数据:
- 要查找单词,请返回其uint64标识符
- 要查找标识符,请返回单词
- 插入新记录,最好具有自动递增的标识符和原子递增的引用计数,最好在批提交中插入(不是指逐字插入,每个记录在单独的事务中,而是在一个提交的事务中插入多个字)
- 原子地删除引用计数为零的记录(即使在速率受限的全表扫描中也可以这样做,方法是迭代所有记录并删除事务中引用计数为0的记录)
- 在传统的旋转铁锈(硬盘)上存储大量记录,记录数量大约在1亿到1万亿(1000*10^9)之间
- 平均字大小在25-80字节之间
- 最好有一个python(用于原型设计)和C接口,主要是可嵌入的,或者一个高效的“远程”(仅在本地主机上)API
CREATE TABLE words (
id SERIAL,
word MEDIUMTEXT,
refcnt INT UNSIGNED,
INDEX(word(12)),
PRIMARY KEY (id)
)
这当然是可行的,但MySQL不能胜任这项任务,而且由于单词搜索所需的索引,它不必要地存储冗余信息
在寻找最有效的解决方案的过程中,我发现了以下几点:
-因为这些单词有很多共同点(大多数是各种语言和字符集中的普通字典单词),所以这样做很好
-到目前为止,我能找到的最好的是东京内阁的TDB:packages.python.org/tokyocatent-python/TDB.html,但我必须评估它的性能和可能的设置(在哪里存储什么,在哪里使用什么类型的索引,以获得最佳的时间和空间效率)
有什么想法、算法、甚至更好的、随时可用的产品和设置吗
谢谢,您可能会想。它涵盖了大部分(如果不是全部的话)
你的要求。它对于您的用例具有良好的性能,具有原子性
用于创建引用计数和唯一标识符的增量/减量,
客户端存在于,您可以包装
事务中的命令序列。它还支持列表、集合和排序
设置和其他一些可能有用的功能
如果可以对工作进行分区,则可以加载/处理来自多个站点的数据
主机并行。考虑到redis的速度,您可能不需要批量处理
但这是可能的(MSET
命令)
另一个好的方面是,您可以使用
redis cli
命令。通过这种方式,您可以尝试/调试
在尝试编写任何代码之前,请执行以下命令。假设redis正在运行
使用默认端口的localhost,键入以下内容:
% redis-cli
redis>
我编写了一组支持您的用例的快速命令
此代码段创建一个名为next.words.id
的整数键,并将其递增
原子地返回新值。为了便于说明,我在123455
开始了这个序列。(整数)123456
是
返回给您的客户:
redis> SET next.words.id 123455
OK
redis> INCR next.words.id
(integer) 123456
然后,我们将这个单词映射到它的id“chaos”->123456
,然后创建一个反向
从id:123456->“混沌”
映射,最后创建一个引用计数键
设置为0
。前缀id:
和ref:
和next.words.id
只是
我选择的惯例--你可以使用任何你喜欢的命名
redis> SET chaos 123456
OK
redis> SET id:123456 chaos
OK
redis> SET ref:chaos 0
OK
要增加“混沌”一词的引用计数:
要减少引用计数,请使用DECR:
redis> DECR ref:chaos
(integer) 1
redis> DECR ref:chaos
(integer) 0
此时,您的代码可能会检测到“混沌”的refcount已被删除
0
并在单个事务中执行以下命令:删除
word及其id:
和ref:
键。我使用了WATCH
命令来避免竞争条件:如果任何其他客户端在提交事务之前更改ref:chaos
键,它将被中止
redis> WATCH ref:chaos
OK
redis> GET chaos
(integer) 123456
redis> MULTI
redis> DEL chaos
QUEUED
redis> DEL id:123456
QUEUED
redis> DEL ref:chaos
QUEUED
redis> EXEC
1) (integer) 1
2) (integer) 1
3) (integer) 1
希望这能有所帮助。删除记录后是否允许重复使用ID?奇怪的是,为什么您认为MySQL无法完成此任务?你试过了吗?如果你不喜欢MySQL,可以试试MongoDB…@caf:是的,它可以重复使用删除的记录IDs@MattBillenstein:是的,我用上面的模式尝试过MySQL,它在数百万条记录之后使用了太多的CPU(固定为100%),当然速度也慢了很多。MongoDB是另一个参与者,我以前使用过它,但是它产生了太大的数据库,这里的空间效率也很重要。顺便说一句,单词的双重存储(一个用于实数,一个用于索引)似乎也是一个主要问题,我不确定它在可伸缩性方面是否会比MySQL好。就您计划存储的密钥数量而言,我对Redis的建议可能行不通,因为它的虚拟内存方案仍然要求所有密钥都适合内存,但我会留下答案供参考。正如你所说,东京内阁可能值得调查。还可以为您提供所需的高性能和空间效率。
redis> WATCH ref:chaos
OK
redis> GET chaos
(integer) 123456
redis> MULTI
redis> DEL chaos
QUEUED
redis> DEL id:123456
QUEUED
redis> DEL ref:chaos
QUEUED
redis> EXEC
1) (integer) 1
2) (integer) 1
3) (integer) 1