アクティブ インデックスの更新と再構築

概要

大規模な検索クエリでは、情報を常に最も正確に維持するため、インデックスの更新が重要です。現在、ベクトル検索インデックスは、バッチ アップデートを使用して更新できます。これにより、バッチ スケジュールに従って、またはストリーミング アップデートによってデータポイントの挿入と削除を行い、わずか数秒間でインデックスの更新とクエリを実行できます。

また、UpdateIndex を使用して、display_namedescriptionlabels などの重要なメタデータ フィールドを更新することもできます。オプションのタグをインデックスに追加して、結果の多様化やインデックス前のクエリのフィルタリングを行うこともできます。

バッチ インデックスの更新

既存の Index の内容を更新するには、IndexService.UpdateIndex メソッドを使用します。

既存の Index のコンテンツを置き換えるには:

  • Index.metadata.contentsDeltaUri を、更新するベクトルを含む Cloud Storage URI に設定します。
  • isCompleteOverwrite を true に設定します。true に設定すると、インデックス全体が、指定した新しいメタデータ ファイルで完全に上書きされます。

IndexService.UpdateIndex の呼び出し時に contentsDeltaUri フィールドを設定するなら、同じ呼び出しで他のインデックス フィールド(displayNamedescriptionuserLabels など)は更新できません。

gcloud

  1. インデックス メタデータ ファイルを更新します
  2. gcloud ai indexes update コマンドを使用します

後述のコマンドデータを使用する前に、次のように置き換えます。

  • LOCAL_PATH_TO_METADATA_FILE: メタデータ ファイルのローカルパス。
  • INDEX_ID: インデックスの ID。
  • LOCATION: Vertex AI を使用するリージョン。
  • PROJECT_ID: Google Cloud プロジェクト ID

次のコマンドを実行します。

Linux、macOS、Cloud Shell

gcloud ai indexes update INDEX_ID \
    --metadata-file=LOCAL_PATH_TO_METADATA_FILE \
    --region=LOCATION \
    --project=PROJECT_ID

Windows(PowerShell)

