Bas*_*asj 8 python serialization dictionary key-value key-value-store
解决方法有很多连载小词典:json.loads/ json.dumps,pickle,shelve,ujson,甚至使用sqlite.
但是当处理可能100 GB的数据时,再也不可能使用在关闭/序列化时可能重写整个数据的模块.
redis 实际上不是一个选项,因为它使用客户端/服务器方案.
问题:哪些密钥:值存储,无服务器,能够使用100多GB数据,在Python中经常使用?
我正在寻找具有标准"Pythonic" d[key] = value语法的解决方案:
import mydb
d = mydb.mydb('myfile.db')
d['hello'] = 17 # able to use string or int or float as key
d[183] = [12, 14, 24] # able to store lists as values (will probably internally jsonify it?)
d.flush() # easy to flush on disk
Run Code Online (Sandbox Code Playgroud)
注意:BsdDB(BerkeleyDB)似乎已被弃用.似乎有一个用于Python的LevelDB,但它似乎并不为人所知 - 我还没有找到一个可以在Windows上使用的版本.哪些是最常见的?
saa*_*aaj 14
您可以使用sqlitedict为SQLite数据库提供键值接口.
SQLite 限制页面表示理论最大值为140 TB,具体取决于page_size和max_page_count.但是,Python 3.5.2-2ubuntu0~16.04.4(sqlite32.6.0)的默认值是page_size=1024和max_page_count=1073741823.这提供了大约1100 GB的最大数据库大小,符合您的要求.
您可以使用如下包:
from sqlitedict import SqliteDict
mydict = SqliteDict('./my_db.sqlite', autocommit=True)
mydict['some_key'] = any_picklable_object
print(mydict['some_key'])
for key, value in mydict.items():
print(key, value)
print(len(mydict))
mydict.close()
Run Code Online (Sandbox Code Playgroud)
关于内存使用情况 SQLite不需要您的数据集适合RAM.默认情况下,它最多可以缓存cache_size页面,这几乎不是2MiB(与上面相同的Python).这是您可以用来检查数据的脚本.运行前:
pip install lipsum psutil matplotlib psrecord sqlitedict
Run Code Online (Sandbox Code Playgroud)
sqlitedct.py
#!/usr/bin/env python3
import os
import random
from contextlib import closing
import lipsum
from sqlitedict import SqliteDict
def main():
with closing(SqliteDict('./my_db.sqlite', autocommit=True)) as d:
for _ in range(100000):
v = lipsum.generate_paragraphs(2)[0:random.randint(200, 1000)]
d[os.urandom(10)] = v
if __name__ == '__main__':
main()
Run Code Online (Sandbox Code Playgroud)
像那样运行它./sqlitedct.py & psrecord --plot=plot.png --interval=0.1 $!.在我的情况下,它生成此图表:

