Javaプログラマの為のGAE/Py bulkloader - bulkloader設定 -

EclipseでGAE/Jをメインアプリとして開発しながら、

GAE/Pyのremote APIでbulkloader使っちゃおうぜ、という計画2回目。

以下が前提条件、という事でした。

  • 1. メインのGAE/Jアプリ実装中に(=Eclipseから)アップロード可能にする事
  • 2. GAEにアップロード、メインのGAE/Jアプリのデータインポート/エクスポート機能として提供可能である事

うん、あれだ。GAEのremote API勉強して分かったんだけど、2の方はbulkloader関係ないw

よく考えれば、「remote APIでGAEにリモートでアクセスできるよ!」って事なので、

実際にGAE上ならbulkloader関係無しにデータ読み書きすればいいじゃない、って話。

まぁいきなり頓挫気味な訳ですが、とりあえずbulkloader使えるように設定しますよ、と。

bulkloader動作確認用にローカルで簡単な確認画面的なWebページも作ってみました。

エンティティ定義

何はともあれ、アップロードするエンティティが定義されてなきゃ話になりません。

まずは、エンティティとそのプロパティを定義します。

from google.appengine.ext import db

class Data(db.Model):
    str = db.StringProperty()
    byteStr = db.ByteStringProperty()
    boolean = db.BooleanProperty()
    int = db.IntegerProperty()
    date = db.DateProperty()
    dateTime = db.DateTimeProperty()
    binary = db.ListProperty(bytes)
    blobList = db.ListProperty(db.Blob)
    strList = db.StringListProperty()
    blob = db.BlobProperty()
    text = db.TextProperty()

db.ListPropertyは第一引数に指定した型のリストのプロパティを返します。

他にも引数あるっぽいですが、とりあえずはこのままで。

確認用ページ作成

いきなり本番環境にアップロードする、などという怖い事はできないので、

意図したデータがアップロードできるかどうかをローカルでテストする確認用ページを作ります。

GAE/PyはwebappフレームワークとDjangoテンプレートエンジンを用意してくれているので思いの外簡単でした。

Handler

sample.py

import os
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app
from zetta1985.model import Data

class DataHandler(webapp.RequestHandler):
    def get(self):
        template_value = {'dataList':Data.all()}
        path = os.path.join(os.path.dirname(__file__), 'index.html')
        self.response.out.write(template.render(path, template_value, True))

application = webapp.WSGIApplication([('/', DataHandler)], debug=True)

def main():
    run_wsgi_app(application)

if __name__ == "__main__":
    main()

Javaでいうサーブレットみたいなものかな?

HTMLテンプレート

index.html

<html>
<head>
  <metahttp-equiv="Content-Type"content="text/html; charset=Shift_JIS">
  <title>Data Viewer</title>
</head>
<body>
  <table border="1">
    <caption>Data</caption>
    <tr>
      <th>str</th>
      <th>byteStr</th>
      <th>boolean</th>
      <th>int</th>
      <th>date</th>
      <th>dateTime</th>
      <th>binary</th>
      <th>blobList</th>
      <th>strList</th>
      <th>blob</th>
      <th>text</th>
    </tr>
  </table>

  <form method="get">
  <input type="submit"value="update"/>
  </form>
</body>
</html>

どのテンプレートエンジンもやれる事に大差は無いはずなので、

他のテンプレートエンジン使った事ある人ならそれほどガッツリ勉強しなくても使えるはず。

JSTL感覚でいけます。

上の二つのファイルをapp.yamlと同ディレクトリに置いて、

app.yamlに以下を追記します。

- url: /.*
  script: sample.py

とりあえずこの段階で試しに表示してみる。

前回作った起動構成から開発サーバーを起動、ブラウザからアクセス。

f:id:zetta1985:20100124172009j:image

まだデータが空なのでこんな感じ。

bulkloader設定

いよいよ、bulkloaderの設定に入ります。

Loader定義

loader.py

class DataLoader(bulkloader.Loader):
    def __init__(self):
        bulkloader.Loader.__init__(self, "Data", [
            ('str', str),
            ('byteStr', bytes),
            ('boolean', bool),
            ('int', int),
            ('date',
            lambda x: datetime.datetime.strptime(x, '%Y/%m/%d').date()),
            ('dateTime',
            lambda x: datetime.datetime.strptime(x, '%Y/%m/%d/%H:%M')),
            ('binary',
            lambda x : map(lambda y: bytes(y), x.split('/'))),
            ('blobList',
            lambda x : map(lambda y: db.Blob(y), x.split('/'))),
            ('strList', lambda x: x.split('/')),
            ('blob', db.Blob),
            ('text', str), ])

loaders = [DataLoader]
アップロードデータ定義

data.csv

String, Byte, True, 1985, 2010/1/1, 2010/1/1/10:10, 37/54/32, 895/8902/7892, AAA/BBBB/CCCC, 8923, Text
ZETTA, bbbbb, FALSE, 1985, 2010/4/16, 2010/4/16/0:00, 37/54/32, 895/8902/7892, AAA/BBBB/CCCC, 8923, Text

DataLoaderでは、CSVのデータをどうやってプロパティに入れるか、という設定をしてます。

CSVでカンマ区切りで書かれてる順序が

bulkloader.Loader.__init__に渡してるタプルのリストの順序にそのまま対応。

リストのタプルが、プロパティ名とCSV文字列からプロパティのデータ型への変換を表しています。

ちなみに、プロパティ名を表す文字列の所を間違えてもエラーが出ずスルーされるので注意。

ラムダ式とかよく分からない&ラムダ式なんか覚えてやらねぇ!って人は、

文字列の引数受け取って、プロパティの型にデータ変換する関数を定義して、

関数名をタプルに入れとけばおk。

Let’s bulkload!

あとは、appcfg.pyを実行すればbulkloaderできます!

試しにローカルのデータストアにbulkloader。

ディレクトリ構成はこんな感じ。

f:id:zetta1985:20100124172011j:image

ローカルの開発サーバーが起動している事を確認して、以下の起動構成を作成、実行します。

f:id:zetta1985:20100124174909j:image

f:id:zetta1985:20100124174910j:image

うん、ウザイ。主に引数がウザイ。

実行するとEclipseのコンソールが出力されるので、パスワードを入力してEnter。

[INFO ] All entities successfully transferred

と出力されたら成功です。確認用ページで見てみましょう。

f:id:zetta1985:20100124172014j:image

よし、見事bulkloaderできた。

本番環境にいきなりアップロードするのは危険極まりないので、 一度ローカルで確かめてから、ってのは常套手段かな?

ちなみに、GAE上ではJavaとPythonのデータストアは相互にプログラム内で扱えますが、 ローカルだとJavaとPythonのデータの保存の仕方が違うので 今回作ったbulkloaderでJavaアプリのローカルのデータストアにサンプルデータをつっこむ、 というのは現状できないそうです。

今回の「起動構成の設定がウザ過ぎる」及び「エンティティ毎に起動構成作るのめんどくさい」を解消する為に、 次回は、設定の共通化&Pythonスクリプトとしてbulkloaderを起動してみたいと思います。

このエントリーをはてなブックマークに追加
comments powered by Disqus