エンティティ、プロパティ、キー

Cloud Datastore のデータ オブジェクトはエンティティと呼ばれます。エンティティは 1 つ以上の名前付きプロパティを持ち、各プロパティが 1 つ以上の値を持ちます。同じ種類のエンティティが同じプロパティを持つとは限りません。また、エンティティの特定のプロパティの値がすべて同じデータ型である必要はありません(必要に応じて、アプリケーション独自のデータモデルでこのような制限を確立して強制できます)。

Cloud Datastore はさまざまなデータ型のプロパティ値をサポートしています。たとえば、次のようなものがあります。

  • 整数
  • 浮動小数点
  • 文字列
  • 日付
  • バイナリデータ

すべての型の一覧は、プロパティと値の型をご覧ください。

Cloud Datastore 内の各エンティティはキーによって一意に識別されます。キーは次のコンポーネントで構成されています。

  • エンティティの名前空間。マルチテナンシーを可能にします。
  • エンティティの種類。Cloud Datastore のクエリ用にエンティティを分類します。
  • 個々のエンティティの識別子。次のいずれかになります。
    • キー名の文字列
    • 整数の数値 ID
  • 祖先パス(省略可)。Cloud Datastore 階層内でのエンティティの位置を指定します。

アプリケーションはエンティティのキーを使用して Cloud Datastore から個々のエンティティをフェッチできます。また、エンティティのキーまたはプロパティ値に基づくクエリを発行して 1 つ以上のエンティティを取得することもできます。

Java App Engine SDK には、簡単な API がパッケージ com.google.appengine.api.datastore に用意されており、この API が Cloud Datastore の機能を直接サポートします。このドキュメントの例はすべて、この簡単な Java API に基づいています。アプリケーションで直接この API を使用するか、独自のデータ管理レイヤを構築するベースとして使用することができます。

Cloud Datastore 自体がエンティティの構造になんらかの制限(特定のプロパティは特定の型の値を持たなければならないなど)を課すことはありません。この役割はアプリケーションが担います。

種類と識別子

Cloud Datastore の各エンティティは特定の種類に属しています。「種類」とは、クエリのためにエンティティを分類するカテゴリのことです。たとえば、人事アプリケーションでは、企業の各従業員が Employee という種類のエンティティで表されます。Java Datastore API では、作成するエンティティの種類を Entity() コンストラクタの引数として指定します。2 つのアンダースコア(__)で始まる種類名はすべて予約済みであり、使用できません。

次の例では、種類が Employee であるエンティティを作成し、プロパティ値を設定した後、データストアに保存します。

Java 8

Entity employee = new Entity("Employee", "asalieri");
employee.setProperty("firstName", "Antonio");
employee.setProperty("lastName", "Salieri");
employee.setProperty("hireDate", new Date());
employee.setProperty("attendedHrTraining", true);

DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
datastore.put(employee);

Java 7

DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

Entity employee = new Entity("Employee", "asalieri");
employee.setProperty("firstName", "Antonio");
employee.setProperty("lastName", "Salieri");
employee.setProperty("hireDate", new Date());
employee.setProperty("attendedHrTraining", true);

datastore.put(employee);

種類に加え、各エンティティは作成時に割り当てられた識別子を持ちます。識別子はエンティティのキーの一部であるため、エンティティに永続的に割り当てられており、変更できません。識別子を割り当てる方法は 2 通りあります。

  • アプリケーションからエンティティの固有のキー名文字列を指定する。
  • エンティティに整数の数値 ID が自動的に割り当てられるように Cloud Datastore を設定する。

エンティティにキー名を設定するには、エンティティの作成時にコンストラクタの 2 番目の引数として、その名前を指定します。

Entity employee = new Entity("Employee", "asalieri");

Cloud Datastore で数値の ID が自動的に設定されるようにするには、この引数を省略します。

Entity employee = new Entity("Employee");

識別子の割り当て

Cloud Datastore は、次の 2 種類の自動 ID ポリシーを使用して自動 ID を生成するように設定できます。

  • default ポリシーは、未使用の ID をランダムに生成します。この ID はほぼ均等に分布しています。各 ID は最大 16 桁の 10 進数になります。
  • legacy ポリシーは、連続していない小さい整数の ID を生成します。

エンティティの ID をユーザーに表示する場合や、ID の順序に従ってなんらかの処理を行う場合は、手動で割り当てることをおすすめします。

