2013年05月10日

Python と Java との Datastore 使用法の比較

Google App Engine を語る上でデータストアは避けて通れません。 軽く復習しておきましょう。 データストアは関係データベースではなく、データ取得のためのクエリにも様々な制限があります。 大雑把な理解としては、 関係データベースでテーブルに相当するものはカインド、 行(レコード)に当たるのはエンティティ、 列(カラム)に当たるのはプロパティです。

複数のプロパティが絡むクエリーを発行する際には、それ用のインデックスが必要です。 これは Python でも Java でも同じです。 このインデックスを定義するファイルは、Python では index.yaml、 Java では datastore-indexes.xml になります。 (繰り返しになりますが実は Java でも yaml 設定ファイルを使うことができるようです。 Java App Configuration Using app.yaml

Java には JDO、JPA といった Java 標準に従った別系統の API もありますが、 ここでは取り上げません。 書籍「Slim3 on Google App Engine for Java」によると、 遅くて使えないそうです。

Python でのエンティティの格納

Python でエンティティを扱う場合、Model クラスを継承してカインドごとにクラスを作成します。 Model クラスは google.appengine.ext.db にあります。 プロパティはクラス定義の際に、型に従った Property クラスを設定します。 こうして作ったクラスのインスタンスに各プロパティの値を与え、 最後に put メソッドを呼んでデータストアに格納します。

Java でのエンティティの格納

Java でエンティティを扱う場合、Entity クラスを使います。 Entity クラスは com.google.appengine.api.datastore にあります。 Entity クラスをインスタンス化する際に文字列としてカインド名を渡します。 プロパティの設定は setProperty メソッドにプロパティ名とプロパティ値を渡します。 プロパティ値は Object 型なので、何でも入れられます。 最後に DatastoreService インスタンスの put メソッドにエンティティを渡してデータストアに格納します。

Python におけるクエリー

Python においてクエリーの構築には2種類の方法があります。 一つはモデルクラスを経由する方法、もう一つは GQL を使う方法です。

モデルクラスを経由する方法では、格納に利用した Model を継承したクラスを使います。 これのクラスメソッド all を呼び出すと無条件にそのカインドのエンティティを取得するクエリーが生成されます。 このクエリーに filter メソッドで取得条件を追加したり、order メソッドで順番を設定したりします。

GQL はこういった操作をせずに、SQL 風のコマンドを記述して一気に望みのクエリーを構築します。

どちらの作り方をしたクエリーも、最後に run メソッドを呼ぶとイテレータを返すので、for 文などに渡して一つずつエンティティを取り出します。

Python コード例:
# クラス定義
class Person(Model):
  name = StringProperty()
  age = IntegerProperty()

# 格納
person = Person(name="Guido", age=57)
person.put()

# 取り出し
q = Person.all().fiter("age =", 57).order("+name")

for person in q.run():
  print person.name

Java におけるクエリー

Java では Query にカインド名を渡して Python の all 呼び出し相当のクエリーを作ります。 フィルターの追加は Query.Filter クラス(及びその派生クラス)を作って、setFilter メソッドで設定します。 一方、順序の設定は直接 addSort メソッドを使います。 こうして作ったクエリーを DatastoreService インスタンスの prepare メソッドで PreparedQuery に変換し、最後に asIterable メソッドを呼ぶことで Iterable を返すので for each で一つずつエンティティを取り出します。

Java コード例:
// DatastoreService インスタンスの取得
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

// 格納
Entity person = new Entity("Person");
person.setProperty("name", "Guido");
person.setProperty("age", 57);
datastore.put(person);

// 取り出し
Filter f = new FilterPredicate("age", FilterOperator.EQUAL, 57);
Query q = new Query("Person").setFilter(f).addSort("name", SortDirection.ASCENDING);
PreparedQuery pq = datastore.prepare(q);

for (Entity entity : pq.asIterable()) {
  System.out.println((String)entity.getProperty("name"));
}

index.yaml と datastore-indexes.xml

上記サンプルで必要になるインデックスです。

index.yaml
indexes:

- kind: Person
  ancestor: no
  properties:
  - name: age
  - name: name
    direction: asc

index.yaml は開発サーバーでアプリケーションを実行してみると自動で作られるので、 ほとんど手書きする機会はありません。

datastore-indexes.xml
<?xml version="1.0" encoding="utf-8"?>
<datastore-indexes autoGenerate="true">
    <datastore-index kind="Person" ancestor="false">
        <property name="age" direction="asc" />
        <property name="name" direction="asc" />
    </datastore-index>
</datastore-indexes>

datastore-indexes.xml の datastore-indexes タグの autoGenerate 属性は必須で、 true にしておくと開発サーバーで使ったインデックスが war/WEB-INF/appengine-generated/datastore-indexes-auto.xml に記録されていきます。ですので、ひと通りローカルでアプリケーションを実行したあと、 この内容を書き写せば OK です。必要なインデックスが揃ったら autoGenerate 属性を false に変えましょう。

次回予告

次回は各種サービスについて比較します。

ラベル:GAE
posted by mft at 11:44| Comment(0) | TrackBack(0) | 技術文書 | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

※ブログオーナーが承認したコメントのみ表示されます。

この記事へのトラックバック
×

この広告は180日以上新しい記事の投稿がないブログに表示されております。