Hatena::ブログ(Diary)

bufferings

2009-11-23

キーとエンティティグループ

| 22:37 |

http://sites.google.com/site/slim3appengine/slim3-datastore/keys-and-entity-groups


データストア内の全エンティティに「キー」があります。キーとはアプリケーションの全エンティティに対してユニークな識別子です。キーにはいくつかの要素があります。

  • エンティティ同士の親子関係を記述する「パス」
  • エンティティの「kind」
  • アプリケーションによって設定された「名前」またはデータストアによって設定された数値の「ID」のどちらか

Kind と Name と ID

http://sites.google.com/site/slim3appengine/slim3-datastore/keys-and-entity-groups/kinds-names-and-ids


全てのエンティティには特定の kind があります。kind とはテーブルのようなものです。Slim3 Datastore はモデルクラスの単純名を kind 名として使用します。


例えば、このモデルの kind は"Employee"です。

import org.slim3.datastore.Model;

@Model
public class Employee {
    ...
}

@Model(kind = "...") アノテーションを使用して kind 名を指定することができます。

import org.slim3.datastore.Model;

@Model(kind = "Emp")
public class Employee {
    ...
}

キーの ID の部分は、アプリケーションが文字列で指定することも、データストアに数値IDを自動生成してもらうようにすることもできます。


アプリケーションで文字列 ID を生成するためには、Key 型の値を ID で作ってその値をフィールドに設定します。

import com.google.appengine.api.datastore.Key;
import org.slim3.datastore.Datastore;

// ...
    Key key = Datastore.createKey(Employee.class, "Alfred.Smith@example.com");
    Employee emp = new Employee();
    emp.setKey(key);
    ...
    Datastore.put(emp);

システムで設定される数値IDを使う場合は、キーのフィールドを null のままにしておきます。そうすると、キーのフィールドは Datastore.put() メソッドを使用してデータストアに書き込まれる際に設定されます。

import com.google.appengine.api.datastore.Key;
import org.slim3.datastore.Datastore;

// ...
    Employee e = new Employee();
    ...
    Datastore.put(e);

システムで設定される数値IDをデータストアに保存する前に取得したい場合は Datastore.allocateId() を使います。

import com.google.appengine.api.datastore.Key;
import org.slim3.datastore.Datastore;

// ...
    Key key = Datastore.allocateId(Employee.class);
    Employee e = new Employee();
    e.setKey(key);
    Datastore.put(e);

システムで設定される数値IDをデータストアに保存する前に複数取得したい場合は Datastore.allocateIds() を使います。

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyRange;
import org.slim3.datastore.Datastore;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

