概要 (原文そのまま引用)

Google App Engine データストアは、強固でスケーラブルな Web アプリケーション用ストレージを提供します。 データストアは Web アプリケーションでの使用を前提として設計されており、特に読み取りおよびクエリのパフォーマンス向上に重点を置いています。 データストアには、アプリケーションの定義に従って整理されたデータエンティティとプロパティが格納されます。 同じ種類のエンティティをまたがるようなクエリを実行できます。 また、プロパティ値とキーでフィルタを適用し、並び替えることもできます。 大量のデータセットから高速にデータを取得するために、すべてのクエリには事前にインデックスが定義されています。 データストアでは、アプリケーションが定義したエンティティ グループを分散データ ネットワークのトランザクション単位として使用する トランザクション更新をサポートしています。

データストアの紹介

App Engine のデータストアは、「エンティティ」と呼ばれるデータオブジェクトに対するクエリを格納し、実行します。 エンティティには 1 つ以上の「プロパティ」(サポートされるデータ型の、名前の付いた値)が含まれます。 プロパティは別のエンティティへの参照とすることもできます。

データストアは 1 回のトランザクションで複数のオペレーションを実行することができ、 いずれかのオペレーションが失敗したときにはトランザクション全体をロールバックできます。 これは、複数のユーザーがアクセスしたり同じデータ オブジェクトを同時に操作したりする可能性のある、分散されたWebアプリケーションで特に便利です。

従来のデータベースとは異なり、データストアは分散型アーキテクチャを使用して、非常に大きなデータセットのスケーリングを管理します。 App Engineアプリケーションは、データオブジェクト間の関係性を記述し、クエリのインデックスを定義することでデータの分散方法を最適化することができます。

App Engineデータストアは、強い一貫性を持ちますが、リレーショナル データベースではありません。 データストアのインターフェースには従来のデータベースと同じ機能が多くありますが、 データストアには独自の特性があり、自動スケーリングの機能を活用した、データ設計と管理の新しい方法の可能性を秘めています。

Java データ インターフェース

データストアエンティティにはスキーマがありません。 同じ種類の2つのエンティティは、同じプロパティを持ったり、同じプロパティに同じ値タイプを持ったりする必要はありません。 必要に応じてエンティティがスキーマを構成するよう、アプリケーションが制御する必要があります。 Java SDKには、データのモデリングおよび保持のために Java Data Objects(JDO)およびJava Persistence API(JPA)というインスタンスの実装が含まれます。 これらの標準インターフェースには、データオブジェクトのクラスの定義およびクエリの実行のメカニズムが含まれます。 データストアには低レベルのAPIも含まれており、他のインターフェースアダプタの実装での使用や、アプリケーションで直接使用することが可能です。

このドキュメントでは、JDOについて詳細に説明します。 JDO についての他の多くのソースの情報もまた、App Engineに適用することができます。 実装の違いや実装されない機能については、このガイドのドキュメントをご覧ください。

JPA もサポートしています。このドキュメントは JPA について簡単に触れています。JPA の使用をご覧ください。

クラスのインスタンスのエンティティとしてのデータストアへの保存、 およびデータストアから取得されたエンティティをインスタンスとして再作成する方法を表すのに、 JDOでは Javaクラスのアノテーション(ごく普通のJavaオブジェクト(plain old Java objects: POJO))を使用しています。 次に、簡単なデータ クラスの例を示します。

Employee.java


import java.util.Date;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Employee {
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long id;

    @Persistent
    private String firstName;

    @Persistent
    private String lastName;

    @Persistent
    private Date hireDate;

    public Person(String firstName, String lastName, Date hireDate) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.hireDate = hireDate;
    }

    // Accessors for the fields.  JDO doesn't use these, but your application does.

    public Long getId() {
        return id;
    }

    public String getFirstName() {
        return firstName;
    }

    // ... other accessors...
}
   

