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

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

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

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

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

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

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

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

Go App Engine SDK にはパッケージが含まれており、これを使用して Cloud Datastore エンティティを Go 構造体として表したり、その構造体を Cloud Datastore に格納して取得したりできます。

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

種類と識別子

Cloud Datastore の各エンティティは特定の種類に属しています。種類とは、クエリ用にエンティティを分類するものです。たとえば、人事アプリケーションでは、会社の各従業員を Employee という種類のエンティティで表します。Go Datastore API では、datastore.Key を作成するときにエンティティの種類を指定します。2 つのアンダースコア(__)で始まる種類名はすべて予約済みであり、使用できません。

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

import (
	"time"

	"golang.org/x/net/context"

	"google.golang.org/appengine/datastore"
)

type Employee struct {
	FirstName          string
	LastName           string
	HireDate           time.Time
	AttendedHRTraining bool
}

func f(ctx context.Context) {
	// ...
	employee := &Employee{
		FirstName: "Antonio",
		LastName:  "Salieri",
		HireDate:  time.Now(),
	}
	employee.AttendedHRTraining = true

	key := datastore.NewIncompleteKey(ctx, "Employee", nil)
	if _, err := datastore.Put(ctx, key, employee); err != nil {
		// Handle err
	}
	// ...
}

Employee 型は、データモデルに FirstNameLastNameHireDateAttendedHRTraining の 4 つのフィールドを宣言します。

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

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

エンティティにキー名を割り当てるには、空でない stringID 引数を datastore.NewKey に渡します。

// Create a key with a key name "asalieri".
key := datastore.NewKey(
	ctx,        // context.Context
	"Employee", // Kind
	"asalieri", // String ID; empty means no string ID
	0,          // Integer ID; if 0, generate automatically. Ignored if string ID specified.
	nil,        // Parent Key; nil means no parent
)

Cloud Datastore で数値 ID を自動的に割り当てるには、空の stringID 引数を使用します。

// Create a key such as Employee:8261.
key := datastore.NewKey(ctx, "Employee", "", 0, nil)
// This is equivalent:
key = datastore.NewIncompleteKey(ctx, "Employee", nil)

識別子の割り当て

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]

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

エンティティ グループ

エンティティの親を指定するには、parent 引数を datastore.NewKey に対して使用します。この引数の値は、親エンティティのキーである必要があります。次の例は、種類が Address であるエンティティを作成し、Employee エンティティをその親として指定しています。

// Create Employee entity
employee := &Employee{ /* ... */ }
employeeKey, err := datastore.Put(ctx, datastore.NewIncompleteKey(ctx, "Employee", nil), employee)

// Use Employee as Address entity's parent
// and save Address entity to datastore
address := &Address{ /* ... */ }
addressKey := datastore.NewIncompleteKey(ctx, "Address", employeeKey)
_, err = datastore.Put(ctx, addressKey, address)

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

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

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

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

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

プロパティと値の型

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

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

値の型 Go の型 並べ替え順 備考
整数 int
int8
int16
int32
int64
数値 64 ビット整数(符号付き)
浮動小数点数 float32
float64
数値 64 ビット倍精度、
IEEE 754
ブール値 bool false<true
文字列(短い) string Unicode
最大 1,500 バイト。1,500 バイトを超える値は実行時にエラーになります。
文字列(長い) stringnoindex を含む) なし 最大 1 メガバイト

インデックス未登録
バイトスライス(短い) datastore.ByteString バイト順 最大 1,500 バイト。1,500 バイトを超える値は実行時にエラーになります。
バイトスライス(長い) []byte なし 最大 1 メガバイト

インデックス未登録
日時 time.Time 時系列
地理的座標 appengine.GeoPoint 最初に緯度、
次に経度
Cloud Datastore のキー *datastore.Key パス要素順
(種類、識別子、
種類、識別子...)
Blobstore のキー appengine.BlobKey バイト順

struct または slice を使用してプロパティを集約することもできます。詳細については、Cloud Datastore リファレンスをご覧ください。

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

  1. Null 値
  2. 固定小数点数
    • 整数
    • 日時型
  3. ブール値
  4. バイト列
    • バイトスライス(短い)
    • Unicode 文字列
    • Blobstore のキー
  5. 浮動小数点数
  6. 地理的座標
  7. Cloud Datastore のキー

長いバイトスライスと長い文字列はインデックスに登録されないため、順序付けは定義されていません。

エンティティの操作

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

エンティティの作成

Go で新しいエンティティを作成するには、Go 構造体のインスタンスを作成し、そのフィールドに値を設定したうえで、datastore.Put を呼び出して Datastore に保存します。Cloud Datastore にはエクスポートされたフィールド(大文字で始まるもの)のみが保存されます。エンティティのキー名は、空でない stringID 引数を datastore.NewKey に渡すことで指定できます。

employee := &Employee{
	FirstName: "Antonio",
	LastName:  "Salieri",
	HireDate:  time.Now(),
}
employee.AttendedHRTraining = true
key := datastore.NewKey(ctx, "Employee", "asalieri", 0, nil)
_, err = datastore.Put(ctx, key, employee)

空のキー名を指定するか、または datastore.NewIncompleteKey を使用すると、Cloud Datastore によって数値 ID がエンティティのキーとして自動的に生成されます。

employee := &Employee{
	FirstName: "Antonio",
	LastName:  "Salieri",
	HireDate:  time.Now(),
}
employee.AttendedHRTraining = true
key := datastore.NewIncompleteKey(ctx, "Employee", nil)
_, err = datastore.Put(ctx, key, employee)

エンティティの取得

指定したキーで識別されるエンティティを取得するには、*datastore.Key を引数として datastore.Get 関数に渡します。*datastore.Key を生成するには、datastore.NewKey 関数を使用します。

employeeKey := datastore.NewKey(ctx, "Employee", "asalieri", 0, nil)
addressKey := datastore.NewKey(ctx, "Address", "", 1, employeeKey)
var addr Address
err = datastore.Get(ctx, addressKey, &addr)

datastore.Get は適切な Go 構造体のインスタンスを設定します。

エンティティの更新

既存のエンティティを更新するには、構造体の属性を変更してから、datastore.Put を呼び出します。このデータで既存のエンティティが上書きされます。datastore.Put を呼び出すたびに、オブジェクト全体が Cloud Datastore に送信されます。

エンティティの削除

エンティティを削除するには、datastore.Delete 関数でエンティティのキーを指定します。

key := datastore.NewKey(ctx, "Employee", "asalieri", 0, nil)
err = datastore.Delete(ctx, key)

一括オペレーション

datastore.Putdatastore.Getdatastore.Delete には、それぞれ datastore.PutMultidatastore.GetMultidatastore.DeleteMulti と呼ばれる一括バリアントがあります。これらを使用すると、1 回の Cloud Datastore 呼び出しで複数のエンティティを処理できます。

// A batch put.
_, err = datastore.PutMulti(ctx, []*datastore.Key{k1, k2, k3}, []interface{}{e1, e2, e3})

// A batch get.
var entities = make([]*T, 3)
err = datastore.GetMulti(ctx, []*datastore.Key{k1, k2, k3}, entities)

// A batch delete.
err = datastore.DeleteMulti(ctx, []*datastore.Key{k1, k2, k3})

一括オペレーションを実行してもコストは変わりません。キーが存在するかどうかにかかわらず、一括オペレーションに含まれるすべてのキーについて課金されます。オペレーションに含まれるエンティティのサイズは、コストに影響しません。

空のリストの使用

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

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

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