インデックスの管理
Firestore では、すべてのクエリにインデックスを使用することで、クエリのパフォーマンスを維持しています。最も基本的なクエリに必要なインデックスは、自動的に作成されます。Cloud Firestore を使用すると、アプリを使用してテストする際に、アプリで必要な追加のインデックスを簡単に作成できます。このページでは、単一フィールド インデックス、複合インデックス、[ベクトル][ベクトル] インデックスの管理方法について説明します。
不足しているインデックスをエラー メッセージから作成する
一方、既存のインデックスに対応しない range 句で複合クエリを実行すると、エラーが発生します。このエラー メッセージに含まれている Firebase コンソールのリンクを使用すると、不足しているインデックスを作成できます。
Firebase コンソールへのリンクをクリックして、自動的に入力された情報を確認し、[作成] をクリックします。
ベクトル インデックスが必要な場合、エラー メッセージには、不足しているベクトル インデックスを作成する Google Cloud CLI コマンドが含まれます。コマンドを実行して、不足しているインデックスを作成します。
ロールと権限
Firestore でインデックスを作成する前に、自身に次のいずれかのロールが割り当てられていることを確認してください。
roles/datastore.ownerroles/datastore.indexAdminroles/editorroles/owner
カスタムロールを定義している場合、インデックスを作成するには次のすべての権限を割り当ててください。
datastore.indexes.createdatastore.indexes.deletedatastore.indexes.getdatastore.indexes.listdatastore.indexes.update
Google Cloud Platform Console を使用する
Google Cloud Platform Console から、単一フィールドのインデックス除外と複合インデックスを管理できます。
複合インデックスを作成する
GCP Console から新しい複合インデックスを手動で作成するには:
Google Cloud コンソールで [データベース] ページに移動します。
データベースのリストから、必要なデータベースを選択します。
ナビゲーション メニューで、[インデックス] をクリックし、[複合] タブをクリックします。
[インデックスを作成] をクリックします。
コレクション ID を入力します。インデックスを作成するフィールドの名前と各フィールドのインデックス モードを追加します。[インデックスの保存] をクリックします。
複合インデックスのリストに新しいインデックスが表示され、Firestore がインデックスの作成を開始します。インデックスの作成が完了すると、インデックスの横に緑色のチェックマークが表示されます。
複合インデックスを削除する
複合インデックスを削除するには:
Google Cloud コンソールで [データベース] ページに移動します。
データベースのリストから、必要なデータベースを選択します。
ナビゲーション メニューで、[インデックス] をクリックし、[複合] タブをクリックします。
複合インデックスのリストで、削除するインデックスのその他ボタン をクリックします。[削除] をクリックします。
アラートから [インデックスの削除] をクリックして、このインデックスを削除することの確認を行います。
単一フィールドのインデックス除外を追加する
単一フィールドのインデックス除外では、コレクションの特定のフィールドの自動インデックス設定をオーバーライドできます。コンソールから、単一フィールド除外を追加できます。
Google Cloud コンソールで [データベース] ページに移動します。
データベースのリストから、必要なデータベースを選択します。
ナビゲーション メニューで [インデックス] をクリックし、[単一フィールド] タブをクリックします。
[除外を追加] をクリックします。
コレクション ID とフィールドパスを入力します。
このフィールドの新しいインデックス設定を選択します。このフィールドに対して自動的に更新される昇順、降順、配列を含む単一フィールド インデックスを有効または無効にします。
[除外を保存] をクリックします。
コレクション レベルの除外を追加する
コレクション ID のすべてのフィールドに適用される単一フィールド インデックス除外を定義するには:
- [除外を追加] をクリックします。
コレクション グループの [コレクション ID] を入力し、[フィールドパス] を
*に設定します。
コレクション グループ内のすべてのフィールドに適用するインデックス登録除外を選択します。
[除外を保存] をクリックします。
単一フィールド インデックス除外を削除する
単一フィールド インデックス除外を削除するには、次のようにします。
Google Cloud コンソールで [データベース] ページに移動します。
データベースのリストから、必要なデータベースを選択します。
ナビゲーション メニューで [インデックス] をクリックし、[単一フィールド] タブをクリックします。
単一フィールド インデックス除外リストで、削除する [さらに表示] ボタン をクリックします。[削除] をクリックします。
アラートから [削除] をクリックして、この除外を削除することの確認を行います。
単一フィールド除外を削除すると、指定されたフィールドまたはサブフィールドは継承されたインデックス設定を使用します。ドキュメント フィールドは、データベースの自動インデックス設定に戻ります。マップ内のサブフィールドは、親フィールドの除外を継承してから、自動インデックス設定を継承します。
Firebase CLI を使用する
Firebase CLI を使用してインデックスをデプロイすることもできます。まず、プロジェクト ディレクトリで firebase init firestore を実行します。設定中に、デフォルトのインデックスが正しい形式で含まれている JSON ファイルが Firebase CLI により生成されます。ファイルを編集してインデックスを追加し、firebase deploy コマンドを使用してデプロイします。
Firestore のインデックスとルールのみをデプロイするには、--only firestore フラグを追加します。
Firebase コンソールでインデックスを編集する場合は、必ずローカル インデックス ファイルも更新してください。JSON インデックス定義リファレンスをご覧ください。
Terraform を使用
データベースのインデックスを作成する
Firestore データベースには、単一フィールド インデックスと複合インデックスの両方を含めることができます。Terraform 構成ファイルを編集して、データベースのインデックスを作成できます。単一フィールド インデックスと複合インデックスでは、異なる Terraform リソースタイプ(google_firestore_index と google_firestore_field)が使用されます。
単一フィールド インデックス
次の Terraform 構成ファイルの例では、chatrooms コレクションの name フィールドに単一フィールド インデックスを作成します。
firestore.tf
resource "random_id" "variable"{
byte_length = 8
}
resource "google_firestore_field" "single-index" {
project = "project-id"
database = "database-id"
collection = "chatrooms_${random_id.variable.hex}"
field = "name"
index_config {
indexes {
order = "ASCENDING"
query_scope = "COLLECTION_GROUP"
}
indexes {
array_config = "CONTAINS"
}
}
ttl_config {}
}
- project-id を実際のプロジェクト ID に置き換えます。プロジェクト ID は一意である必要があります。
- database-id をデータベース ID に置き換えます。
複合インデックス
次の Terraform 構成ファイルの例では、chatrooms コレクションの name フィールドと description フィールドの組み合わせに複合インデックスを作成します。
firestore.tf
resource "google_firestore_index" "composite-index" {
project = "project-id"
database = "database-id"
collection = "chatrooms"
fields {
field_path = "name"
order = "ASCENDING"
}
fields {
field_path = "description"
order = "DESCENDING"
}
}
- project-id を実際のプロジェクト ID に置き換えます。プロジェクト ID は一意である必要があります。
- database-id をデータベース ID に置き換えます。
ベクトル インデックス
次の Terraform 構成ファイルの例では、chatrooms コレクションの embedding フィールドにベクトル インデックスを作成します。
firestore.tf
resource "google_firestore_index" "vector-index" {
project = "project-id"
database = "database-id"
collection = "chatrooms"
fields {
field_path = "__name__"
order = "ASCENDING"
}
fields {
field_path = "embedding"
vector_config {
dimension = 128
flat {}
}
}
}
- project-id を実際のプロジェクト ID に置き換えます。プロジェクト ID は一意である必要があります。
- database-id をデータベース ID に置き換えます。
Datastore モードのインデックス
Terraform を使用して Datastore モードのインデックスを作成することもできます。
datastore.tf
resource "google_firestore_index" "datastore-mode-index" {
project = "project-id"
database = "database-id"
collection = "chatrooms"
fields {
field_path = "name"
order = "ASCENDING"
}
fields {
field_path = "description"
order = "DESCENDING"
}
query_scope = "COLLECTION_GROUP"
api_scope = "DATASTORE_MODE_API"
}
google_datastore_index から移行する
google_datastore_index リソースは非推奨であり、terraform-provider-google バージョン 6.0.0 以降では使用できなくなります。
以前に google_datastore_index リソースを使用していた場合は、google_firestore_index に移行できます。移行するには、次のようにします。
- 同等の
google_firestore_indexリソースを記述します。 - 既存の Datastore モード インデックスを新しいリソースにインポートします。
- 古い
google_datastore_indexリソースへの参照を削除します。 - Terraform の状態から古い
google_datastore_indexリソースを削除します。 terraform applyを実行して変更を適用します。
詳しい手順は次のとおりです。
- 既存の
google_datastore_indexリソースに基づいて、置き換え用のgoogle_firestore_indexを記述します。必要な変更については、下記をご覧ください。 - インデックスの Firestore リソースパスを特定します。
export INDEX_RESOURCE_PATH=$(echo '"projects/${google_datastore_index.datastore-index-resource-name.project}/databases/(default)/collectionGroups/${google_datastore_index.datastore-index-resource-name.kind}/indexes/${google_datastore_index.datastore-index-resource-name.index_id}"' | terraform console | tr -d '"')datastore-index-resource-name を既存のリソースの Terraform 名に置き換えます。
- 既存の Datastore モード インデックスを、前に作成した
google_firestore_indexリソースにインポートします。terraform import google_firestore_index.firestore-index-resource-name $INDEX_RESOURCE_PATHfirestore-index-resource-name を既存のリソースの Terraform 名に置き換えます。
Firestore インデックス リソースのインポートの詳細については、google_firestore_index リファレンス ドキュメントをご覧ください。
- Terraform 構成ファイルから既存の
google_datastore_indexリソースを削除します。 - Terraform の状態から既存の
google_datastore_indexリソースを削除します。terraform state rm google_datastore_index.datastore-index-resource-nameリソースの削除の詳細については、Terraform のリソースの削除のページをご覧ください。
terraform planを実行します。出力を確認して、リソースが作成または破棄されていないことを確認します。出力を調べて、インポートが正常に完了したことを確認します。出力にフィールドの変更が示されている場合は、これらの変更が意図したとおりであることを確認してください。出力に次のような行が含まれている場合。
google_firestore_index.firestore-index-resource-name must be replaced
次に、Terraform 構成ファイルを調べて間違いがないか確認します。
- Terraform プランの出力に満足したら、次の内容を実行します。
terraform apply google_datastore_indexをgoogle_firestore_indexに置き換えます。- 引数名
kindをcollectionに置き換えますが、引数値は同じにします。 - 引数名
ancestorをquery_scopeに置き換えます。引数値ALL_ANCESTORSをCOLLECTION_RECURSIVEに置き換え、他の値をCOLLECTION_GROUPに置き換えます。ancestor引数がない場合は、値COLLECTION_GROUPのquery_scope引数を追加します。 - 値
DATASTORE_MODE_APIの引数api_scopeを追加します。 propertiesの各インスタンスを、対応するfieldsのインスタンスに置き換えます。nameの各インスタンスをfield_pathに置き換え、directionの各インスタンスをorderに置き換えます。インデックスの設定には数分かかります。インデックスの最小構築時間は、空のデータベースであっても数分です。
バックフィル時間は、新しいインデックスに既存のデータがどの程度存在するかによって異なります。インデックス定義に一致するフィールド値が多いほど、インデックスのバックフィルにかかる時間が長くなります。
インデックスを翻訳する
google_datastore_index リソースを同等の google_firestore_index リソースに変換するには、リソースをコピーして次の変更を行います。
たとえば、次の google_datastore_index リソースについて考えてみましょう。
datastore.tf
resource "google_datastore_index" "legacy" {
kind = "foo"
properties {
name = "property_a"
direction = "ASCENDING"
}
properties {
name = "property_b"
direction = "ASCENDING"
}
}
同等の google_firestore_index リソースは次のようになります。
resource "google_firestore_index" "new" {
// note: defaults to the provider project
project = project
// note: defaults to the (default) database
database = "(default)"
collection = "foo"
api_scope = "DATASTORE_MODE_API"
// since there was no "ancestor" property set above, use COLLECTION_GROUP here
query_scope = "COLLECTION_GROUP"
fields {
field_path = "property_a"
order = "ASCENDING"
}
fields {
field_path = "property_b"
order = "ASCENDING"
}
}
インデックスの構築時間
インデックスを構築するには、Firestore によりインデックスがセットアップされ、既存データにインデックスがバックフィルされる必要があります。インデックスの構築時間は、セットアップ時間とバックフィル時間の合計です。
インデックスの構築は長時間実行オペレーションになります。
インデックスの構築を開始すると、Firestore によりオペレーションに一意の名前が割り当てられます。次のように、オペレーション名の先頭には projects/[PROJECT_ID]/databases/(default)/operations/ という文字列が付きます。
projects/project-id/databases/(default)/operations/ASA1MTAwNDQxNAgadGx1YWZlZAcSeWx0aGdpbi1zYm9qLW5pbWRhEgopEg
ただし、describe コマンドのオペレーション名を指定するときは、接頭辞を省略できます。
すべての長時間実行オペレーションの一覧表示
長時間実行オペレーションを一覧表示するには、gcloud firestore operations list コマンドを使用します。このコマンドは、実行中のオペレーションと最近完了したオペレーションを一覧表示します。オペレーションは、完了後数日間一覧表示されます。
gcloud firestore operations list
オペレーションのステータスを確認する
すべての長時間実行オペレーションを一覧表示する代わりに、1 つのオペレーションの詳細を一覧表示できます。
gcloud firestore operations describe operation-name
完了時間の見積もり
オペレーションを実行すると、state フィールドの値で、オペレーション全体のステータスが確認できます。
長時間実行オペレーションのステータスをリクエストすると、workEstimated と workCompleted の指標も合わせて返されます。これらの指標はドキュメント数で返されます。workEstimated には、オペレーションで処理される推定の合計ドキュメント数が表示されます。workCompleted には、これまでに処理されたドキュメント数が表示されます。オペレーションが完了すると、workCompleted には実際に処理されたドキュメントの合計数が反映されます。これは workEstimated の値とは異なる場合があります。
進行した割合を大まかに得るには、workCompleted を workEstimated で割ります。この割合は、最新の統計情報コレクションとの間に遅延があるために正確ではない可能性があります。
例として、インデックス構築の進行状況を次に示します。
{
"operations": [
{
"name": "projects/project-id/operations/AyAyMDBiM2U5NTgwZDAtZGIyYi0zYjc0LTIzYWEtZjg1ZGdWFmZWQHEjF0c2Flc3UtcmV4ZWRuaS1uaW1kYRUKSBI",
"metadata": {
"@type": "type.googleapis.com/google.firestore.admin.v1.IndexOperationMetadata",
"common": {
"operationType": "CREATE_INDEX",
"startTime": "2020-06-23T16:52:25.697539Z",
"state": "PROCESSING"
},
"progressDocuments": {
"workCompleted": "219327",
"workEstimated": "2198182"
}
},
},
...
オペレーションが完了すると、オペレーションの説明に、"done":
true が含まれます。オペレーションの結果をみるには、state フィールドの値を確認します。done フィールドがレスポンスに設定されていない場合、値は false になります。進行中のオペレーションに関しては、done の値の有無は参考になりません。
インデックス構築エラー
複合インデックスと単一フィールド インデックスの除外を管理するときに、インデックス構築エラーが発生することがあります。Firestore がインデックスを作成しているデータで問題を検出すると、インデックス作成オペレーションに失敗する可能性があります。多くの場合、インデックスの上限に達すると、この問題が発生します。たとえば、オペレーションでドキュメントあたりの最大インデックス エントリ数に達した可能性があります。
インデックスの作成に失敗すると、コンソールにエラー メッセージが表示されます。インデックスの上限に達していないことを確認した後、インデックス オペレーションを再試行します。