PersistenceManagerFactoryオブジェクトから作成したPersistenceManagerオブジェクトを使用しデータストアとのやりとりを行います。 PersistenceManagerFactoryの設定は高価であるため、アプリケーションに対し1度だけインスタンスを取得するようにしてください (多くのリクエストをスパンすることができます)。 次のようにシングルトンクラスでラップすることで簡単に実行できます。

Employee.java


import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;

public final class PMF {
    private static final PersistenceManagerFactory pmfInstance =
        JDOHelper.getPersistenceManagerFactory("transactions-optional");

    private PMF() {}

    public static PersistenceManagerFactory get() {
        return pmfInstance;
    }
}
   

データクラスのインスタンスをインスタンス化し、データストアに保存できます。


import java.util.Date;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;

import Employee;
import PMF;

// ...
        Employee employee = new Employee("Alfred", "Smith", new Date());

        PersistenceManager pm = PMF.get().getPersistenceManager();

        try {
            pm.makePersistent(employee);
        } finally {
            pm.close();
        }
   

JDOにはJDOQL というクエリ インターフェースが含まれます。 JDOQLを使用し、このクラスのインタンスとしてエンティティを取得できます。次に例を示します。


import java.util.List;
import Employee;

// ...
        String query = "select from " + Employee.class.getName() + " where lastName == 'Smith'";
        List<Employee> employees = (List<Employee>) pm.newQuery(query).execute();
   

エンティティとプロパティ

App Engineデータストア内のデータオブジェクトを「エンティティ」といいます。 エンティティには1つ以上の「プロパティ」があります。プロパティとは、名前のついた値であり、 そのデータ型には整数、浮動小数点値、文字列、日付、バイナリデータなどを指定できます。

エンティティには各自を一意に識別する「キー」も含まれます。 最も単純なキーには、「種類」とデータストアが指定した一意の数値IDがあります。 IDはアプリケーションが指定した文字列の場合もあります。

アプリケーションがデータストアからエンティティをフェッチする場合は、 そのエンティティのキーを使用するか、そのエンティティのプロパティに適合するクエリを実行します。 クエリは 0 以上のエンティティを返します。クエリの結果はプロパティ値によって並べ替えることができます。 クエリでは、メモリと実行時間を節約するため、データストアが返す結果の数を制限することもできます。

リレーショナル データベースとは違い、App Engineデータストアでは、 指定された種類のすべてのエンティティが同じプロパティを持っている必要はありません。 SDKに含まれているライブラリ、または独自のコードを使用してアプリケーションからデータモデルを定義し、適用できます。

プロパティには 1 つ以上の値を割り当てることができます。 複数の値を持つプロパティには、さまざまなデータ型の値を指定できます。 複数の値を持つプロパティへのクエリでは、いずれかの値がクエリの条件を満たすかどうかを確認します。 そのため、複数の値を持つプロパティはメンバーシップの確認において有効です。

クエリとインデックス

App Engineデータストアクエリは指定された種類(データクラス)のすべてのエンティティで動作します。 エンティティプロパティ値とキーに対して、0個以上のフィルタと0個以上の並び替え順序を指定できます。 クエリのフィルタや並べ替え順に指定されているすべてのプロパティに対し、 エンティティに少なくとも 1 つの値(null 値の場合もある)が割り当てられており、 また、すべてのフィルタ条件がプロパティ値を満たす場合、クエリの結果としてエンティティが返されます。

すべてのデータストアクエリはインデックスを使用します。 インデックスは、希望する順に並べられたクエリ結果を含むテーブルです。 App Engineアプリケーションは、 設定ファイルでインデックスを定義します。 開発用Webサーバーは、インデックスが設定されていないクエリが発生すると、このファイルに自動的に候補を追加します。 アプリケーションをアップロードする前に、手動でファイルを編集して、インデックスを調整できます。 アプリケーションがデータストアエンティティに変更を加えると、データストアは正しい結果でインデックスを更新します。 アプリケーションがクエリを実行すると、データストアは対応するインデックスから直接結果をフェッチします。

このメカニズムは広範囲のクエリをサポートしており、ほとんどのアプリケーションに適しています。 しかし、他のデータベース技術の慣れ親しんだクエリの中には対応していないものもあります。

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

