Python 的快速键值磁盘存储

6
我想知道是否有一种带有Python绑定的快速磁盘键值存储,支持对不同键进行数百万次读/写调用。我的问题涉及在非常大的语料库(Wikipedia)中计算词共现,并不断更新共现计数。这涉及到使用64位键和64位值读取和写入大约300亿个值70次。
我还可以将我的数据表示为上三角稀疏矩阵,尺寸约为2M x 2M。
到目前为止,我已经尝试过:
- Redis(64GB内存不够大) - TileDB SparseArray(无法添加到值) - Sqlite(速度太慢) - LMDB(将300亿次读/写分批执行事务需要多个小时) - Zarr(基于坐标的更新超级慢) - Scipy .npz (无法在内存中保留矩阵以进行加法部分) - 稀疏COO与memmapped coords和data(添加矩阵时RAM使用量巨大)
目前唯一有效的解决方案是LMDB,但运行时间约为12天,这似乎是不合理的,因为我觉得我没有处理那么多数据。使用.npz将子矩阵(约300M个值)保存到磁盘几乎是瞬时的。
有什么想法吗?

1
尝试使用PySpark。这正是它被设计用来完成的任务。 - avloss
1
通过将子矩阵(COO格式)转换为csv并使用PySpark合并它们解决了合并问题。不过,将此csv转换为键值存储的问题仍然存在。由于写入性能非常好,我将尝试使用TileDB SparseArray。 - Henrik Andersson
你如何在Python中实现并发? - amirouche
顺便说一下,这就是我转向 Chez Scheme 的原因。 - amirouche
1
“SQLite way too slow”这种情况很奇怪,因为它被设计成快速的。使用SQLite很容易出现性能问题,但是如果表格配置正确,访问应该是快速的。如果您希望内存缓存可以提高性能,我建议再试一次SQLite。如果访问更多的是完整写入而不是完整读取,则真正的直接访问数据库(例如Python标准库中的ndbm)可能值得一试。 - Serge Ballesta
显示剩余2条评论
3个回答

1

看看Plyvel,它是一个Python接口到LevelDB

我几年前成功地使用了它,而且这两个项目似乎仍然活跃。我的用例是存储数亿个键值对,我更关注读取性能,但它似乎也针对写入进行了优化。


1
你可能想要查看我的项目。 pip install rocksdict 这是一个基于RockDB的快速磁盘键值存储,它可以将任何Python对象作为值。我认为它可靠且易于使用。它的性能与GDBM相当,但与仅适用于Linux上的Python的GDBM相比,它是跨平台的。

https://github.com/Congyuwang/RocksDict

以下是一个演示:
from rocksdict import Rdict, Options

path = str("./test_dict")

# create a Rdict with default options at `path`
db = Rdict(path)

db[1.0] = 1
db[1] = 1.0
db["huge integer"] = 2343546543243564534233536434567543
db["good"] = True
db["bad"] = False
db["bytes"] = b"bytes"
db["this is a list"] = [1, 2, 3]
db["store a dict"] = {0: 1}

import numpy as np
db[b"numpy"] = np.array([1, 2, 3])

import pandas as pd
db["a table"] = pd.DataFrame({"a": [1, 2], "b": [2, 1]})

# close Rdict
db.close()

# reopen Rdict from disk
db = Rdict(path)
assert db[1.0] == 1
assert db[1] == 1.0
assert db["huge integer"] == 2343546543243564534233536434567543
assert db["good"] == True
assert db["bad"] == False
assert db["bytes"] == b"bytes"
assert db["this is a list"] == [1, 2, 3]
assert db["store a dict"] == {0: 1}
assert np.all(db[b"numpy"] == np.array([1, 2, 3]))
assert np.all(db["a table"] == pd.DataFrame({"a": [1, 2], "b": [2, 1]}))

# iterate through all elements
for k, v in db.items():
    print(f"{k} -> {v}")

# batch get:
print(db[["good", "bad", 1.0]])
# [True, False, 1]
 
# delete Rdict from dict
del db
Rdict.destroy(path)

-1

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