Vertex AI Search for Retail の在庫を更新する

Product の作成、読み取り、更新、削除(CRUD)メソッドは Product の属性の広範な変更に使用されますが、在庫に固有のフィールドをさまざまな粒度で更新するために使用する一連の Product メソッドもあります。次の Product フィールドが在庫フィールドとみなされます。

  • Product.price_info
  • Product.availability
  • Product.available_quantity
  • Product.fulfillment_info

在庫設定のチュートリアル

このチュートリアルでは、商品全体を更新する代わりに、SetInventory メソッドを使用して在庫の更新を push する方法を示します。


このタスクを Cloud Shell エディタで直接行う際のガイダンスについては、「ガイドを表示」をクリックしてください。

ガイドを表示


フルフィルメント追加のチュートリアル

AddFulfillmentPlaces ではなく AddLocalInventories メソッドを使用することをおすすめします。AddLocalInventories で同じ結果が得られますが、ローカル在庫データの取り込みをより細かく制御できます。詳細については、AddLocalInventories のドキュメントをご確認ください。

このチュートリアルでは、AddFulfillmentPlaces メソッドを使用して商品のフルフィルメント情報を更新する方法について説明します。このようにして、検索は商品が入手可能で注文が納品可能な場所の最新情報を表示できます。たとえば、買い物客が店で青いジーンズを探しているが、在庫切れになっているとします。このショップや他のショップにジーンズが再入荷した時点で、買い物客は更新情報を確認して注文を続行できます。


このタスクを Cloud Shell エディタで直接行う際のガイダンスについては、「ガイドを表示」をクリックしてください。

ガイドを表示


フルフィルメント削除のチュートリアル

RemoveFulfillmentPlaces ではなく RemoveLocalInventories メソッドを使用することをおすすめします。RmoveLocalInventories で同じ結果が得られますが、ローカル在庫データの取り込みをより細かく制御できます。詳細については、RemoveLocalInventories のドキュメントをご確認ください。

このチュートリアルでは、RemoveFulfillmentPlaces メソッドを使用して商品のフルフィルメント情報を更新する方法について説明します。このようにして、Vertex AI Search for Retail は商品が入手不可能で注文が納品不可能な場所の最新情報を表示できます。このようにして、検索は商品が入手不可能で注文が納品不可能な場所の最新情報を表示できます。たとえば、買い物客が店で青いジーンズを探しているとします。ジーンズがこの店舗で在庫切れになった場合、買い物客はこれを見ると注文を続行できません。


このタスクを Cloud Shell エディタで直接行う際のガイダンスについては、「ガイドを表示」をクリックしてください。

ガイドを表示


在庫更新メソッド

商品の在庫情報の変更は、カタログ情報の変更よりも頻繁に発生する可能性があります。そのため、在庫固有の更新を大量に処理するための特別な一連のメソッドが提供されます。これらのメソッドは、パフォーマンスを犠牲にすることなく、商品ごとに数百の同時更新をサポートするダウンストリームの最適化のために、非同期になっています。

増分アップデート

ローカル在庫の更新ガイドに従って、在庫の増分更新を行うことをおすすめします。新しい API メソッドは、場所ごとの在庫属性をよりきめ細かく制御できます。

fulfillment_info は、Product に対する場所レベルのフルフィルメントの可用性をエンコードするためによく使用されます。場合によっては、特定の場所のフルフィルメントの可用性が変わることがあります。その場合、UpdateProduct メソッドを使用して商品全体のフルフィルメント情報を再指定する代わりに、この変更を説明する更新を発行することを決定できます。

そのような場合、AddFulfillmentPlaces メソッドと RemoveFulfillmentPlaces メソッドを使用して、特定のフルフィルメント タイプに対して追加または削除される場所 ID に基づいて商品のフルフィルメントの変更を段階的に更新できます。

Java

Vertex AI Search for Retail のクライアント ライブラリをインストールして使用する方法については、Vertex AI Search for Retail クライアント ライブラリをご覧ください。詳細については、Vertex AI Search for Retail の Java API リファレンス ドキュメントをご覧ください。

Vertex AI Search for Retail に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。

