複合インデックスの構成

Datastore モードの Firestore はアプリケーションからのすべてのクエリにインデックスを使用します。インデックスは、エンティティが変更されるたびに更新されるため、アプリケーションからのクエリにはすばやく結果が返されます。Datastore モードには組み込みインデックスを自動的に作成する機能がありますが、どの複合インデックスがアプリケーションに必要になるかをあらかじめ認識させる必要があります。アプリケーションに必要な複合インデックスは、構成ファイルで指定します。Datastore エミュレータは、アプリケーションのテストの際に Datastore モード複合インデックス構成を自動的に生成できます。gcloud コマンドライン ツールには、本番環境用の Datastore モード データベースで利用可能なインデックスを更新するコマンドがあります。

システム要件

gcloud CLI を使用するには、Google Cloud CLI をインストールする必要があります。

index.yaml について

アプリケーションで実行されるすべての Datastore モードのクエリには、対応するインデックスが必要です。単純なクエリ用のインデックス(1 つのプロパティに関するクエリなど)は自動的に作成されます。複雑なクエリ用の複合インデックスは、index.yaml という構成ファイルで定義する必要があります。このファイルはアプリケーションとともにアップロードされ、Datastore モードのデータベースに複合インデックスを作成します。

Datastore エミュレータは、構成ファイルに適切なエントリを持たない複合インデックスを必要とするクエリをアプリケーションが実行しようとする際に、このファイルに自動的に項目を追加します。このファイルを編集して、手動で複合インデックスを変更したり、新規に作成したりすることもできます。index.yaml<project-directory>/WEB-INF/ フォルダにあります。デフォルトでは、WEB-INF/appengine-generated/index.yaml が含まれるデータ ディレクトリは ~/.config/gcloud/emulators/datastore/ です。詳細については、Datastore エミュレータのプロジェクト ディレクトリをご覧ください。

index.yaml ファイルの例を次に示します。

indexes:

- kind: Task
  ancestor: no
  properties:
  - name: done
  - name: priority
    direction: desc

- kind: Task
  properties:
  - name: collaborators
    direction: asc
  - name: created
    direction: desc

- kind: TaskList
  ancestor: yes
  properties:
  - name: percent_complete
    direction: asc
  - name: type
    direction: asc

index.yaml の構文は YAML 形式です。この構文について詳しくは、YAML のウェブサイトをご覧ください。

複合インデックスの定義

index.yaml には、indexes という名前のリスト要素が 1 つだけあります。このリストに含まれる各要素は、アプリケーションの複合インデックスを表します。

インデックス要素には、次のような要素があります。

kind
クエリに対応するエンティティの種類です。この要素は必須です。
properties

複合インデックスの列として並べ替え順で収録するプロパティのリスト。最初に等式フィルタで使用するプロパティ、次に不等式フィルタで使用するプロパティ、そして表示順とその方向。

このリスト内の各要素には、次の要素を指定します。

name
プロパティの Datastore モード名です。
direction
並べ替えの方向です。昇順の場合は asc を指定し、降順の場合は desc を指定します。この値は、クエリの並べ替え順序で使用するプロパティについてのみ必要です。また、クエリで使用する方向と同じである必要があります。デフォルトは asc です。
ancestor

クエリに祖先句がある場合は yes。デフォルトは no

自動および手動の複合インデックス

Datastore エミュレータが、生成された複合インデックス定義を index.yaml に追加すると、次の行の下で必要に応じて定義が挿入されます。

# AUTOGENERATED

エミュレータは、この行の下のすべての複合インデックス定義を自動複合インデックスとみなし、アプリケーションがクエリを実行すると、この行の下の既存の定義を更新します。

この行の上の複合インデックス定義は、すべて手動で管理されているものとみなされ、エミュレータによって更新されることはありません。アプリケーションで実行されるクエリを説明する複合インデックスが、完全な index.yaml ファイルに記載されていない場合、エミュレータは行の下のみを変更します。自動複合インデックス定義を管理するには、定義をこの行の上に移動します。

複合インデックスの更新

datastore indexes create コマンドは、ローカルの Datastore 複合インデックス構成(index.yaml ファイル)を確認し、本番環境用の Datastore モード データベースにまだ存在していない複合インデックスが複合インデックス構成で定義されていると、データベースは新しい複合インデックスを作成します。indexes create の使用方法の例については、gcloud CLI を使用した開発ワークフローをご覧ください。

複合インデックスを作成するには、データベースで複合インデックスを設定してから、複合インデックスを既存のデータでバックフィルする必要があります。複合インデックスの作成時間は、セットアップ時間とバックフィル時間の合計です。

  • 複合インデックスの設定には数分かかります。複合インデックスの最小作成時間は、空のデータベースであっても数分です。

  • バックフィル時間は、新しい複合インデックスに既存のデータがどの程度存在するかによって異なります。複合インデックスに存在するプロパティ値が多いほど、複合インデックスのバックフィルにかかる時間が長くなります。

まだビルドが完了していない複合インデックスを要求するクエリをアプリケーションが実行すると、そのクエリでは例外が発生します。これを防ぐには、新しい複合インデックスがビルドを終了する前に、複合インデックスを要求する新しいバージョンのアプリケーションのデプロイに注意する必要があります。

複合インデックスのステータスは、Google Cloud コンソールの [インデックス] ページで確認できます。

使用されていない複合インデックスの削除

複合インデックス構成から複合インデックスを変更または削除しても、元の複合インデックスは Datastore モードのデータベースから自動的に削除されません。これにより、新しい複合インデックスをビルドしながらアプリケーションの古いバージョンを実行したり、新しいバージョンで問題が発見されたらすぐに古いバージョンを復元したりできます。