Cloud Datastore は、おおむね均一に分散した一連の未使用 ID をランダムに生成します。各 ID は最大 16 桁の 10 進数になります。

システムから割り当てられる ID 値はエンティティ グループに対して一意であることが保証されています。あるエンティティ グループまたは名前空間から別のエンティティ グループまたは名前空間にエンティティをコピーしキーの ID 部分を保持する場合は、まず ID を割り当ててその ID が Cloud Datastore による今後の割り当てで選ばれないようにしてください。

祖先パス

Cloud Datastore 内の各エンティティは、ファイル システムのディレクトリ構造と同様の階層的に構造化された空間を形成します。エンティティを作成するときに、別のエンティティを親として設定することもできます。新しいエンティティは、この親エンティティの子になります(ファイル システムとは異なり、親エンティティが実際に存在している必要はありません)。親を持たないエンティティは、ルート エンティティとなります。 エンティティと親との割り当ては永続的であり、エンティティの作成後は変更できません。同じ親を持つ 2 つのエンティティ、または 2 つのルート エンティティ(親を持たないエンティティ)に同じ数値 ID が割り当てられることはありません。

エンティティの親、親の親、さらにその親などは順に祖先として位置付けられ、エンティティの子、子の子、さらにその子などは順に子孫として位置付けられます。 ルート エンティティとその子孫のエンティティはすべて同じエンティティ グループに属します。 ルート エンティティから始まり、親から子を経由して対象のエンティティに至るまでの連なりをエンティティの祖先パスといいます。 エンティティを識別する完全なキーは、エンティティの祖先パスから始まってそのエンティティ自身で終わる一連の「種類と識別子のペア」で構成されます。

[Person:GreatGrandpa, Person:Grandpa, Person:Dad, Person:Me]

ルート エンティティの場合は祖先パスが空で、エンティティ自身の種類と識別子だけでキーが構成されています。

[Person:GreatGrandpa]

この概念を次の図に示します。

エンティティ グループ

エンティティの親を指定するには、子エンティティの作成時に親エンティティのキーを Entity() コンストラクタの引数として指定します。このとき指定するキーを取得するには、親エンティティの getKey() メソッドを呼び出します。

Java 8

Entity employee = new Entity("Employee");
datastore.put(employee);

Entity address = new Entity("Address", employee.getKey());
datastore.put(address);

Java 7

Entity employee = new Entity("Employee");
datastore.put(employee);

Entity address = new Entity("Address", employee.getKey());
datastore.put(address);

作成するエンティティにキー名も指定する場合は、Entity() コンストラクタの 2 番目の引数にそのキー名を指定し、3 番目の引数に親エンティティのキーを指定します。

Entity address = new Entity("Address", "addr1", employee.getKey());

トランザクションとエンティティ グループ

エンティティの作成、更新、削除は、すべてトランザクションのコンテキストで行われます。1 つのトランザクションで、このようなオペレーションが複数実行される場合もあります。トランザクションでは、データの整合性を維持するため、すべてのオペレーションを 1 つの単位として Cloud Datastore に適用します。いずれかのオペレーションが失敗した場合、すべてのオペレーションが適用されません。また同一のトランザクション内で実行されるすべての強整合性読み取り(祖先クエリまたは取得)は、データの一貫性のあるスナップショットを維持します。

上記のとおり、エンティティ グループとは、祖先から共通のルート要素までが連結された一連のエンティティです。データをエンティティ グループに編成する場合、実行可能なトランザクションの種類が制限されることがあります。

  • トランザクションがアクセスするすべてのデータは、最大 25 のエンティティ グループに制限されます。
  • トランザクション内でクエリを使用する場合は、適切なデータと一致する祖先フィルタを指定できるように、データをエンティティ グループに編成する必要があります。
  • 1 つのエンティティ グループに対し、1 秒につき約 1 つのトランザクションという書き込みスループットの制限があります。これは高い信頼性とフォールト トレランスを実現するため、Cloud Datastore が広範な地域にわたって個々のエンティティ グループをマスターなしで同期複製するために生じる制限です。

多くのアプリケーションでは、相互に関連性のないデータに対する広範なビューを取得するのであれば、結果整合性(複数のエンティティ グループに対する非祖先クエリ、多少古いデータが返される場合もある)の使用で対応できます。一方、関連性の高いデータから成る単一データセットを表示または編集する場合は、強整合性の使用が適します(祖先クエリ、または単一エンティティに対する get)。このようなアプリケーションでは通常、関連性の高い個々のデータセットに対し、個別のエンティティ グループを作成すると効率的です。詳細については、強整合性に対応するデータ構造をご覧ください。

