【Python百日进阶-Web开发-Peewee】Day281 - SQLite 扩展(六)

12.2.14 class LSMTable

class LSMTable

VirtualModel适合使用lsm1 扩展 的子类lsm1扩展是一个虚拟表,它为来自 SQLite4 的 lsm 键/值存储引擎提供 SQL 接口。

笔记
LSM1 扩展尚未发布(撰写本文时 SQLite 版本为 3.22),因此请考虑此功能是实验性的,可能会在后续版本中进行更改。

LSM 表定义了一个主键列和任意数量的附加值列(它们被序列化并存储在存储引擎的单个值字段中)。主键必须是同一类型并使用以下字段类型之一:

  • IntegerField
  • TextField
  • BlobField
    由于 LSM 存储引擎是键/值存储,因此应用程序必须指定主键(包括整数)。

注意
LSM 引擎不支持二级索引,因此唯一有效的查询将是对主键的查找(或范围查询)。可以查询和过滤其他字段,但可能会导致全表扫描。

示例模型声明:

db = SqliteExtDatabase('my_app.db')
db.load_extension('lsm.so')  # Load shared library.

class EventLog(LSMTable):
    timestamp = IntegerField(primary_key=True)
    action = TextField()
    sender = TextField()
    target = TextField()

    class Meta:
        database = db
        filename = 'eventlog.ldb'  # LSM data is stored in separate db.

# Declare virtual table.
EventLog.create_table()

示例查询:

# Use dictionary operators to get, set and delete rows from the LSM
# table. Slices may be passed to represent a range of key values.
def get_timestamp():
    # Return time as integer expressing time in microseconds.
    return int(time.time() * 1000000)

# Create a new row, at current timestamp.
ts = get_timestamp()
EventLog[ts] = ('pageview', 'search', '/blog/some-post/')

# Retrieve row from event log.
log = EventLog[ts]
print(log.action, log.sender, log.target)
# Prints ("pageview", "search", "/blog/some-post/")

# Delete the row.
del EventLog[ts]

# We can also use the "create()" method.
EventLog.create(
    timestamp=get_timestamp(),
    action='signup',
    sender='newsletter',
    target='sqlite-news')

简单的键/值模型声明:

class KV(LSMTable):
    key = TextField(primary_key=True)
    value = TextField()

    class Meta:
        database = db
        filename = 'kv.ldb'

db.create_tables([KV])

对于由单个值字段组成的表,Peewee 在获取单个项目时会直接返回该值。您还可以请求行切片,在这种情况下,Peewee 返回一个相应的Select查询,该查询可以被迭代。下面是一些例子:

>>> KV['k0'] = 'v0'
>>> print(KV['k0'])
'v0'

>>> data = [{'key': 'k%d' % i, 'value': 'v%d' % i} for i in range(20)]
>>> KV.insert_many(data).execute()

>>> KV.select().count()
20

>>> KV['k8']
'v8'

