attribute: Phillie Casablanca

zlibとsqlite3の組み合わせ



Python 2.5で追加されたsqlite3モジュールで簡単にデータベースを使うことができる。

sqliteでの一つの特徴は、サーバプロセスはいらなくて、データベース自体が一つのファイルになる。
これはすごく便利!

しかし、そのファイルが大きくなるとテーブルや値のQuery時間(検索時間)が遅くなる。
そこで文字列を入れているなら、zlibを使って、圧縮して入れれば、ファイルサイズが小さくなって、検索時間が上がるではないかと思っていた。
(圧縮・解凍プロセス時間が発生するが、自分のデータによってある程度改善されるかも)

とりあえず、その方法を紹介する。

まず、DBの構築、さっき言ったようにこれは簡単。


import sqlite3

# ここでメモリ上のDBを作成。パスとファイル名を指定してあげれば、ファイルDBができる
con = sqlite3.connect(':memory:')
cur = con.cursor()

table_query = u'''CREATE TABLE testtable (binval)'''
cur.execute(table_query)
con.commit()

じゃ、データベースが出来て、これからデータの用意:

# Unicode
mojiretsu = u'''日本語をいれてみよう。  問題にならないといいな~'''

それでデータの圧縮:

import zlib
compstr = zlib.compress(mojiretsu)

しかし、これでだめだった

Traceback (most recent call last):
File "stdin", line 1, in module
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)

失敗しちゃったよ。 なぜかここのPCではasciiでエンコードしようとしているようだ。
じゃ、zlib.compress()に渡す前、utf8に変換しよう。

mojiretsu_utf8 = mojiretsu.encode('utf8')
compstr = zlib.compress(mojiretsu_utf8)

文字列の圧縮が出来た。
データベースに入れるところだが、ここでなかなか分からなかったことは、どうやって、バイナリデータのままでデータベースへの挿入ができる?いろいろ探してみたところ、sqlite3.Binary()を使うと動いたようだ。

query = u'''insert into testtable VALUES(?)'''
b = sqlite3.Binary(compstr)

cur.execute(query,(b,))
[sqlite3.Cursor object at 0x00CB035]

con.commit()

解凍が可能かどうかを確認しよう!

result_obj = cur.execute('''SELECT * FROM bintest''')
rows = result_obj.fetchall()
rows
[(read-write buffer ptr 0x00BE8F20, size 80 at 0x00BE8F00,)]
first_row = rows[0][0]

kaitou_mojiretsu = zlib.decompress(first_row)
print kaitou_mojiretsu
日本語をいれてみよう。  問題にならないといいな~

参照モジュール:
zlib (日本語)
http://www.pinkdragon.net/doc_lib/contents/ja/python_man/lib/module-zlib.html

sqlite3 (英語)
http://docs.python.org/lib/module-sqlite3.html

monkut // July 3, 2008 // 2:03 a.m.