プロパティと値の型

エンティティに関連付けられたデータ値は 1 つ以上のプロパティで構成されます。 各プロパティには名前と 1 つ以上の値があります。プロパティは複数の型の値を持つことができるため、2 つのエンティティがあった場合、プロパティが同じであっても型が異なる値が存在する場合があります。プロパティにはインデックスを付けることも付けないでおくこともできます(プロパティ P で並べ替えまたはフィルタリングを行うクエリは、P にインデックスが付けられていないエンティティを無視します)。1 つのエンティティに、インデックスが付けられたプロパティを最大 20,000 個まで割り当てることができます。

サポートされている値の型は、次のとおりです。

値の型 Java の型 並べ替え順 備考
整数 short
int
long
java.lang.Short
java.lang.Integer
java.lang.Long
数値 長整数として保存され、フィールド タイプに変換されます

範囲外の値はオーバーフローします
浮動小数点数 float
double
java.lang.Float
java.lang.Double
数値 64 ビット倍精度、
IEEE 754
ブール値 boolean
java.lang.Boolean
false<true
テキスト文字列(短) java.lang.String Unicode 最大 1,500 バイト

1,500 バイトを超える値は IllegalArgumentException をスローします
テキスト文字列(長) com.google.appengine.api.datastore.Text なし 最大 1 メガバイト

インデックス未登録
バイト文字列(短い) com.google.appengine.api.datastore.ShortBlob バイト順 最大 1,500 バイト

1,500 バイトを超える値は IllegalArgumentException をスローします
バイト文字列(長) com.google.appengine.api.datastore.Blob なし 最大 1 メガバイト

インデックス未登録
日時 java.util.Date 時系列
地理的座標 com.google.appengine.api.datastore.GeoPt 最初に緯度、
次に経度
住所 com.google.appengine.api.datastore.PostalAddress Unicode
電話番号 com.google.appengine.api.datastore.PhoneNumber Unicode
メールアドレス com.google.appengine.api.datastore.Email Unicode
Google アカウント ユーザー com.google.appengine.api.users.User メールアドレス
Unicode 順
インスタント メッセージング ハンドル com.google.appengine.api.datastore.IMHandle Unicode
リンク com.google.appengine.api.datastore.Link Unicode
カテゴリ com.google.appengine.api.datastore.Category Unicode
評価 com.google.appengine.api.datastore.Rating 数値
Cloud Datastore のキー com.google.appengine.api.datastore.Key
または参照先オブジェクト(子として)
パス要素順
(種類、識別子、
種類、識別子...)
最大 1,500 バイト

1,500 バイトを超える値は IllegalArgumentException をスローします
Blobstore のキー com.google.appengine.api.blobstore.BlobKey バイト順
埋め込みエンティティ com.google.appengine.api.datastore.EmbeddedEntity なし インデックス未登録
Null null なし

重要: プロパティ値として users.User を保存しないでください。これには、メールアドレスとともに一意の ID が含まれるためです。ユーザーが自分のメールアドレスを変更したときに、保存されている古い user.User と新しい user.User の値を比較すると一致しなくなります。代わりに、ユーザーの安定した一意の識別子として、User のユーザー ID 値を使用してください。

テキスト文字列とエンコードされていないバイナリデータ(バイト文字列)については、Cloud Datastore は次の 2 つの値の型をサポートしています。

  • 短い文字列(最大 1,500 バイト)は、インデックスに登録され、クエリのフィルタ条件や並び替えの順序付けに使用できます。
  • 長い文字列(最大 1 メガバイト)は、インデックスに登録されず、クエリのフィルタや並べ替えの順序付けには使用できません。
注: 長いバイト文字列型は、Cloud Datastore API では Blob と呼ばれています。この型は、Blobstore API で使用される blob とは関係ありません。

型が混合した値を持つプロパティをクエリで扱う場合、内部表現に基づく決定論的な順序付けが使用されます。

  1. Null 値
  2. 固定小数点数
    • 整数
    • 日時型
    • 評価
  3. ブール値
  4. バイト列
    • バイト文字列
    • Unicode 文字列
    • Blobstore のキー
  5. 浮動小数点数
  6. 地理的座標
  7. Google アカウントのユーザー
  8. Cloud Datastore のキー