古い複合インデックスが確実に不要な場合は、datastore indexes cleanup コマンドでそのインデックスを削除できます。このコマンドは、ローカル バージョンの index.yaml に名前リンクを付けられていない本番環境用の Datastore モード インスタンス用のすべての複合インデックスをすべて削除します。indexes cleanup の使用方法の例については、gcloud CLIを使用した開発ワークフローをご覧ください。

コマンドライン引数

複合インデックスの作成および削除のためのコマンドライン引数の詳細については、それぞれ datastore indexes createdatastore indexes cleanup をご覧ください。gcloud CLI のコマンドライン引数の詳細については、gcloud CLI のリファレンスをご覧ください。

長時間実行オペレーションの管理

複合インデックスのビルドは長時間実行オペレーションであるため、完了までにかなりの時間がかかることがあります。

複合インデックスの作成を開始すると、Datastore モードによってオペレーションに一意の名前が割り当てられます。次のように、オペレーション名の先頭には projects/[PROJECT_ID]/databases/(default)/operations/ という文字列が付きます。

projects/project-id/databases/(default)/operations/ASA1MTAwNDQxNAgadGx1YWZlZAcSeWx0aGdpbi1zYm9qLW5pbWRhEgopEg

ただし、describe コマンドのオペレーション名を指定するときは、接頭辞を省略できます。

すべての長時間実行オペレーションの一覧表示

長時間実行オペレーションを一覧表示するには、gcloud datastore operations list コマンドを使用します。このコマンドは、実行中のオペレーションと最近完了したオペレーションをリストします。オペレーションは、完了後数日間リストされます。

gcloud

gcloud datastore operations list

rest

リクエストのデータを使用する前に、次のように置き換えます。

  • project-id: プロジェクト ID

HTTP メソッドと URL:

GET https://datastore.googleapis.com/v1/projects/project-id/operations

リクエストを送信するには、次のいずれかのオプションを展開します。

レスポンスの詳細については、下記をご覧ください。

たとえば、最近完了した複合インデックスのビルドには、次の情報が表示されます。

{
  "operations": [
  {
    "name": "projects/project-id/operations/S01vcFVpSmdBQ0lDDCoDIGRiNTdiZDQNmE4YS0yMTVmNWUzZSQadGx1YWZlZAcSMXRzYWVzdS1yZXhlZG5pLW5pbWRhFQpWEg",
    "done": true,
    "metadata": {
      "@type": "type.googleapis.com/google.datastore.admin.v1.IndexOperationMetadata",
      "common": {
        "endTime": "2020-06-23T16:55:29.923562Z",
        "operationType": "CREATE_INDEX",
        "startTime": "2020-06-23T16:55:10Z",
        "state": "SUCCESSFUL"
      },
      "indexId": "CICAJiUpoMK",
      "progressEntities": {
        "workCompleted": "2193027",
        "workEstimated": "2198182"
      }
    },
    "response": {
      "@type": "type.googleapis.com/google.datastore.admin.v1.Index",
      "ancestor": "NONE",
      "indexId": "CICAJiUpoMK",
      "kind": "Task",
      "projectId": "project-id",
           "properties": [
        {
          "direction": "ASCENDING",
          "name": "priority"
        },
        {
          "direction": "ASCENDING",
          "name": "done"
        },
        {
          "direction": "DESCENDING",
          "name": "created"
        }
      ],
      "state": "READY"
    }
  },
  ]
}

単一オペレーションの記述

すべての長時間実行オペレーションをリストする代わりに、1 つのオペレーションの詳細をリストできます。

gcloud

operations describe コマンドを使用して、複合インデックスのビルドのステータスを表示します。

gcloud datastore operations describe operation-name

rest

リクエストのデータを使用する前に、次のように置き換えます。

  • project-id: プロジェクト ID

HTTP メソッドと URL:

GET https://datastore.googleapis.com/v1/projects/project-id/operations

リクエストを送信するには、次のいずれかのオプションを展開します。

レスポンスの詳細については、下記をご覧ください。

完了時間の見積もり

オペレーションを実行すると、state フィールドの値で、オペレーション全体のステータスが確認できます。

長時間実行オペレーションのステータスをリクエストすると、workEstimatedworkCompleted の指標も合わせて返されます。こうした指標はエンティティの数に対して返されます。workEstimated は、データベース統計情報に基づき、オペレーションが処理すると推定されるエンティティ数の合計を示します。workCompleted には、これまでに処理されたエンティティ数が表示されます。オペレーションが完了すると、workCompleted には実際に処理されたエンティティの合計数が反映されます。これは workEstimated の値とは異なる場合があります。

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

例として、複合インデックスのビルドの進行状況を次に示します。

{
  "operations": [
    {
      "name": "projects/project-id/operations/AyAyMDBiM2U5NTgwZDAtZGIyYi0zYjc0LTIzYWEtZjg1ZGdWFmZWQHEjF0c2Flc3UtcmV4ZWRuaS1uaW1kYRUKSBI",
      "metadata": {
        "@type": "type.googleapis.com/google.datastore.admin.v1.IndexOperationMetadata",
        "common": {
          "operationType": "CREATE_INDEX",
          "startTime": "2020-06-23T16:52:25.697539Z",
          "state": "PROCESSING"
        },
        "progressEntities": {
          "workCompleted": "219327",
          "workEstimated": "2198182"
        }
       },
    },
    ...

オペレーションが完了すると、オペレーションの説明に、"done": true が含まれます。オペレーションの結果をみるには、state フィールドの値を確認します。done フィールドがレスポンスに設定されていない場合、値は false になります。進行中のオペレーションに関しては、done の値の有無は参考になりません。