gcloud ai indexes update INDEX_ID `
    --metadata-file=LOCAL_PATH_TO_METADATA_FILE `
    --region=LOCATION `
    --project=PROJECT_ID

Windows(cmd.exe)

gcloud ai indexes update INDEX_ID ^
    --metadata-file=LOCAL_PATH_TO_METADATA_FILE ^
    --region=LOCATION ^
    --project=PROJECT_ID

REST

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

  • INPUT_DIR: インデックス コンテンツの Cloud Storage ディレクトリ パス。
  • INDEX_ID: インデックスの ID。
  • LOCATION: Vertex AI を使用するリージョン。
  • PROJECT_ID: Google Cloud プロジェクト ID
  • PROJECT_NUMBER: プロジェクトに自動生成されたプロジェクト番号

HTTP メソッドと URL:

PATCH https://LOCATION-aiplatform.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/indexes/INDEX_ID

リクエストの本文(JSON):

{
 "metadata": {
   "contentsDeltaUri": "INPUT_DIR",
   "isCompleteOverwrite": true
 }
}

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

次のような JSON レスポンスが返されます。

{
 "name": "projects/PROJECT_NUMBER/locations/LOCATION/indexes/INDEX_ID/operations/OPERATION_ID",
 "metadata": {
   "@type": "type.googleapis.com/google.cloud.aiplatform.v1.UpdateIndexOperationMetadata",
   "genericMetadata": {
     "createTime": "2022-01-12T23:56:14.480948Z",
     "updateTime": "2022-01-12T23:56:14.480948Z"
   }
 }
}

コンソール

バッチ インデックスのコンテンツを更新するには、次の手順で操作します。

  1. Google Cloud コンソールの [Vertex AI] セクションで、[Deploy and Use] セクションに移動します。[ベクトル検索] を選択します。

    [ベクトル検索] に移動

  2. 更新するインデックスを選択します。[インデックスの情報] ページが開きます。
  3. [インデックスを編集] を選択します。インデックスの編集ペインが開きます。
  4. [Cloud Storage] フィールドで、ベクトルデータが保存されている Cloud Storage フォルダを検索して選択します。
  5. (省略可)既存のデータをすべて上書きする場合は、[完全な上書き] チェックボックスをオンにします。
  6. [更新] をクリックします。
  7. [完了] をクリックしてパネルを閉じます。

Index に関連するデプロイがある場合(Index.deployed_indexes フィールドを参照)、元の Index への特定の変更が完了すると、その変更を反映するため、バックグラウンドで非同期的に DeployedIndex が自動更新されます。

変更が伝播されたかどうかを確認するには、更新インデックス オペレーションの終了時間と DeployedIndex.index_sync_time を比較します。

ストリーミング インデックスの更新

ストリーミング アップデートにより、数秒以内にインデックスを更新してクエリを実行できます。現時点では、既存のバッチ アップデート インデックスに対してストリーミング アップデートは使用できません。新しいインデックスを作成する必要があります。詳細については、ストリーミング アップデートのインデックスを作成するをご覧ください。

ストリーミング アップデートに使用される 1 GB あたり $0.45 が課金されます。料金の詳細については、Vertex AI の料金ページをご覧ください。ストリーミング アップデートは、メモリ内にデプロイされたインデックスに直接適用され、その後少し遅延してクエリ結果に反映されます。

データポイントの upsert

これらのサンプルを使用して、データポイントを upsert する方法を説明します。upsert-datapoints は配列形式の JSON のみを受け入れます。

Python

Python

def stream_update_vector_search_index(
    project: str, location: str, index_name: str, datapoints: Sequence[dict]
) -> None:
    """Stream update an existing vector search index

    Args:
      project (str): Required. The Project ID
      location (str): Required. The region name, e.g. "us-central1"
      index_name (str): Required. The index to update. A fully-qualified index
        resource name or a index ID.  Example:
        "projects/123/locations/us-central1/indexes/my_index_id" or
        "my_index_id".
      datapoints: Sequence[dict]: Required. The datapoints to be updated. The dict
        element should be of the IndexDatapoint type.
    """
    # Initialize the Vertex AI client
    aiplatform.init(project=project, location=location)

    # Create the index instance from an existing index with stream_update
    # enabled
    my_index = aiplatform.MatchingEngineIndex(index_name=index_name)

    # Upsert the datapoints to the index
    my_index.upsert_datapoints(datapoints=datapoints)

Curl

スループットの割り当て上限は、upsert に含まれるデータの量に関連します。データポイント ID がインデックスにある場合、エンベディングが更新されます。それ以外の場合は、新しいエンベディングが追加されます。

  
  DATAPOINT_ID_1=
  DATAPOINT_ID_2=
  curl -H "Content-Type: application/json" -H "Authorization: Bearer `gcloud auth print-access-token`" https://${LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${LOCATION}/indexes/${INDEX_ID}:upsertDatapoints \
  -d '{datapoints: [{datapoint_id: "'${DATAPOINT_ID_1}'", feature_vector: [...]},
  {datapoint_id: "'${DATAPOINT_ID_2}'", feature_vector: [...]}]}'
  
  

公開プレビュー版のハイブリッド検索では、データポイントのスパースなエンベディング表現と密なエンベディング表現がサポートされています。upsert オペレーションで密エンベディングを省略すると密表現が削除され、スパース エンベディングを省略するとスパース表現が削除されます。

この例では、密エンベディングとスパース エンベディングの両方を更新します。

  
    curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer `gcloud auth print-access-token`"  https://${LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${LOCATION}/indexes/${INDEX_ID}:upsertDatapoints -d '{datapoints: [{datapoint_id: "111", feature_vector: [0.111, 0.111], "sparse_embedding": {"values": [111.0,111.1,111.2], "dimensions": [10,20,30]}}]}'
  
  

この例では、密エンベディングを更新し、スパース エンベディングを削除します。

    
      curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer `gcloud auth print-access-token`"  https://${LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${LOCATION}/indexes/${INDEX_ID}:upsertDatapoints -d '{datapoints: [{datapoint_id: "111", feature_vector: [0.111, 0.111]}]}'
    
  

この例では、スパース エンベディングを更新し、密エンベディングを削除します。

    
      curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer `gcloud auth print-access-token`"  https://${LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${LOCATION}/indexes/${INDEX_ID}:upsertDatapoints -d '{datapoints: [{datapoint_id: "111",  "sparse_embedding": {"values": [111.0,111.1,111.2], "dimensions": [10,20,30]}}]}'
    
  

コンソール

コンソール

ストリーミング インデックスのコンテンツを更新するには、次の手順で操作します。

  1. Google Cloud コンソールで、[ベクトル検索] ページに移動します。

    [ベクトル検索] に移動

  2. 更新するインデックスを選択します。[インデックスの情報] ページが開きます。
  3. [インデックスを編集] をクリックします。インデックスの編集ペインが開きます。
  4. このペインで [データポイントの Upsert] タブを選択して、コンテンツを追加します。
  5. データポイント ID を入力します。
  6. エンベディングのタイプを 1 つ以上入力します。
    • 密エンベディング: カンマ区切りの浮動小数点値の配列を入力します。値の数は、インデックスのディメンションと一致している必要があります。
    • スパース エンベディング(公開プレビュー):
      1. スパース エンベディングのディメンションを、カンマ区切りの整数の配列として入力します。値の数はインデックスのディメンションと一致している必要はありません。
      2. 値は、カンマ区切りの浮動小数点値の配列として入力します。値の数は、スパース エンベディングのディメンションの数と一致している必要があります。
  7. 省略可: このデータポイントでトークン制限によるフィルタリングを有効にするには、[トークン制限を追加] をクリックし、名前空間とトークンとしてカンマ区切りの文字列を入力します。
  8. 省略可: このデータポイントで数値制限によるフィルタリングを有効にするには、[数値制限を追加] をクリックして名前空間を入力し、数値型を選択して値を入力します。
  9. 省略可: 類似する結果が多数表示されるのを防ぐには、クラウディング タグ文字列を入力します。
  10. [Upsert] をクリックします。
  11. [完了] をクリックしてパネルを閉じます。

スループットの割り当て上限は、upsert に含まれるデータの量に関連します。データポイント ID がインデックスにある場合、エンベディングが更新されます。それ以外の場合は、新しいエンベディングが追加されます。

動的なメタデータの更新

ストリーミング制限や数値制限の更新が必要になる理由はさまざまです。たとえば、大容量で急速に変化するデータを処理する場合に、特定のデータ ストリームを優先したい場合です。制限または数値制限を直接更新すると、リアルタイムでフォーカスを絞り込み、最も重要なデータをすぐに処理またはハイライト表示できます。

完全に更新する場合の圧縮コストがかかることはなく、ストリーミング インデックス内のデータポイント制限と数値制限を直接更新できます。

これらのメタデータのみの更新を実行するには、リクエストに update_mask フィールドを追加する必要があります。update_mask の値は all_restricts に設定する必要があります。データポイントに設定された制限値と数値制限値は、更新で適用する新しい値にする必要があります。

次の例は、既存の 2 つのデータポイントに制限を追加する方法を示しています。

DATAPOINT_ID_1=
DATAPOINT_ID_2=

curl -H "Content-Type: application/json" -H "Authorization: Bearer gcloud auth print-access-token" https://${LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${LOCATION}/indexes/${INDEX_ID}:upsertDatapoints \
-d '{datapoints:
[{datapoint_id: "'${DATAPOINT_ID_1}'", feature_vector: [...],  restricts:[{namespace: "color", allow_list: ["red"]}]},
{datapoint_id: "'${DATAPOINT_ID_2}'", feature_vector: [...],  restricts:[{namespace: "color", allow_list: ["red"]}]}
], update_mask: "all_restricts"}'

データポイントの削除

ストリーミング インデックスからデータポイントの削除が必要になる場合があります。これを行うには、curl または Google Cloud コンソールを使用します。

インデックスからデータポイントを削除する主なユースケースとして、インデックスと実際のソースの間の整合性の維持が挙げられます。ベクトル エンベディングを使用して検索やおすすめのために書籍の在庫を表示する、書籍販売業者の場合を考えてみましょう。書籍が売り切れた場合や、在庫から削除した場合は、関連するデータポイントをインデックスから削除することで、検索結果とおすすめを正確かつ最新の状態に保てます。

Curl


curl -H "Content-Type: application/json" -H "Authorization: Bearer `gcloud auth print-access-token`" https://{LOCATION}-aiplatform.googleapis.com/v1/projects/{PROJECT_ID}/locations/{REGION}/indexes/{INDEX_ID}:removeDatapoints -d '{datapoint_ids: ["'{DATAPOINT_ID_1}'", "'{DATAPOINT_ID_2}'"]}'

コンソール

コンソール

ストリーミング インデックスからデータポイントを削除するには、次の手順で操作します。

  1. Google Cloud コンソールの [Vertex AI] セクションで、[Deploy and Use] セクションに移動します。[ベクトル検索] を選択します。

    [ベクトル検索] に移動

  2. 更新するストリーミング インデックスを選択します。[インデックスの情報] ページが開きます。
  3. [インデックスを編集] を選択します。インデックスの編集ペインが開きます。
  4. このペインで [データポイントの削除] タブを選択します。
  5. データポイント ID のカンマ区切りリストを指定すれば、最大 20 個のデータポイントを追加できます
  6. [削除] をクリックします。
  7. [完了] をクリックしてパネルを閉じます。

圧縮

インデックスは、前回の再構築以降に行われたすべての更新を反映して、定期的に再構築されます。この再構築(圧縮)により、クエリのパフォーマンスと信頼性が向上します。圧縮は、ストリーミング アップデートとバッチ アップデートの両方で行われます。

  • ストリーミング アップデート: ベクトル検索では、ヒューリスティック ベースの指標を使用して圧縮をトリガーするタイミングを決定します。最も古いものが 5 日以上前の未圧縮データである場合、圧縮は常にトリガーされます。ストリーミング アップデートの費用に加えて、バッチ アップデートと同じ頻度でインデックスを再構築する費用も課金されます。

  • バッチ アップデート: 増分データセット サイズが基本データセット サイズの 20% を超えるときに行われます。

インデックスの再構築とクエリ

gRPC CLI、クライアント ライブラリ、または Vertex AI SDK for Python を使用して、通常どおりに一致リクエストまたはバッチ一致リクエストを送信できます。クエリを再構築すると、数秒以内に更新が反映されます。インデックスをクエリする方法については、インデックスをクエリして最近傍を取得するをご覧ください。

省略可能フィールド

インデックスを作成するとき、クエリの微調整に使用できる省略可能フィールドがいくつかあります。

制限付きのアップサート

インデックスをアップサートして制限を追加するのは、データポイントにタグを付けて、クエリ時にフィルタリング対象として識別されるようにする方法です。クエリを送信する前に、データに表示される結果を制限するため、制限タグを追加するのが望ましいこともあります。たとえば、インデックスでクエリを実行するとき、「フットウェア」の検索で「赤」に一致するアイテムのみが結果に表示されるようにすることを考えます。以下の例では、インデックスが upsert され、すべての赤い靴でフィルタリングが行われていますが、青い靴は拒否されています。これにより、実行前に大規模で多様なインデックスから、最適な特定のオプションで検索をフィルタリングできます。

この例では、トークン制限に加えて数値制限も使用しています。この場合、データポイントは価格 20、長さ 0.3、幅 0.5 に関連付けられます。クエリの実行時に、これらの数値制限を使用して結果をフィルタリングし、クエリの結果を価格、長さ、幅の値に制限できます。たとえば、このデータポイントは、価格が 25 より大きい、長さが 1 より小さい、幅が 1 より小さい、というフィルタのクエリで表示されます。

フィルタリングの詳細については、インデックス作成用のベクトル検索をご覧ください。

Python

# Upsert datapoints
_TEST_DATAPOINT_1 = aiplatform_v1.types.index.IndexDatapoint(
    datapoint_id="3",
    feature_vector=[0.00526886899, -0.0198396724],
    restricts=[
        aiplatform_v1.types.index.IndexDatapoint.Restriction(namespace="Color", allow_list=["red"])
    ],
    numeric_restricts=[
        aiplatform_v1.types.index.IndexDatapoint.NumericRestriction(
            namespace="cost",
            value_int=1,
        )
    ],
)
_TEST_DATAPOINT_2 =  aiplatform_v1.types.index.IndexDatapoint(
    datapoint_id="4",
    feature_vector=[0.00526886899, -0.0198396724],
    numeric_restricts=[
        aiplatform_v1.types.index.IndexDatapoint.NumericRestriction(
            namespace="cost",
            value_double=0.1,
        )
    ],
    crowding_tag=aiplatform_v1.types.index.IndexDatapoint.CrowdingTag(crowding_attribute="crowding"),
)
_TEST_DATAPOINT_3 = aiplatform_v1.types.index.IndexDatapoint(
    datapoint_id="5",
    feature_vector=[0.00526886899, -0.0198396724],
    numeric_restricts=[
        aiplatform_v1.types.index.IndexDatapoint.NumericRestriction(
            namespace="cost",
            value_float=1.1,
        )
    ],
)

_TEST_DATAPOINTS = [_TEST_DATAPOINT_1, _TEST_DATAPOINT_2, _TEST_DATAPOINT_3]

my_streaming_index = my_streaming_index.upsert_datapoints(datapoints=_TEST_DATAPOINTS)

# Dynamic metadata update
_TEST_DATAPOINT_4 = aiplatform_v1.types.index.IndexDatapoint(
    datapoint_id="-2",
    numeric_restricts=[
        aiplatform_v1.types.index.IndexDatapoint.NumericRestriction(
            namespace="cost",
            value_float=1.1,
        )
    ],
)
my_streaming_index = my_streaming_index.upsert_datapoints(datapoints=[_TEST_DATAPOINT4], update_mask=["all_restricts"])

curl

curl -H "Content-Type: application/json" -H "Authorization: Bearer `gcloud auth print-access-token`" https://${ENDPOINT}/v1/projects/${PROJECT_ID}/locations/us-central1/indexes/${INDEX_ID}:upsertDatapoints \
-d '{
datapoints: [
  {
    datapoint_id: "'${DATAPOINT_ID_1}'",
    feature_vector: [...],
    restricts: { namespace: "color", allow_list: ["red"], deny_list: ["blue"]},
    numeric_restricts: [{namespace: "price", value_int: 20}, {namespace: "length", value_float: 0.3}, {namespace: "width", value_double: 0.5}]
  }
]}'

クラウディングでのアップサート

クラウディング タグは、検索結果の多様性を改善することで、類似の結果を制限します。クラウディングは、最近傍検索によって生成される近傍リストに対する制約で、同じ crowding_attribute の値について、少数の値、または結果のグループしか返されないようにします。たとえば、オンラインで靴を購入することを考えます。結果において、さまざまな色の靴を含め、しかしスタイルについてはサッカー用スパイクのように 1 つのスタイルに限ることが望まれる場合があります。データポイントを挿入するとき、crowding_attribute を靴の色に設定したと想定すると、クエリで per_crowding_attribute_num_neighbors = 3 を設定すると、返される結果で同じ色の靴を 3 足以下にするよう指定できます。

このフィールドは、同じクラウディング タグで許容される最大一致数を表します。

curl -H "Content-Type: application/json" -H "Authorization: Bearer `gcloud auth print-access-token`" https://${ENDPOINT}/v1/projects/${PROJECT_ID}/locations/us-central1/indexes/${INDEX_ID}:upsertDatapoints \
-d '{
datapoints: [
  {
    datapoint_id: "'${DATAPOINT_ID_1}'",
    feature_vector: [...],
    restricts: { namespace: "type", allow_list: ["cleats"]}
    crowding_tag: { crowding_attribute: "red-shoe"},
  }
]}'

次のステップ