>>> list(KV['k4.1':'k7.x']
[Row(key='k5', value='v5'),
 Row(key='k6', value='v6'),
 Row(key='k7', value='v7')]

>>> list(KV['k6xxx':])
[Row(key='k7', value='v7'),
 Row(key='k8', value='v8'),
 Row(key='k9', value='v9')]

您还可以索引LSMTableusing 表达式:

>>> list(KV[KV.key > 'k6'])
[Row(key='k7', value='v7'),
 Row(key='k8', value='v8'),
 Row(key='k9', value='v9')]

>>> list(KV[(KV.key > 'k6') & (KV.value != 'v8')])
[Row(key='k7', value='v7'),
 Row(key='k9', value='v9')]

del您可以使用切片或表达式删除单行或多行:

>>> del KV['k1']
>>> del KV['k3x':'k8']
>>> del KV[KV.key.between('k10', 'k18')]

>>> list(KV[:])
[Row(key='k0', value='v0'),
 Row(key='k19', value='v19'),
 Row(key='k2', value='v2'),
 Row(key='k3', value='v3'),
 Row(key='k9', value='v9')]

尝试获取单个不存在的键将导致 a DoesNotExist,但切片不会引发异常:

>>> KV['k1']
...
KV.DoesNotExist: <Model:KV> instance matching query does not exist: ...

>>> list(KV['k1':'k1'])
[]

12.2.15 class ZeroBlob

class ZeroBlob(length)

参数: length( int ) – blob 的大小(以字节为单位)。
ZeroBlob仅用于为存储支持增量 I/O 的 BLOB 预留空间。要使用SQLite BLOB 存储 ,必须首先将所需大小的 ZeroBlob 插入您希望用于增量 I/O 的行中。

例如,请参阅Blob。

12.2.16 class Blob

class Blob(database, table, column, rowid[, read_only=False])

参数:

  • database-SqliteExtDatabase实例。
  • table ( str ) – 正在访问的表的名称。
  • column ( str ) – 正在访问的列的名称。
  • rowid ( int ) – 正在访问的行的主键。
  • read_only ( bool ) – 防止对 blob 数据进行任何修改。
    打开一个存储在给定表/列/行中的 blob,用于增量 I/O。要为新数据分配存储空间,可以使用ZeroBlob非常高效的 。
class RawData(Model):
    data = BlobField()

# Allocate 100MB of space for writing a large file incrementally:
query = RawData.insert({'data': ZeroBlob(1024 * 1024 * 100)})
rowid = query.execute()

# Now we can open the row for incremental I/O:
blob = Blob(db, 'rawdata', 'data', rowid)

# Read from the file and write to the blob in chunks of 4096 bytes.
while True:
    data = file_handle.read(4096)
    if not data:
        break
    blob.write(data)

bytes_written = blob.tell()
blob.close()

read([n=None])

参数: n( int ) – 仅从文件中的当前位置读取最多n个字节。
从 blob 文件中的当前位置读取最多n个字节。如果未指定n ,则将读取整个 blob。

seek(offset[, whence=0])

参数:
offset ( int ) – 查找文件中给定的偏移量。
whence ( int ) – 相对于指定的参考系寻找。
的值whence:

  • 0: 文件开头
  • 1: 当前位置
  • 2: 文件结束

tell()

返回文件中的当前偏移量。

write(value)

参数: 数据( bytes ) – 要写入的数据
从文件中的当前位置开始写入给定的数据。

close()

关闭文件并释放相关资源。

reopen(rowid)

参数: rowid( int ) – 要打开的行的主键。
如果已经为给定的表/列打开了 blob,则可以使用该reopen()方法重新使用同一Blob 对象来访问表中的多行。

12.3 附加的功能

SqliteExtDatabase接受一个初始化选项来注册对简单bloomfilter的支持。bloomfilter一旦初始化,就可以用于对大量数据进行有效的成员资格查询。

这是一个例子:

db = CSqliteExtDatabase(':memory:', bloomfilter=True)

# Create and define a table to store some data.
db.execute_sql('CREATE TABLE "register" ("data" TEXT)')
Register = Table('register', ('data',)).bind(db)

# Populate the database with a bunch of text.
with db.atomic():
    for i in 'abcdefghijklmnopqrstuvwxyz':
        keys = [i * j for j in range(1, 10)]  # a, aa, aaa, ... aaaaaaaaa
        Register.insert([{'data': key} for key in keys]).execute()

# Collect data into a 16KB bloomfilter.
query = Register.select(fn.bloomfilter(Register.data, 16 * 1024).alias('buf'))
row = query.get()
buf = row['buf']

# Use bloomfilter buf to test whether other keys are members.
test_keys = (
    ('aaaa', True),
    ('abc', False),
    ('zzzzzzz', True),
    ('zyxwvut', False))
for key, is_present in test_keys:
    query = Register.select(fn.bloomfilter_contains(key, buf).alias('is_member'))
    answer = query.get()['is_member']
    assert answer == is_present

SqliteExtDatabase还可以注册其他有用的功能:

  • rank_functions(默认开启):注册对搜索结果进行排名的函数,例如bm25和lucene。
  • hash_functions: 注册 md5、sha1、sha256、adler32、crc32 和 murmurhash 函数。
  • regexp_function: 注册一个正则表达式函数。
    例子:
def create_new_user(username, password):
    # DO NOT DO THIS IN REAL LIFE. PLEASE.
    query = User.insert({'username': username, 'password': fn.sha1(password)})
    new_user_id = query.execute()

您可以使用murmurhash函数将字节散列为整数以进行紧凑存储:

>>> db = SqliteExtDatabase(':memory:', hash_functions=True)
>>> db.execute_sql('SELECT murmurhash(?)', ('abcdefg',)).fetchone()
(4188131059,)
  • 20
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

岳涛@心馨电脑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值