// ...
    List<Employee> list = new ArrayList<Employee>();
    Iterator<Key> keys = Datastore.allocateIds(Employee.class, 100).iterator();
    while (keys.hasNext() {    
        Employee e = new Employee();
        e.setKey(keys.next());
        ...
        list.add(e);
    }
    Datastore.put(list);

Datastore.allocateId(s) はアプリケーションのトランザクションとは無関係ということです。

(id:higayasuo さんありがとうございます。)


エンティティグループと祖先とパス

http://sites.google.com/site/slim3appengine/slim3-datastore/keys-and-entity-groups/entity-groups-ancestors-and-paths


全てのエンティティは「エンティティグループ」に所属しています。エンティティグループとは、単一のトランザクションで扱うことのできる1つ以上のエンティティのセットです。App Engine はエンティティグループの関連に基づいて、複数のエンティティを分散ネットワークの同じ部分に格納します。トランザクションはエンティティグループに対してデータストアの操作を開始し、全ての操作が実行されるか、または失敗時には全ての操作が実行されないかのどちらかとなります。


アプリケーション指定の文字列IDを使用して子のキーを生成する場合は「親」のキーを次のように指定することができます。

import com.google.appengine.api.datastore.Key;
import org.slim3.datastore.Datastore;

// ...
    Key parentKey = ...;
    Key childKey = Datastore.createKey(parentKey, Child.class, "...");

自動生成のIDを使用する場合は「親」のキーを次のように指定することができます。

import com.google.appengine.api.datastore.Key;
import org.slim3.datastore.Datastore;

// ...
    Key parentKey = ...;
    Key childKey = Datastore.allocateId(parentKey, Child.class);

自動生成IDの場合に複数の子のキーを設定する際には「親」のキーを次のように指定することができます。

import com.google.appengine.api.datastore.Key;
import org.slim3.datastore.Datastore;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

// ...
    Key parentKey = ...;
    List<Child> list = new ArrayList<Child>();
    Iterator<Key> childKeys = Datastore.allocateIds(parentKey, Child.class, 100).iterator();
    while(childKeys.hasNext()) {
        Child child = new Child();
        child.setKey(childKeys.next());
        ...
        list.add(child);
    }
    Datastore.put(list);

親を持たないエンティティは「ルート」エンティティとなります。別のエンティティの親であるエンティティも親を持つことができます。あるエンティティからルートまでの親エンティティのチェーンがエンティティの「パス」となります。パスのメンバーはエンティティの「祖先」となります。エンティティの親はエンティティの作成時に定義され、後で変更することはできません。


単一のトランザクションでできるのは

  • 1つのグループ内の複数のエンティティを変更すること
  • グループ内に存在するエンティティを親に指定してグループに新しいエンティティを追加すること

です。


トランザクションについての詳しい情報は、トランザクション を参照してください。


あるエンティティの祖先エンティティが削除されても、子孫エンティティは削除されません。子孫エンティティは完全キーを使用してアクセスすることができます。


エンティティグループを使用する際の Tips :

  • トランザクションのために必要な場合だけエンティティグループを使用します。
  • エンティティグループが多いほど、つまり、ルートエンティティが多いほど、データストアは効率よくノードをまたいだエンティティグループの分散を行うことができます。うまく分散されればデータの生成や更新のパフォーマンスが改善されます。さらに、処理がトランザクションの一部ではない場合に同じエンティティグループに対する同時更新が行われて処理が失敗するとデータストアは自動的にリトライしますが、トランザクションの一部の処理に対してはリトライをしません。その代わりにすぐに java.util.ConcurrentModificationException を投げます。
  • エンティティグループに対する経験から言うと、1人のユーザーにとって意味のあるデータサイズにするか、それより小さくするべきです。
  • エンティティグループはクエリの速度に大した影響を与えません。

shin1oshin1o 2009/11/23 23:44 *1の箇所の「自動インデックスの設定を true にしてたら自動生成用の設定ファイルに候補が追加される」というのは、逆かも。「自動インデックスの設定をfalseにしたら自動生成用の設定ファイルに候補が追加されない」つまり「何もしなければ勝手にインデックス設定ファイルに候補が追加される」というのが正解。

bufferingsbufferings 2009/11/24 00:22 > shin1o さん
コメントありがとうございます。

なるほど。
「何もしなければ(自動生成がONになっていて)勝手に(自動生成用の)インデックス設定ファイルに候補が追加される。」
ということですね。文の通りなんですね。ありがとうございます。

kamiru78kamiru78 2009/12/20 22:51 既存プロジェクトで・・・とある手順で試してみましたがMetaデータのソースが自動生成できませんでした。
slim3-blankプロジェクトから.projectや.settingsや.externalToolBuildersを既存プロジェクトにコピーして.apt_generatedというソースフォルダを作成したらMetaデータが自動生成できるようになりました。
どれが必要でどれが不必要だったかはわかりませんが報告まで。

bufferingsbufferings 2009/12/20 23:05 > kamiru78さん
ご報告ありがとうございます。

「slim3-gen-xxx.jar を 注釈処理のファクトリー・パスに追加します。」
の部分がうまく動作できていなかったのかなと思います。設定ファイルでいうと「.factorypath」です。
でも、自動生成できるようになって良かったです。

slim3 について質問や意見などあれば
http://groups.google.co.jp/group/slim3-user-japan
に投稿するとみなさんが答えてくれますよ。

shimanpshimanp 2010/04/28 12:36 私もMetaクラスが生成されなかったのですが、
slim3-gen-xxx.jar を 注釈処理のファクトリー・パスから一度削除して、
再度追加し直したら.apt_generatedフォルダに生成されました。