長いテキスト文字列、長いバイト文字列、埋め込みエンティティはインデックスに登録されないため、順序付けは定義されていません。

エンティティの操作

アプリケーションは Cloud Datastore API を使用してエンティティを作成、取得、更新、削除できます。エンティティの完全なキーがわかっている場合(または親のキー、種類、識別子からキーを導出できる場合)、アプリケーションはそのキーを使用してエンティティを直接操作できます。また、Cloud Datastore クエリの結果としてエンティティのキーを取得することもできます。詳しくは、データストアのクエリをご覧ください。

Java Datastore API では、DatastoreService インターフェースのメソッドを使用してエンティティを処理します。DatastoreService オブジェクトを取得するには、静的メソッド DatastoreServiceFactory.getDatastoreService() を呼び出します。

DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

エンティティの作成

Java で新しいエンティティを作成するには、そのエンティティの種類を Entity() コンストラクタの引数として指定してクラス Entity のインスタンスを作成します。必要に応じてエンティティのプロパティを入力してから、そのエンティティをデータストアに保存するには、DatastoreService.put() メソッドの引数として渡します。エンティティのキー名を指定するには、コンストラクタの 2 番目の引数として渡します。

Java 8

Entity employee = new Entity("Employee", "asalieri");
// Set the entity properties.
// ...
datastore.put(employee);

Java 7

Entity employee = new Entity("Employee", "asalieri");
// Set the entity properties.
// ...
datastore.put(employee);

キー名を指定しない場合は、Cloud Datastore によって数値 ID がエンティティのキーとして自動的に生成されます。

Java 8

Entity employee = new Entity("Employee");
// Set the entity properties.
// ...
datastore.put(employee);

Java 7

Entity employee = new Entity("Employee");
// Set the entity properties.
// ...
datastore.put(employee);

エンティティの取得

指定したキーで識別されるエンティティを取得するには、Key オブジェクトを DatastoreService.get() メソッドに渡します。

// Key employeeKey = ...;
Entity employee = datastore.get(employeeKey);

エンティティの更新

既存のエンティティを更新するには、Entity オブジェクトの属性を変更してから、それを DatastoreService.put() メソッドに渡します。そのオブジェクト データで既存のエンティティが上書きされます。put() を呼び出すたびにオブジェクト全体が Cloud Datastore に送信されます。

エンティティの削除

エンティティを削除するには、エンティティのキーを指定して DatastoreService.delete() メソッドを実行します。

// Key employeeKey = ...;
datastore.delete(employeeKey);

反復プロパティ

1 つのプロパティに複数の値を保存できます。

Java 8

Entity employee = new Entity("Employee");
ArrayList<String> favoriteFruit = new ArrayList<String>();
favoriteFruit.add("Pear");
favoriteFruit.add("Apple");
employee.setProperty("favoriteFruit", favoriteFruit);
datastore.put(employee);

// Sometime later
employee = datastore.get(employee.getKey());
@SuppressWarnings("unchecked") // Cast can't verify generic type.
    ArrayList<String> retrievedFruits = (ArrayList<String>) employee
    .getProperty("favoriteFruit");

Java 7

Entity employee = new Entity("Employee");
ArrayList<String> favoriteFruit = new ArrayList<String>();
favoriteFruit.add("Pear");
favoriteFruit.add("Apple");
employee.setProperty("favoriteFruit", favoriteFruit);
datastore.put(employee);

// Sometime later
employee = datastore.get(employee.getKey());
@SuppressWarnings("unchecked") // Cast can't verify generic type.
ArrayList<String> retrievedFruits = (ArrayList<String>) employee.getProperty("favoriteFruit");

エンティティの埋め込み

あるエンティティを別のエンティティのプロパティとして埋め込むと便利な場合があります。たとえば、1 つのエンティティ内でプロパティ値の階層構造を作成する場合です。これは、Java クラス EmbeddedEntity を使用することで可能になります。

Java 8

// Entity employee = ...;
EmbeddedEntity embeddedContactInfo = new EmbeddedEntity();

embeddedContactInfo.setProperty("homeAddress", "123 Fake St, Made, UP 45678");
embeddedContactInfo.setProperty("phoneNumber", "555-555-5555");
embeddedContactInfo.setProperty("emailAddress", "test@example.com");