App Engineデータストアでは、エンティティの作成、更新、削除のすべての操作は「トランザクション」で実行されます。 トランザクションは、エンティティへのすべての変更が確実にデータストアに保存されるよう処理します。 トランザクションが失敗した場合、変更は適用されません。これにより、エンティティ内のデータの一貫性が保証されます。

トランザクションAPIを使用し、1 つのトランザクションで複数のアクションをエンティティに適用できます。 たとえば、オブジェクトのカウンタフィールドの値を増やす場合を考えてみましょう。 カウンタを増やすには、カウンタの値を読み取り、新しい値を算出し格納します。 トランザクションを使用しない場合、値を読み取ってから更新するまでの間に、別のプロセスがカウンタを増やしてしまい、 アプリケーションがその更新された値を上書きしてしまうケースが発生する可能性があります。 読み取り、計算、書き込みを 1 つのトランザクションで実行することで、他のプロセスの影響を受けずに値を増やすことができます。

1つのトランザクションで複数のエンティティを変更できます。 この機能を実行するには、同時に更新できるエンティティがどれであるかをApp Engineが事前に知っている必要があります。 これにより、トランザクションをサポートする形式でエンティティを保存できます。 エンティティの作成時に、他のエンティティと同じ「エンティティグループ」に属していることを宣言する必要があります。 1 つのトランザクションからフェッチ、作成、更新、削除を実行するすべてのエンティティは、同じエンティティグループに属している必要があります。

エンティティグループでは、エンティティ間の関係を階層構造で定義します。 グループにエンティティを作成するには、そのグループに属するエンティティの「子」として定義します。 もう一方のエンティティは「親」となります。親を持たずに作成されたエンティティは、「ルート」 エンティティとなります。 子のないルートエンティティは、そのエンティティグループに属する唯一のエンティティとなります。 各エンティティには、ルートエンティティから自分自身への親子関係のパスが存在します (最短のパスは親のないエンティティです)。 このパスは、エンティティの完全キーの基本となる部分です。 完全キーは、パス内の各エンティティの種類およびIDまたはキー名で表されます。

データストアではトランザクションの管理に「楽観的並行性制御」を使用しています。 アプリケーションインスタンスがエンティティグループ内のエンティティへの変更を適用中は、 グループ内のすべてのエンティティへの他の更新は即座にエラーとなります。 アプリケーションは更新されたデータに対してトランザクションを再実行できます。

割り当てと制限

データストアAPIへの各コールはデータストアAPIコールの割り当てとして数えられます。 ライブラリコールによっては、基本となるデータストアAPIへの複数のコールとなることにご注意ください。

アプリケーションからデータストアに送られたデータは、(データストアに)送信されたデータのAPIの割り当てとして数えられます。 アプリケーションがデータストアから受け取るデータは、(データストアから)受信したデータのAPIの割り当てとして数えられます。

アプリケーションが使用するために現在データストアに格納されているデータの合計は保存されているデータ(調整可能)の割り当てを超えることはできません。 これにはエンティティプロパティとキーは含まれますが、インデックスは含まれません。

データストア処理で使用された CPU 時間は、次の割り当てに含まれます。

割り当ての詳細については、割り当て、および管理コンソールの「Quota Details」セクションをご覧ください。

割り当てに加え、データストアの使用には次の制限があります。

制限 制限値
最大エンティティサイズ 1MB
エンティティのインデックス値の最大数(1) 1000個
バッチputまたはdeleteの最大エンティティ数 500エンティティ
バッチ get の最大エンティティ数 1000エンティティ
クエリの最大結果オフセット 1000
すべてのインデックスにおいて、エンティティはエンティティを参照するすべての列およびすべての行に対して、 インデックスの値の 1 つを使用します。インデックス付けされたプロパティに複数の値がある場合、 エンティティのインデックス値の数は増え、テーブル内に繰り返し値のある複数の行を必要とします。

戻る 原文