週末にPythonでAvroの読み書きをする用事ができたので、やり方を確認した記録。
Python3.5を利用。
pipからインストール。Python3の場合はavro-python3を入れる。avroを入れるとSyntax Errroで動かない。
pip install avro-python3
今回の用事はHTTPリクエストした結果を保存しておくことだったので、URL、TOP URL(そのサイトの一番上のURL)、ヘッダから取ったencoding、contentsのbyte配列で入れるスキーマを用意する。
{
"namespace": "jp.mwsoft.example.response",
"type": "record",
"name": "page",
"fields": [
{"name": "url", "type": "string"},
{"name": "top_url", "type": "string"},
{"name": "header_encoding", "type": "string"},
{"name": "contents", "type": "bytes"}
]
}
上記をexample.avscという名前で保存しておく。
import avro.schema, requests
from avro.datafile import DataFileWriter
from avro.io import DatumWriter
url = "http://www.mwsoft.jp/"
resp = requests.get(url)
with open("example.avsc", "rt") as avsc:
schema = avro.schema.Parse(avsc.read())
with DataFileWriter(open("contents.avro", "wb"), DatumWriter(), schema) as writer:
writer.append({
"url": url,
"top_url": url,
"header_encoding": requests.utils.get_encoding_from_headers(resp.headers),
"contents": resp.content
})
読み込みの方はschemaを定義する必要がないので、書き込みよりも楽。
from avro.datafile import DataFileReader
from avro.io import DatumReader
with DataFileReader(open("contents.avro", "rb"), DatumReader()) as reader:
for resp in reader:
print(resp)
Avroは追記も可能。openでwb(binaryで書き込み)なのを、ab+(binaryで追記)にしてappendするだけでいい。
注意点として、追記する際はDataFileWriterにschemaは設定しない。設定するとschema - record - schema - recordみたいなデータができてしまって読み取れなくなる。
import avro.schema, requests
from avro.datafile import DataFileWriter
from avro.io import DatumWriter
top_url = "http://www.mwsoft.jp/"
url = "http://www.mwsoft.jp/programming/"
resp = requests.get(url)
with DataFileWriter(open("contents.avro", "ab+"), DatumWriter()) as writer:
writer.append({
"url": url,
"top_url": top_url,
"header_encoding": requests.utils.get_encoding_from_headers(resp.headers),
"contents": resp.content
})
from avro.datafile import DataFileReader
from avro.io import DatumReader
with DataFileReader(open("contents.avro", "rb"), DatumReader()) as reader:
for resp in reader:
print(resp['url'])
#=> http://www.mwsoft.jp/
#=> http://www.mwsoft.jp/programming/
codecを設定していない場合は、圧縮されていない状態でファイルが出力される。今回作成したファイルをcatで見てみると、生データが読める状態で格納されていることがわかる。
codecを指定しておけば、deflateもしくはsnappyで圧縮して出力できる。
import avro.schema, requests
from avro.datafile import DataFileWriter
from avro.io import DatumWriter
url = "http://www.mwsoft.jp/"
resp = requests.get(url)
with open("example.avsc", "rt") as avsc:
schema = avro.schema.Parse(avsc.read())
with DataFileWriter(open("contents.avro", "wb"), DatumWriter(), writer_schema=schema, codec='deflate') as writer:
writer.append({
"url": url,
"top_url": url,
"header_encoding": requests.utils.get_encoding_from_headers(resp.headers),
"contents": resp.content
})
これでdeflateで圧縮された状態で保存される。
追記する際も圧縮しないケースと同じで、ab+で追記モードにして実行すればいい。追記の場合はcodecを明記する必要はない。追記対象のファイルのヘッダ部分を読み込んでcodecを自動で設定してくれる処理が付いている。codecは指定しても既存ファイルの内容が優先され、指定は無視される。
url = "http://www.mwsoft.jp/programming/"
resp = requests.get(url)
with DataFileWriter(open("contents.avro", "ab+"), DatumWriter()) as writer:
writer.append({
"url": url,
"top_url": top_url,
"header_encoding": requests.utils.get_encoding_from_headers(resp.headers),
"contents": resp.content
})
圧縮形式についてはファイルのヘッダに記述されているので、読み込む際は特に形式を意識する必要はない。