employee.setProperty("contactInfo", embeddedContactInfo);

Java 7

// Entity employee = ...;
EmbeddedEntity embeddedContactInfo = new EmbeddedEntity();

embeddedContactInfo.setProperty("homeAddress", "123 Fake St, Made, UP 45678");
embeddedContactInfo.setProperty("phoneNumber", "555-555-5555");
embeddedContactInfo.setProperty("emailAddress", "test@example.com");

employee.setProperty("contactInfo", embeddedContactInfo);

埋め込まれたエンティティがインデックスに含まれている場合、サブプロパティに対してクエリを実行できます。埋め込まれたエンティティをインデックス付けから除外した場合、すべてのサブプロパティもインデックス付けから除外されます。埋め込まれたエンティティにキーを関連付けることもできますが、このキーは通常のエンティティの場合と異なり必須ではなく、存在する場合でも、そのエンティティの取得には使用できません。

埋め込まれたエンティティのプロパティを手動で設定する代わりに、setPropertiesFrom() メソッドを使用すると、既存のエンティティからプロパティをコピーできます。

Java 8

// Entity employee = ...;
// Entity contactInfo = ...;
EmbeddedEntity embeddedContactInfo = new EmbeddedEntity();

embeddedContactInfo.setKey(contactInfo.getKey()); // Optional, used so we can recover original.
embeddedContactInfo.setPropertiesFrom(contactInfo);

employee.setProperty("contactInfo", embeddedContactInfo);

Java 7

// Entity employee = ...;
// Entity contactInfo = ...;
EmbeddedEntity embeddedContactInfo = new EmbeddedEntity();

embeddedContactInfo.setKey(contactInfo.getKey()); // Optional, used so we can recover original.
embeddedContactInfo.setPropertiesFrom(contactInfo);

employee.setProperty("contactInfo", embeddedContactInfo);

同じメソッドを後で使用して、埋め込まれたエンティティから元のエンティティを復元できます。

Java 8

Entity employee = datastore.get(employeeKey);
EmbeddedEntity embeddedContactInfo = (EmbeddedEntity) employee.getProperty("contactInfo");

Key infoKey = embeddedContactInfo.getKey();
Entity contactInfo = new Entity(infoKey);
contactInfo.setPropertiesFrom(embeddedContactInfo);

Java 7

Entity employee = datastore.get(employeeKey);
EmbeddedEntity embeddedContactInfo = (EmbeddedEntity) employee.getProperty("contactInfo");

Key infoKey = embeddedContactInfo.getKey();
Entity contactInfo = new Entity(infoKey);
contactInfo.setPropertiesFrom(embeddedContactInfo);

一括オペレーション

DatastoreService のメソッド put()get()delete()(および AsyncDatastoreService の対応する各メソッド)にはバッチ バージョンがあり、反復可能なオブジェクトを 1 つ受け取ります。そのクラスは Entityput() の場合)または Keyget()delete() の場合)です。このオブジェクトを使用して、1 回の Cloud Datastore 呼び出しで複数のエンティティを処理できます。

Java 8

Entity employee1 = new Entity("Employee");
Entity employee2 = new Entity("Employee");
Entity employee3 = new Entity("Employee");
// ...

List<Entity> employees = Arrays.asList(employee1, employee2, employee3);
datastore.put(employees);

Java 7

Entity employee1 = new Entity("Employee");
Entity employee2 = new Entity("Employee");
Entity employee3 = new Entity("Employee");
// ...

List<Entity> employees = Arrays.asList(employee1, employee2, employee3);
datastore.put(employees);

このバッチ オペレーションでは、すべてのエンティティまたはキーがエンティティ グループごとにグループ化され、エンティティ グループごとにオペレーションが並列に行われます。このようなバッチ呼び出しでは、サービス呼び出しの 1 回分のオーバーヘッドしか発生しないため、エンティティごとに個別の呼び出しを行うよりも高速に処理できます。また、複数のエンティティ グループを対象とする場合は、サーバー側で各エンティティ グループの処理が並列に行われます。

キーの生成

アプリケーションでクラス KeyFactory を使用すると、エンティティの Key オブジェクトを既知のコンポーネント(エンティティの種類や ID など)から作成できます。親のないエンティティの場合、種類と ID(キー名の文字列または数値 ID)を静的メソッド KeyFactory.createKey() に渡してキーを作成できます。エンティティの種類 Person とキー名 "GreatGrandpa" または数値 ID 74219 からキーを作成する例を次に示します。