public static AddFulfillmentPlacesResponse addFulfillmentPlaces(
    Product productToUpdate, String fulfillmentInfoType, ImmutableList<String> placeIds)
    throws IOException, InterruptedException, ExecutionException {
  ProductServiceClient productClient = getProductServiceClient();

  AddFulfillmentPlacesRequest request = AddFulfillmentPlacesRequest.newBuilder()
      .setProduct(productToUpdate.getName())
      .setType(fulfillmentInfoType)
      .addAllPlaceIds(placeIds)
      .setAddTime(Timestamps.fromMillis(System.currentTimeMillis()))
      .build();

  AddFulfillmentPlacesResponse response = productClient
      .addFulfillmentPlacesAsync(request).get();

  productClient.shutdownNow();
  productClient.awaitTermination(2, TimeUnit.SECONDS);

  return response;
}

PROTO

  {
    product: "projects/123/locations/global/catalogs/default_catalog/branches/default_branch/products/p123"
    type: "pickup-in-store"
    place_ids: "store0"
    place_ids: "store1"
    add_time: {
      seconds: 100
      nanos: 100
    }
    allow_missing: true
  }
  

このサンプル AddFulfillmentPlacesRequest では、特定の商品の場所 ID "store0""store1" にフルフィルメント タイプ "pickup-in-store" を追加します。AddFulfillmentPlacesRequest.allow_missing は true に設定されているため、商品がまだ存在しない場合でも、最終的に商品が作成されたときに更新された在庫情報が保存されます。更新には、AddFulfillmentPlacesRequest.add_time というタイムスタンプが付けられており、これらの場所 ID のフルフィルメント ステータスが古い更新によってオーバーライドされないようにしています。これらの機能については、次のセクションで詳しく説明します。

この動作は RemoveFulfillmentPlacesRequest とほぼ同じであり、スキーマもよく似ています。

fulfillment_typesAddLocalInventoriesRemoveLocalInventories によって更新されると、それぞれの場所 ID からサポートするフルフィルメント タイプのリストへのマッピングが反映されます。fulfillment_infoAddFulfillmentPlacesRemoveFulfillmentPlaces で更新されると、それぞれの特定のフルフィルメント タイプから各タイプをサポートする場所 ID のリストへのマッピングが反映されます。どちらの API タイプでも同じ基盤となるフルフィルメント情報が変更され、両方のタイプの API の効果は Product.fulfillment_info に反映されます。

非増分アップデート

price_infoavailabilityavailable_quantity は、場所レベルの情報ではなく、商品レベルの在庫を表すため、増分更新できません。また、増分の変更のみではなく、非増分アップデートを fulfillment_info に発行することが望ましい場合もあります。このような場合は、SetInventory メソッドをおすすめします。

Java

Vertex AI Search for Retail のクライアント ライブラリをインストールして使用する方法については、Vertex AI Search for Retail クライアント ライブラリをご覧ください。詳細については、Vertex AI Search for Retail の Java API リファレンス ドキュメントをご覧ください。

Vertex AI Search for Retail に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。

public static SetInventoryResponse setInventoryWithMask(Product productToUpdate,
    FieldMask updateMask)
    throws IOException, ExecutionException, InterruptedException {
  ProductServiceClient productClient = getProductServiceClient();

  SetInventoryRequest request = SetInventoryRequest.newBuilder()
      .setInventory(productToUpdate)
      .setSetMask(updateMask)
      .setSetTime(Timestamps.fromMillis(System.currentTimeMillis()))
      .setAllowMissing(true)
      .build();

  SetInventoryResponse response = productClient.setInventoryAsync(request).get();

  productClient.shutdownNow();
  productClient.awaitTermination(2, TimeUnit.SECONDS);

  return response;
}

PROTO

  {
    product: {
      name: "projects/123/locations/global/catalogs/default_catalog/branches/default_branch/products/p123"
      availability: IN_STOCK
      fulfillment_info: {
        type: "pickup-in-store"
        place_ids: "store0"
        place_ids: "store1"
        place_ids: "store2"
        place_ids: "store3"
      }
      fulfillment_info: {
        type: "same-day-delivery"
      }
    }
    set_time: {
      seconds: 100
      nanos: 100
    }
    set_mask: {
      paths: "availability"
      paths: "fulfillment_info"
    }
    allow_missing: true
  }
  

