インデックスの管理

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 から新しい複合インデックスを手動で作成するには:

  1. Google Cloud コンソールで [データベース] ページに移動します。

    [データベース] に移動

  2. データベースのリストから、必要なデータベースを選択します。

  3. ナビゲーション メニューで、[インデックス] をクリックし、[複合] タブをクリックします。

  4. [インデックスを作成] をクリックします。

  5. コレクション ID を入力します。インデックスを作成するフィールドの名前と各フィールドのインデックス モードを追加します。[インデックスの保存] をクリックします。

複合インデックスのリストに新しいインデックスが表示され、Firestore がインデックスの作成を開始します。インデックスの作成が完了すると、インデックスの横に緑色のチェックマークが表示されます。

複合インデックスを削除する

複合インデックスを削除するには:

  1. Google Cloud コンソールで [データベース] ページに移動します。

    [データベース] に移動

  2. データベースのリストから、必要なデータベースを選択します。

  3. ナビゲーション メニューで、[インデックス] をクリックし、[複合] タブをクリックします。

  4. 複合インデックスのリストで、削除するインデックスのその他ボタン をクリックします。[削除] をクリックします。

  5. アラートから [インデックスの削除] をクリックして、このインデックスを削除することの確認を行います。

単一フィールドのインデックス除外を追加する

単一フィールドのインデックス除外では、コレクションの特定のフィールドの自動インデックス設定をオーバーライドできます。コンソールから、単一フィールド除外を追加できます。

  1. Google Cloud コンソールで [データベース] ページに移動します。

    [データベース] に移動

  2. データベースのリストから、必要なデータベースを選択します。

  3. ナビゲーション メニューで [インデックス] をクリックし、[単一フィールド] タブをクリックします。

  4. [除外を追加] をクリックします。

  5. コレクション IDフィールドパスを入力します。

  6. このフィールドの新しいインデックス設定を選択します。このフィールドに対して自動的に更新される昇順、降順、配列を含む単一フィールド インデックスを有効または無効にします。

  7. [除外を保存] をクリックします。

コレクション レベルの除外を追加する

コレクション ID の下にあるすべてのフィールドに適用される単一フィールド インデックス除外を定義するには:

  1. [除外を追加] をクリックします。
  2. コレクション グループの [コレクション ID] を入力し、[フィールドパス] を * に設定します。

    除外するフィールドを選択

  3. コレクション グループ内のすべてのフィールドに適用するインデックス除外を選択します。

  4. [除外を保存] をクリックします。

単一フィールド インデックス除外を削除する

単一フィールド インデックス除外を削除するには、次のようにします。

  1. Google Cloud コンソールで [データベース] ページに移動します。

    [データベース] に移動

  2. データベースのリストから、必要なデータベースを選択します。

  3. ナビゲーション メニューで [インデックス] をクリックし、[単一フィールド] タブをクリックします。

  4. 単一フィールド インデックス除外リストで、削除する [さらに表示] ボタン をクリックします。[削除] をクリックします。

  5. アラートから [削除] をクリックして、この除外を削除することの確認を行います。

単一フィールド除外を削除すると、指定されたフィールドまたはサブフィールドは継承されたインデックス設定を使用します。ドキュメント フィールドは、データベースの自動インデックス設定に戻ります。マップ内のサブフィールドは、親フィールドの除外を継承してから、自動インデックス設定を継承します。

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 に移行できます。移行するには、次のようにします。

  1. 同等の google_firestore_index リソースを記述します。
  2. 既存の Datastore モード インデックスを新しいリソースにインポートします。
  3. 古い google_datastore_index リソースへの参照を削除します。
  4. Terraform の状態から古い google_datastore_index リソースを削除します。
  5. terraform apply を実行して変更を適用します。

詳しい手順は次のとおりです。

  1. 既存の google_datastore_index リソースに基づいて、置換用の google_firestore_index を記述します。必要な変更については、下記をご覧ください。
  2. インデックスの 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 名に置き換えます。

  3. 既存の 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 リファレンス ドキュメントをご覧ください。

  4. Terraform 構成ファイルから既存の google_datastore_index リソースを削除します。
  5. Terraform の状態から既存の google_datastore_index リソースを削除します。

    terraform state rm google_datastore_index.datastore-index-resource-name
    

    リソースの削除の詳細については、Terraform のリソースの削除のページをご覧ください。

  6. terraform plan を実行します。出力を確認して、リソースが作成または破棄されていないことを確認します。

    出力を調べて、インポートが正常に完了したことを確認します。出力にフィールドの変更が示されている場合は、これらの変更が意図したとおりであることを確認してください。出力に次のような行が含まれている場合。

    google_firestore_index.firestore-index-resource-name must be replaced
    

    次に、Terraform 構成ファイルを調べて間違いがないか確認します。

  7. Terraform プランの出力に満足したら、次の内容を実行します。

    terraform apply
    

  8. インデックスを翻訳する

    google_datastore_index リソースを同等の google_firestore_index リソースに変換するには、リソースをコピーして次の変更を行います。

    • google_datastore_indexgoogle_firestore_index に置き換えます。
    • 引数名 kindcollection に置き換えますが、引数値は同じにします。
    • 引数名 ancestorquery_scope に置き換えます。引数値 ALL_ANCESTORSCOLLECTION_RECURSIVE に置き換え、他の値を COLLECTION_GROUP に置き換えます。ancestor 引数がない場合は、値 COLLECTION_GROUPquery_scope 引数を追加します。
    • DATASTORE_MODE_API の引数 api_scope を追加します。
    • properties の各インスタンスを、対応する fields のインスタンスに置き換えます。name の各インスタンスを field_path に置き換え、direction の各インスタンスを order に置き換えます。

    たとえば、次の 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 フィールドの値で、オペレーション全体のステータスが確認できます。

    長時間実行オペレーションのステータスをリクエストすると、workEstimatedworkCompleted の指標も合わせて返されます。これらの指標はドキュメント数で返されます。workEstimated には、オペレーションで処理される推定の合計ドキュメント数が表示されます。workCompleted には、これまでに処理されたドキュメント数が表示されます。オペレーションが完了すると、workCompleted には実際に処理されたドキュメントの合計数が反映されます。これは workEstimated の値とは異なる場合があります。

    進行した割合を大まかに得るには、workCompletedworkEstimated で割ります。この割合は、最新の統計情報コレクションとの間に遅延があるために正確ではない可能性があります。

    例として、インデックス構築の進行状況を次に示します。

    {
      "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 がインデックスを作成しているデータで問題を検出すると、インデックス作成オペレーションに失敗する可能性があります。多くの場合、インデックスの上限に達すると、この問題が発生します。たとえば、オペレーションでドキュメントあたりの最大インデックス エントリ数に達した可能性があります。

    インデックスの作成に失敗すると、コンソールにエラー メッセージが表示されます。インデックスの上限に達していないことを確認した後、インデックス オペレーションを再試行します。