Key k1 = KeyFactory.createKey("Person", "GreatGrandpa");
Key k2 = KeyFactory.createKey("Person", 74219);

キーにパス コンポーネントを入れる場合には、ヘルパークラス KeyFactory.Builder を使用してパスを作成します。このクラスの addChild メソッドでは、1 つのエンティティがパスに追加され、ビルダーそのものが返されます。これを連続して呼び出すことにより、ルート エンティティからエンティティを 1 つずつ追加して、パスを構築することができます。完全なパスを構築した後、getKey を呼び出して、結果のキーを取得します。

Java 8

Key k =
    new KeyFactory.Builder("Person", "GreatGrandpa")
        .addChild("Person", "Grandpa")
        .addChild("Person", "Dad")
        .addChild("Person", "Me")
        .getKey();

Java 7

Key k =
    new KeyFactory.Builder("Person", "GreatGrandpa")
        .addChild("Person", "Grandpa")
        .addChild("Person", "Dad")
        .addChild("Person", "Me")
        .getKey();

クラス KeyFactory には静的メソッド keyToStringstringToKey もあり、キーと文字列表現の間の変換に使用できます。

Java 8

String personKeyStr = KeyFactory.keyToString(k);

// Some time later (for example, after using personKeyStr in a link).
Key personKey = KeyFactory.stringToKey(personKeyStr);
Entity person = datastore.get(personKey);

Java 7

String personKeyStr = KeyFactory.keyToString(k);

// Some time later (for example, after using personKeyStr in a link).
Key personKey = KeyFactory.stringToKey(personKeyStr);
Entity person = datastore.get(personKey);

キーの文字列表現は「ウェブセーフ」で、HTML や URL で特殊文字と見なされる文字は含まれません。

空のリストの使用

これまで、Cloud Datastore には空のリストを表すプロパティの表記がありませんでした。Java SDK では、この問題を回避するために空のコレクションを Null 値として保存していました。そのため、Null 値と空のリストを区別する方法がありません。下位互換性を維持するために、これはデフォルトの動作として残されています。次に、その概要を示します。

  • Null のプロパティは、Null として Cloud Datastore に書き込まれます。
  • 空のコレクションは、Null として Cloud Datastore に書き込まれます。
  • Null は、Null として Cloud Datastore から読み取られます。
  • 空のコレクションは、Null として読み取られます。

ただし、デフォルトの動作を変更すれば、Java SDK で空のリストの保存がサポートされます。アプリケーションのデフォルトの動作を変更した場合の影響について考慮したうえで、空のリストのサポートを有効にしてください

空のリストを使用できるようにするためにデフォルトの動作を変更する場合は、アプリの初期化時に、次に示すように DATASTORE_EMPTY_LIST_SUPPORT プロパティを設定します。

System.setProperty(DatastoreServiceConfig.DATASTORE_EMPTY_LIST_SUPPORT, Boolean.TRUE.toString());

上記のように、このプロパティを true に設定すると、次のようになります。

  • Null のプロパティは、Null として Cloud Datastore に書き込まれます。
  • 空のコレクションは、空のリストとして Cloud Datastore に書き込まれます。
  • Null は、Null として Cloud Datastore から読み取られます。
  • 空のリストを Cloud Datastore から読み取ると、空のコレクションとして返されます。

書き込みコストについて

アプリケーションで Cloud Datastore の put オペレーションを実行する場合、Cloud Datastore でエンティティを保存するために複数回の書き込みが必要になります。このような書き込みが行われるたびに費用が発生します。エンティティの保存に必要な書き込みの回数は、SDK 開発用コンソールのデータビューアで確認できます。このセクションでは、書き込みコストの計算方法について説明します。

1 つのエンティティを保存するには最低 2 回の書き込みが必要です(エンティティ自体の保存に 1 回、EntitiesByKind 組み込みインデックスの保存に 1 回)。この組み込みインデックスは、クエリ プランナーがさまざまなクエリを処理するために使用します。Cloud Datastore では、これ以外に EntitiesByPropertyEntitiesByPropertyDesc の 2 つの組み込みインデックスが保持されます。これらのインデックスはそれぞれ、エンティティの単一のプロパティ値が昇順、降順になっており、エンティティを効率的にスキャンできるようになっています。エンティティのインデックス登録される各プロパティ値は、これらのインデックスそれぞれに書き込む必要があります。

