Flask で始める Google AppEngine アプリ開発:番外編 データ移行


2010年 12月 15日

一つ前の「Flask で始める Google AppEngine アプリ開発」の番外編です。
前回は Flask + Appengine という観点でアプリ開発を始め方について説明しましたが、
番外編ではアプリ移植の際に手間をかけたデータ移行について説明します。

今回移植した GMappers というアプリは元々 MySQL 上にデータを保存していたため、
Appengine に移植するにあたりデータを移行する必要がありました。
いろいろ調べてみたところ、Appengine では bulkloader.py を用いてデータ移行をする方法
よく知られているようです。

しかし、bulkloader.py は CSV をインポートするという仕組みであるため、
MySQL → CSV → Appengine というステップを踏む必要があります。
つまり、今回のケースでは
  • MySQL から CSV を抽出するプログラム
  • CSV をモデル化して Appengine に登録するプログラム
が必要になります。
また、この方法では ReferenceProperty を使って他のデータを参照するのは難しいようです。


もう少しデータ移行について調べていったところ Appengine の提供する
remote_api というライブラリがこの問題を解決できることに気づきました。
remote_api を利用することで、ローカル環境から Appengine 環境のデータを操作することができます。
※ remote_api は remote_api_shell コマンドなどで利用されています。

というわけで、remote_api を利用して開発したのが gaerunner というツールです。
gaerunner は指定したプログラムを Appengine 環境につないで実行することができます。
これを利用すると
  • ローカルの DB から Appengine へデータ移行する
  • Appengine からローカルの DB にデータを抜き出す
  • Appengine 上のデータを他のモデルに変換する (データ移行する)
などの処理を簡単に実現することができます。

gaerunner を使うには
  • gaerunner をインストールする (easy_install gaerunner)
  • appengine アプリケーションで remote_api の使用を許可する (app.yaml 内で指定する)
という手順を踏む必要があります。
前回の記事の buildout.cfg にはこの手順を含んでいるため、
ここではセットアップについては割愛します。
前回の記事を読んで環境を構築するか、自分で調べて環境を作ってみて下さい。

では、早速 MySQL から Appengine へのデータ移行スクリプトを準備します。

  import _mysql

  from google.appengine.ext import db

  class Map(db.Model):
    map_id = db.IntegerProperty(required=True)
    name = db.StringProperty(required=True)
    description = db.TextProperty()

  cn = _mysql.connect(host, user, passwd, db)

  cn.query(‘SELECT * FROM maps’)
  map_rs = cn.store_result()
  for i in range(map_rs.num_rows()):
      r = map_rs.fetch_row()[0]

      map = Map(map_id=int(r[0]),
                name=unicode(r[1], ‘utf-8’),
                description=unicode(r[2], ‘utf-8’))

      map.put()

このスクリプトでは、MySQL の maps テーブルからレコードを取り出し
各レコードを Map モデルとして保存(put)しています。

このスクリプトを gaerunner を使って次のように実行します。

  % bin/gaerunner gmappers import_from_mysql.py
  ※ gmappers の部分はアプリケーション ID を指定して下さい

上記を実行すると gaerunner は remote_api を経由して
Map データを Appengine 環境に保存します。
これにより MySQL から Appengine へのデータ移行が実現されます。