このリクエストでは、増分仕様とは異なり、SetInventoryRequest.product.fulfillment_info フィールドが各フルフィルメント タイプの有効な場所 ID の完全な説明です。"same-day-delivery" への更新は、この商品のこのフルフィルメント タイプの対象となる場所 ID がないことを示します。他のすべてのフルフィルメント タイプは、このリクエストで更新されません。したがって、このメソッドを使用して、フルフィルメント タイプのサブセットのみの場所 ID を置換し、他のタイプはそのままにすることができます。

デフォルトでは、SetInventorySetInventory.set_mask が未設定または空の場合にすべての在庫フィールドを更新します。マスクが空でない場合、または在庫フィールドが SetInventoryRequest.set_mask に明示的に一覧表示されていない場合、その在庫フィールドの指定された値は更新リクエストで無視されます。

増分更新と同様に、SetInventoryRequest.set_time フィールドを使用して、すべての更新済み在庫フィールドで最後に記録された更新時間に対して更新時間を設定できます。

在庫更新のためのタイムスタンプの保護

商品の在庫フィールドを更新したり、順不同な更新から保護したりするためのいくつかのパスがあり、各在庫フィールドが最新の更新時間に関連付けられます。

最新の更新時間が price_infoavailabilityavailable_quantity(fulfillment_info.place_ids, fulfillment_info.type) の各ペアに対して記録されます。

AddFulfillmentPlaces メソッド、RemoveFulfillmentPlaces メソッド、SetInventory メソッドを使用すると、リクエストの発行時に、呼び出し元が更新時刻を指定できます。この更新時刻が、関連する在庫フィールドに対して記録された最新の更新時刻と比較され、更新時刻が直近の更新時刻より後の場合に限り、更新がコミットされます。

たとえば、場所 ID "store1" でフルフィルメント タイプ "pickup-in- store" が有効で、最後に記録された更新時刻が T に設定されているとします。RemoveFulfillmentPlacesRequest.type = "pickup-in-store"RemoveFulfillmentPlacesRequest.place_ids"store1" を含む場合、RemoveFulfillmentPlacesRequest.remove_timeT より後の場合に限り、リクエストにより "pickup-in-store""store1" から消去されます。AddFulfillmentPlacesRequests の場合も同様です。

price_infoavailabilityavailable_quantity の更新についても、SetInventory は同様に動作します。fulfillment_info の更新時に、SetInventoryRequest は特定のフルフィルメント タイプに指定されたすべての場所 ID を追加し、指定されていない既存の場所 ID をすべて削除するよう暗黙的に要求します。

したがって、SetInventoryRequest が処理されると、fulfillment_info の更新によって、指定されたフルフィルメント タイプごとに AddFulfillmentPlacesRequestRemoveFulfillmentPlacesRequest に暗黙的に変換されます。つまり、フルフィルメント "pickup-in-store" がある既存の場所 "store1" の最終更新時刻 TSetInventoryRequest.set_time よりも新しい場合、"store1""pickup-in-store" での暗黙の追加 / 削除は適用されません。

在庫情報をプリロードする

各在庫更新メソッドでは、呼び出し元がリクエストで allow_missing を設定できます。allow_missing が true に設定されている場合、存在しない Product への在庫の更新は、メソッドの仕様に従って Product が存在しているかのように処理されます。この期間内に対応する ProductCreateProduct を介して作成しない場合、在庫情報は最大 2 日間保持されます。

Java

public static SetInventoryResponse setInventory(Product productToUpdate)
    throws IOException, ExecutionException, InterruptedException {
  ProductServiceClient productClient = getProductServiceClient();

  SetInventoryRequest request = SetInventoryRequest.newBuilder()
      .setInventory(productToUpdate)
      .setSetTime(Timestamps.fromMillis(System.currentTimeMillis()))
      .setAllowMissing(true)
      .build();

  SetInventoryResponse response = productClient.setInventoryAsync(request).get();

  productClient.shutdownNow();
  productClient.awaitTermination(2, TimeUnit.SECONDS);

  return response;
}

Product メソッドを使用するタイミング

商品の CRUD メソッドを使って在庫フィールドを更新することは可能ですが、呼び出し元は既存の在庫情報または既存の在庫情報への影響に注意する必要があります。