たとえば、A、B、C というプロパティがあるエンティティについて考えてみます。

Key: 'Foo:1' (kind = 'Foo', id = 1, no parent)
A: 1, 2
B: null
C: 'this', 'that', 'theOther'

このようなエンティティに複合インデックス(後述)がないと仮定すると、このエンティティを保存するために 14 回の書き込みが必要です。

  • エンティティ自体のために 1 回
  • EntitiesByKind インデックスのために 1 回
  • プロパティ A のために 4 回(2 つの値に 2 回ずつ)
  • プロパティ B のために 2 回(Null 値も書き込みが必要です)
  • プロパティ C のために 6 回(3 つの値に 2 回ずつ)

複合インデックスとは複数のプロパティを参照するインデックスのことで、保持するために追加の書き込みが必要です。次の複合インデックスを定義するとします。

Kind: 'Foo'
A ▲, B ▼

三角形はプロパティの並べ替え順序を示します(プロパティ A は昇順、プロパティ B は降順)。この場合、前述のエンティティを保存するには、A の値と B の値の組み合わせそれぞれに対して複合インデックスへの追加の書き込みが必要になります。

(1, null) (2, null)

この結果、複合インデックス用に 2 回の書き込みが追加され、書き込みは合計 16 回(1+1+4+2+6+2)になります。次に、プロパティ C をインデックスに追加します。

Kind: 'Foo'
A ▲, B ▼, C ▼

この場合、エンティティを保存すると、A、B、C の値で可能な組み合わせごとに複合インデックスへの書き込みが必要になります。

(1, null, 'this') (1, null, 'that') (1, null, 'theOther')

(2, null, 'this') (2, null, 'that') (2, null, 'theOther')

この結果、書き込みの合計数は 20 回(1+1+4+2+6+6)になります。

複数の値を持つプロパティが Cloud Datastore のエンティティに多数ある場合、または複数の値を持つ 1 つのプロパティが何度も参照される場合、インデックスを保持するために必要な書き込みの回数が組み合わせにより爆発的に増加する可能性があります。このようなインデックス爆発が発生すると、インデックスの保持コストが非常に高価になる場合があります。たとえば、祖先が含まれる複合インデックスについて考えてみます。

Kind: 'Foo'
A ▲, B ▼, C ▼
Ancestor: True

このインデックスを含む単純なエンティティを保存するには、前の例と同じ回数の書き込みが必要です。ただし、このエンティティに祖先がある場合は、エンティティ自体の書き込みの他に、プロパティ値と祖先で可能な組み合わせごとに書き込みが必要になります。たとえば次のように定義されるエンティティがあるとします。

Key: 'GreatGrandpa:1/Grandpa:1/Dad:1/Foo:1' (kind = 'Foo', id = 1, parent = 'GreatGrandpa:1/Grandpa:1/Dad:1')
A: 1, 2
B: null
C: 'this', 'that', 'theOther'

このエンティティでは、次に示すプロパティと祖先の組み合わせごとに、複合インデックスへの書き込みが必要です。

(1, null, 'this', 'GreatGrandpa') (1, null, 'this', 'Grandpa') (1, null, 'this', 'Dad') (1, null, 'this', 'Foo')

(1, null, 'that', 'GreatGrandpa') (1, null, 'that', 'Grandpa') (1, null, 'that', 'Dad') (1, null, 'that', 'Foo')

(1, null, 'theOther', 'GreatGrandpa') (1, null, 'theOther', 'Grandpa') (1, null, 'theOther', 'Dad') (1, null, 'theOther', 'Foo')

(2, null, 'this', 'GreatGrandpa') (2, null, 'this', 'Grandpa') (2, null, 'this', 'Dad') (2, null, 'this', 'Foo')

(2, null, 'that', 'GreatGrandpa') (2, null, 'that', 'Grandpa') (2, null, 'that', 'Dad') (2, null, 'that', 'Foo')

(2, null, 'theOther', 'GreatGrandpa') (2, null, 'theOther', 'Grandpa') (2, null, 'theOther', 'Dad') (2, null, 'theOther', 'Foo')

このエンティティを Cloud Datastore に保存するには、38 回(1 + 1 + 4 + 2 + 6 + 24)の書き込みが必要です。

このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...

Java の App Engine スタンダード環境