和数据库文件:
$ du -h my_db.sqlite
84M my_db.sqlite
Run Code Online (Sandbox Code Playgroud)
C. *_*oli 10
LMDB(闪电内存映射数据库)是一种非常快速的键值存储,它具有Python 绑定,可以轻松处理巨大的数据库文件。
还有提供 Pythonic语法的lmdbmd[key] = value包装器。
默认情况下,它仅支持字节值,但可以轻松扩展以使用序列化程序(json、msgpack、pickle)来处理其他类型的值。
import json
from lmdbm import Lmdb
class JsonLmdb(Lmdb):
def _pre_key(self, value):
return value.encode("utf-8")
def _post_key(self, value):
return value.decode("utf-8")
def _pre_value(self, value):
return json.dumps(value).encode("utf-8")
def _post_value(self, value):
return json.loads(value.decode("utf-8"))
with JsonLmdb.open("test.db", "c") as db:
db["key"] = {"some": "object"}
obj = db["key"]
print(obj["some"]) # prints "object"
Run Code Online (Sandbox Code Playgroud)
一些基准。批量插入(每个 1000 个项目)用于 lmdbm 和 sqlitedict。对于这些非批量插入,写入性能会受到很大影响,因为默认情况下每次插入都会打开一个新事务。dbm 指的是 stdlib dbm.dumb。在 Win 7、Python 3.8、SSD 上测试。
以秒为单位连续写入
| items | lmdbm | pysos |sqlitedict| dbm |
|------:|------:|------:|---------:|--------:|
| 10| 0.0000| 0.0000| 0.01600| 0.01600|
| 100| 0.0000| 0.0000| 0.01600| 0.09300|
| 1000| 0.0320| 0.0460| 0.21900| 0.84200|
| 10000| 0.1560| 2.6210| 2.09100| 8.42400|
| 100000| 1.5130| 4.9140| 20.71700| 86.86200|
|1000000|18.1430|48.0950| 208.88600|878.16000|
Run Code Online (Sandbox Code Playgroud)
几秒内随机读取
| items | lmdbm | pysos |sqlitedict| dbm |
|------:|------:|------:|---------:|-------:|
| 10| 0.0000| 0.000| 0.0000| 0.0000|
| 100| 0.0000| 0.000| 0.0630| 0.0150|
| 1000| 0.0150| 0.016| 0.4990| 0.1720|
| 10000| 0.1720| 0.250| 4.2430| 1.7470|
| 100000| 1.7470| 3.588| 49.3120| 18.4240|
|1000000|17.8150| 38.454| 516.3170|196.8730|
Run Code Online (Sandbox Code Playgroud)
有关基准测试脚本,请参阅https://github.com/Dobatymo/lmdb-python-dbm/blob/master/benchmark.py
我会为此考虑HDF5。它有几个优点:
/foo/bar)寻址。它也有一些缺点:
h5py)。您可以将 HDF5 视为一种将值(标量或 N 维数组)存储在单个文件(或多个此类文件)内的层次结构中的方法。仅将您的值存储在单个磁盘文件中的最大问题是您会淹没某些文件系统;您可以将 HDF5 视为文件中的文件系统,当您将一百万个值放入一个“目录”时,该文件系统不会崩溃。
标准库中的shelve模块就是这样做的:
import shelve
with shelve.open('myfile.db') as d:
d['hello'] = 17 # Auto serializes any Python object with pickle
d[str(183)] = [12, 14, 24] # Keys, however, must be strings
d.sync() # Explicitly write to disc (automatically performed on close)
Run Code Online (Sandbox Code Playgroud)
这使用 python dbm模块从磁盘保存和加载数据,而不加载整个数据。
dbm 示例:
import dbm, json
with dbm.open('myfile2.db', 'c') as d:
d['hello'] = str(17)
d[str(183)] = json.dumps([12, 14, 24])
d.sync()
Run Code Online (Sandbox Code Playgroud)
但是,使用shelf时有两个注意事项:
pickle序列化。这意味着数据与 Python 以及可能用于保存数据的 Python 版本耦合。如果这是一个问题,dbm可以直接使用该模块(相同的接口,但只能使用字符串作为键/值)。因此,从此处复制的以下第三方选项将是不错的选择:
我知道这是一个老问题,但我很久以前写过这样的东西:
https://github.com/dagnelies/pysos
它的工作原理与普通的 python 类似dict,但优点是比shelveWindows 更高效,而且是跨平台的,这shelve与数据存储因操作系统而异的情况不同。
安装:
pip install pysos
Run Code Online (Sandbox Code Playgroud)
用法:
import pysos
db = pysos.Dict('somefile')
db['hello'] = 'persistence!'
Run Code Online (Sandbox Code Playgroud)
编辑:性能
只是为了给出一个大概的数字,这里是一个迷你基准(在我的 Windows 笔记本电脑上):
pip install pysos
Run Code Online (Sandbox Code Playgroud)
生成的文件大约有 3.5 Mb 大。...所以,非常粗略地说,您每秒可以插入 1 mb 的数据。
编辑:它是如何工作的
每次设置值时它都会写入,但仅写入键/值对。因此,添加/更新/删除项目的成本始终相同,尽管仅添加“更好”,因为大量更新/删除会导致文件中的数据碎片(浪费垃圾字节)。内存中保存的是映射(键 -> 文件中的位置),因此您只需确保有足够的 RAM 用于所有这些键。SSD也强烈推荐。100 MB 既简单又快速。最初发布的 100 GB 会很多,但也是可行的。即使原始读/写 100 GB 也需要相当长的时间。
| 归档时间: |
|
| 查看次数: |
6533 次 |
| 最近记录: |