これらは同期メソッドであり、在庫メソッドで使用されるダウンストリームの最適化は適用されないため、頻繁に在庫を更新する場合にこれらのメソッドに依存すると、コストが膨大になる可能性があります。可能であれば、前述の在庫の更新メソッドを使用してください。

CreateProduct

在庫フィールドを設定して CreateProduct を呼び出す場合、CreateProductRequest.product で指定された値によって、各フィールドのプリロード済みの値がオーバーライドされます。在庫フィールドが設定されていない場合、既存の在庫情報が自動的に使用されます。

また、オーバーライドされた在庫フィールドの最新の更新時間は、メソッド呼び出しの時間にリセットされます。

プリロード済み在庫を含む CreateProduct

PROTO

{
  parent: "projects/123/locations/global/catalogs/default_catalog/branches/default_branch"
  product_id: "p123"
  product: {
    name: "projects/123/locations/global/catalogs/default_catalog/branches/default_branch/products/p123"
    title: "some product"
    type: VARIANT
  }
}

この例では、作成した商品に在庫フィールドが設定されていません。つまり、在庫更新メソッドを使用して更新された場合、プリロードされた在庫情報が自動的に使用されます。これは、在庫の更新をカタログの更新から切り離し、新しく作成した Product を既存の在庫情報と同期させる場合に便利です。

明示的な在庫のある CreateProduct

PROTO

{
  parent: "projects/123/locations/global/catalogs/default_catalog/branches/default_branch"
  product_id: "p123"
  product: {
    name: "projects/123/locations/global/catalogs/default_catalog/branches/default_branch/products/p123"
    title: "some product"
    type: VARIANT
    availability: OUT_OF_STOCK
    fulfillment_info: {
      type: "pickup-in-store"
    }
    fulfillment_info: {
      type: "same-day-delivery"
    }
  }
}

この例では、在庫フィールドを明示的に設定した Product が作成されます。これらのフィールドは、既存のフィールドをオーバーライドして、対応するフィールドの最終更新時刻を無視します。したがって、新しく作成された Product では可用性が OUT_OF_STOCK に設定され、場所 ID はフルフィルメント タイプ "pickup-in-store""same-day-delivery" をサポートしません。

在庫情報を含む CreateProduct は、プリロードされた在庫情報がすべて正確かどうか不明な場合や、Product の作成時にカタログと在庫を完全に同期するように在庫を明示的に設定します。

UpdateProduct

UpdateProduct が呼び出され、フィールド マスク UpdateProductRequest.update_mask に在庫フィールドが含まれている場合、UpdateProductRequest.product で指定された値がそれぞれのフィールドに対してプリロードされた値をオーバーライドします。

また、オーバーライドされた在庫フィールドの最新の更新時間は、メソッド呼び出しの時間にリセットされます。

PROTO

{
  product: {
    name: "projects/123/locations/global/catalogs/default_catalog/branches/default_branch/products/p123"
    availability: IN_STOCK
    fulfillment_info: {
      type: "pickup-in-store"
      place_ids: "store0"
      place_ids: "store1"
      place_ids: "store2"
      place_ids: "store3"
    }
    fulfillment_info: {
      type: "same-day-delivery"
    }
  }
  update_mask: {
    paths: "availability"
    paths: "fulfillment_info"
  }
}

この例は、各在庫フィールドの最新更新時刻に関係なく更新が確実に適用されるという点を除き、SetInventory の例と非常によく似ています。

在庫の UpdateProduct は、タイムスタンプの保護を無視して、在庫情報の完全な同期が必要な場合に役立ちます。

UpdateProduct を使用して UpdateProductRequest.allow_missingtrue に設定して Product upsert を実行することによって、在庫情報をプリロードすることは可能ですが、このメソッドでは、UpdateProductRequest.product.title などの特定のカタログ フィールドを設定する必要があります。したがって、在庫更新メソッドを使用して、ユースケースをプリロードすることをおすすめします。

DeleteProduct

DeleteProduct が呼び出されると、DeleteProductRequest.name で指定した商品のすべての既存の在庫情報が削除されます。これには、各在庫の最新の更新時刻のすべてのレコードも含まれます。