インデックスの管理
Firestore では、すべてのクエリにインデックスを使用することで、クエリのパフォーマンスを維持しています。最も基本的なクエリに必要なインデックスは、自動的に作成されます。Cloud Firestore を使用すると、アプリを使用してテストする際に、アプリで必要な追加のインデックスを簡単に作成できます。このページでは、単一フィールド インデックスと複合インデックスの管理方法について説明します。
不足しているインデックスをエラー メッセージから作成する
一方、既存のインデックスに対応しない range 句で複合クエリを実行すると、エラーが発生します。このエラー メッセージに含まれている Firebase コンソールのリンクを使用すると、不足しているインデックスを作成できます。
Firebase コンソールへのリンクをクリックして、自動的に入力された情報を確認し、[作成] をクリックします。
ロールと権限
Firestore でインデックスを作成する前に、自身に次のいずれかのロールが割り当てられていることを確認してください。
roles/datastore.owner
roles/datastore.indexAdmin
roles/editor
roles/owner
カスタムロールを定義している場合、インデックスを作成するには次のすべての権限を割り当ててください。
datastore.indexes.create
datastore.indexes.delete
datastore.indexes.get
datastore.indexes.list
datastore.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 リソースタイプを使用します。
Firestore ネイティブ モードと Datastore モードの両方のインデックスがサポートされています。単一フィールド インデックス
次の 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 に置き換えます。
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_PATH
firestore-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 がインデックスを作成しているデータで問題を検出すると、インデックス作成オペレーションに失敗する可能性があります。多くの場合、インデックスの上限に達すると、この問題が発生します。たとえば、オペレーションでドキュメントあたりの最大インデックス エントリ数に達した可能性があります。
インデックスの作成に失敗すると、コンソールにエラー メッセージが表示されます。インデックスの上限に達していないことを確認した後、インデックス オペレーションを再試行します。