これは「関連記事表示 by Vector Search 2.0」のデモサイトです。記事コンテンツはソリューションブログから引用しています。
KARTE Datahub上のデータでCraft Vector Searchのベクトルデータを更新する

KARTE Datahub上のデータでCraft Vector Searchのベクトルデータを更新する

こんにちは、Customer Engineerのgamiです!今更『No No Girls』にハマっています。

さて今回は、KARTE Datahubで実行したクエリの実行結果を使って、Craft Vector Searchのベクトルデータを更新する方法を紹介します。

Craft Vector Searchは、ベクトル検索技術を活用した機能を提供するサービスです。セマンティック検索と呼ばれる、言葉の意味やニュアンスを汲み取った検索を実現できます。

たとえば次のようなユースケースを想定した機能です。

Craft Vector Searchの想定ユースケース例:

  • 商品のセマンティック検索: 大量にある商品データに対してあいまいなワードで検索
  • AIレコメンド: ユーザーにヒアリングした内容とニュアンスが近いアイテムをAIがレコメンド
  • 類似記事の特定: 大量にある記事コンテンツについて、各記事と内容が近い記事を特定

Craft Vector Searchを使ったベクトル検索機能を実装する際、検索対象となるベクトルデータをCraft Vector Searchに事前投入する必要があります。例えば商品レコメンデーション機能を実装する場合、商品マスタデータをベクトル化して登録しておく必要があります。

現状のCraft Vector Searchの仕様では、ベクトルデータの書き込みはCraft Functions経由でおこなう必要があります。大量のデータを一括で投入したい場合は、KARTE Datahub上にあるデータをまとめてCraft Functionsに連携してCraft Vector Searchを更新できると便利です。

そこで今回は、KARTE Datahubにあるデータを使って定期的にCraft Vector Searchのベクトルデータを更新する方法について紹介します。

アウトプットイメージ

今回の記事では、「アパレル商品のデータをCraft Vector Searchに入れたい」という状況を例に手順を紹介します。アパレル商品はスタイルやユーザーの好みの幅が広く、曖昧な検索ワードで商品を探せるセマンティック検索との相性が良い商品ジャンルの1つです。

アウトプットのイメージは次の通りです。

まず、対象のアパレル商品データを抽出するDatahubクエリを用意します。

このクエリ結果をCraft Vector Searchに連携するためのDatahubジョブフローを実行します。

その結果、Craft Vector Searchにベクトルデータがupsertされます。

Craft Vector Searchに格納されたベクトルデータは、前述したようなセマンティック検索に活用できるようになります。

構成図は次の通りです。

対象データを抽出するDatahubクエリを作成し、Datahubジョブフローを介してその実行結果を1レコードずつCraft Functionsに渡します。そのデータをCraft AI Modulesでベクトル化し、Craft Vector Searchにそのベクトルデータをupsertします。

なお、入稿したいデータの種類が複数ある場合は、Datahubクエリやファンクションをその分だけ作成する必要があります。

ちなみに本記事ではCraft Vector Search上のデータを更新する方法だけを説明しており、実際にそのデータを検索で利用する方法については次の記事で紹介しています。

Craft Vector Searchを使ってセマンティック検索を実現する

注意点

前提として、次の点に注意をしてください。

  • KARTE Datahub、Craft Functions、Craft Vector Search、Craft AI Modulesを利用できるKARTEプロジェクトが必要です

設定手順

設定の手順は次の通りです。

  1. Craft Vector Searchのインデックスを作成する
  2. データ抽出用のDatahubクエリを作成する
  3. Craft Vector Search更新用のCraft Functionsを作成する
  4. クエリ結果をファンクションに連携するDatahubジョブフローを作成する

順番に見てみましょう。

1. Craft Vector Searchのインデックスを作成する

Craft Vector Searchのインデックスを作成します。すでに作成済みのインデックスを利用する場合は、この手順はスキップしてください。

  • [すべてのメニュー > Craft > ベクターサーチ > 新規作成] をクリックします
  • 次の項目を設定してインデックスを作成します
    • [名前] : 命名規則に合わせて適当に入力
    • [次元数] : 1408 を設定
  • 作成されたインデックスの「インデックスId」をコピーして控えておきます
    • 後でファンクションの設定で使用します

ちなみに、扱うベクトルデータの次元数が同じであれば、1つのインデックスに複数種類のデータをまとめて格納することもできます。具体的には、データ種別毎にpartition名を指定することで複数種類のデータを同一インデックス内に格納できます。このpartition名は、後述するファンクションの変数で設定できます。

インデックスの次元数をどう設定すべきかについては後述します。

2. データ抽出用のDatahubクエリを作成する

Craft Vector Searchに格納したいデータを抽出するために、Datahubクエリを作成します。

  • [すべてのメニュー > Datahub > クエリ] からクエリ作成画面を開きます
  • 次のサンプルクエリの内容でクエリを作成し保存します
    • ここでは、「AIレコメンド用の商品データをCraft Vector Searchに投入する」というケースを想定しています
SELECT
  item_id
  , item_name
  , price
  , description
  , category
  , brand
  , FALSE AS __delete
FROM (
  SELECT 'ITEM001' AS item_id, 'エレガント シルクブラウス' AS item_name, 12800 AS price, '上質なシルク素材を使用したエレガントなブラウス' AS description, 'トップス' AS category, 'Luxaria' AS brand
  UNION ALL
  SELECT 'ITEM002' AS item_id, 'プレミアム ストレートデニム' AS item_name, 18500 AS price, '最高品質のデニム生地を使用したスタイリッシュなジーンズ' AS description, 'ボトムス' AS category, 'Vevanna' AS brand
  UNION ALL
  SELECT 'ITEM003' AS item_id, 'クラシック レザージャケット' AS item_name, 45000 AS price, '本革を使用したタイムレスなデザインのジャケット' AS description, 'アウター|ジャケット' AS category, 'Zephyros' AS brand
)
ORDER BY item_id

後に作成するCraft Functionsを実行することで、このクエリ結果の指定した列がテキストとして結合され、ベクトル化してCraft Vector Searchに格納されます。

ちなみに今回紹介するファンクションのテンプレートでは、Datahubクエリ結果の__deleteフィールドの値をTRUEにすることでCraft Vector Searchから対象アイテムデータを削除できるようになっています。詳細については後述します。

3. Craft Vector Search更新用のCraft Functionsを作成する

Craft Vector Search更新用のCraft Functionsを作成します。作成手順は次の通りです。

  • [すべてのメニュー > Craft > ファンクション] からファンクション一覧画面を開きます

  • [新規作成 > テンプレートから作成] を選択します

  • KARTE Datahub上のデータでCraft Vector Searchのベクトルデータを更新する 」というテンプレートを検索し[取得]ボタンをクリックします

  • [反映] ボタンをクリックします

  • [設定] タブでファンクションのタイプイベント駆動タイプに設定します

  • [変数] タブで次の変数の値を設定します

    • INDEX_ID
      • 手順1で作成したCraft Vector SearchのインデックスIDを指定します
    • DIMENSION_NUM
      • 手順1で作成したCraft Vector Searchのインデックスの次元数を指定します
      • 今回の例: 1408
    • HEADER_COLUMNS
      • クエリ結果の列名をカンマ区切りで指定します
      • 今回の例: item_id,item_name,price,description,category,brand,__delete
    • ID_FIELD
      • クエリ結果のフィールドの中で、Craft Vector Search側でdatapoint_idとして使用するフィールド名を指定します
      • 今回の例: item_id
    • TEXT_FIELDS
      • クエリ結果のフィールドの中で、ベクトル化対象のテキストが含まれるフィールド名をカンマ区切りで指定します
      • 今回の例: item_name,description
    • NAMESPACE_FIELDS
      • クエリ結果のフィールドの中で、フィルタリング検索に使用するフィールド名をカンマ区切りで指定します
      • 今回の例: category,brand
    • PARTITION_NAME
      • パーティション名のベースとなる名前を指定します
      • 今回の例: items
      • 内部的には、テキストデータと画像データが別々のパーティションとして格納できるように、ここで指定したパーティション名に自動でsuffixが付与されます(後述)
    • その他の変数は、ひとまずデフォルト値のままで問題ありません
  • 適当なファンクション名をつけて [デプロイ] します

なお、テンプレートのソースコードはGitHubで公開されています。

craft-codes/craft-functions/datahub-to-vectorsearch at main · plaidev/craft-codes

4. クエリ結果をファンクションに連携するDatahubジョブフローを作成する

作成したDatahubクエリの結果をCraft Functionsに連携するためのDatahubジョブフローを作成します。

  • [すべてのメニュー > Datahub > ジョブフロー] からジョブフロー一覧画面を開きます
  • [作成] ボタンを押下し、次の設定でジョブフローを作成します
    • [エクスポート元 > クエリの選択]
      • 作成したクエリを選択
    • [エクスポート先]
      • 外部サービス
    • [接続先]
      • Craftに連携するための接続先を選択
    • [function名]
      • 作成したファンクションの名前を指定
    • [行ごとにqueue をpublishする]
      • チェックを入れる

「行ごとにqueue をpublishする」のチェックを入れることで、クエリ結果1行毎に1回のCraft Functions実行がされ、1件ずつデータが処理されるようになります。

実際に動かしてみる

実際に動作を確認してみましょう。

作成したDatahubジョブフローを実行し、完了を待ちます。

問題なく設定できていれば、Craft Vector Searchにベクトルデータが追加され管理画面上の「密ベクトル数」が増加します。

なお、Craft Vector Search管理画面へのベクトル数の反映には時間がかかる場合があります。Craft Functions側でエラーログなどが出ていない場合は、少し待ってから確認してください。

補足

本記事で紹介したファンクションのテンプレートは、様々な要件に対応できるように汎用的に作られています。詳細を補足します。

投入されるデータの形式について

今回のファンクションテンプレートにおける変数の設定を変えることで、Craft Vector Search上でどのようにデータを格納するかを変更することができます。

データ形式に関わるファンクション変数:

  • HEADER_COLUMNS
    • Datahubクエリ結果の全フィールドを指定します
    • ここで指定されたフィールドしか他の変数では利用できません
  • ID_FIELD
    • ここで指定したフィールドの値が、Vector Search側のdatapoint_id(データを区別するためのID)に利用されます
    • 1つのフィールドしか設定できません
  • TEXT_FIELDS
    • ここで指定したフィールド群の値は、item_id:ITEM001\nitem_name:エレガント シルクブラウス\n...のように1つのテキストにまとめられ、テキストベクトル化されます
    • 検索の条件に含めたいテキスト値が格納されたフィールドをすべて指定してください
    • 複数設定する場合は、カンマ区切りで設定します
  • NAMESPACE_FIELDS
    • ここで指定したフィールド群は、Vector Search投入時のrestrictsに設定され、検索時のフィルタリングで利用できるようになります
      • 商品データであれば、たとえばカテゴリやブランドを指定した検索を実現できます
    • 複数設定する場合は、カンマ区切りで設定します

対応しているモーダル

Craft AI Modulesでは、テキストだけではなく画像のEmbeddings(ベクトル化)にも対応しています。

今回のファンクションテンプレートでも、Craft Vector Searchに対して次のパターンでベクトルデータを投入することができるようになっています。

ベクトルデータの投入パターン:

  • テキストベクトルだけを投入する
  • 画像ベクトルだけを投入する
  • 同一アイテムに関するテキストベクトルと画像ベクトルの両方を投入する

こうしたパターンに対応するためには、ファンクションの変数にある TEXT_FIELDSIMAGE_URL_FIELD に適切な値を設定してください。

TEXT_FIELDSIMAGE_URL_FIELDの設定方法:

  • TEXT_FIELDS にはテキストベクトルの元となるフィールド名をカンマ区切りで指定します
  • 画像データを扱う場合は、Datahubクエリ結果に画像URLを含めて、そのフィールド名をIMAGE_URL_FIELDで指定します
  • IMAGE_URL_FIELDは1フィールドしか指定できず、同時に複数の画像をベクトル化することはできません
  • TEXT_FIELDSを指定せずIMAGE_URL_FIELDを指定することで、画像データのみをベクトル化することもできます
  • TEXT_FIELDSIMAGE_URL_FIELDの両方を指定することで、1回の処理で同時にテキストベクトルと画像ベクトルを生成することも可能です

テキストと画像のマルチモーダルな検索に対応しておくと、たとえばユーザーの入力テキストに対して意味的に類似する画像を持つアイテムを検索したり、ユーザーがアップロードした画像に対して意味的に類似するテキストや画像を持つアイテムを検索したりすることができます。

マルチモーダル対応をせずにコストを下げる方法

今回のファンクションテンプレートでは、テキストと画像の両方のベクトルデータを扱うことを想定して、デフォルトではCraft AI ModulesのaiModules.gcpEmbeddingsMulti()を使っています。

一方で、マルチモーダル対応をせずテキストだけを扱いたい場合は、ファンクションのJS中にあるUSE_MULTI_EMBEDDINGという変数の値をfalseにすることで、代わりにaiModules.gcpEmbeddingsText()を使うことができます。 これによって、ベクトル化の際のAIトークン消費量を節約することができます。

「次元数」の設定について

2026年1月現在、Craft AI ModulesのEmbeddings機能の制約により、マルチモーダルの場合は1408次元、テキストのみの場合は768次元が最低の次元数になります。

Craft Vector Searchのインデックス作成時の次元数についても、実際に運用する場合はどちらのEmbeddingsを使うかによって設定値を決めてください。

なお、次元数が大きいほどCraft Vector Search上でのデータサイズは大きくなります。

キーワード検索とのハイブリッド検索について

今回のファンクションテンプレートでは、ベクトルデータを利用したセマンティック検索だけではなく、セマンティック検索とキーワード検索を混ぜ合わせたハイブリッド検索を実現したいという要件にも対応しています。

具体的には、ファンクションの変数にあるBM25_MODEL_URLを設定することで、キーワード検索のためのスパースベクトルの生成や投入にも対応しています。

ただし、その方法の詳細説明については、長くなるので別の記事にて紹介します。

partitionについて

Craft Vector Searchにおいて、次元数が同じであれば、1つのインデックスに複数種類のベクトルデータを投入することができます。そうすることで利用するインデックス数を節約でき、コストを抑えることができます

たとえば商品データとスタッフデータを同じインデックスで管理したいとき、PARTITION_NAMEproductstaffなどと指定することで、同一インデックス内で複数種類のデータを分けて管理することができます。

ちなみに今回のテンプレートではマルチモーダルに対応するために、PARTITION_NAMEで指定したpartition名に加えて、テキストデータと画像データを区別するために ${PARTITION_NAME}_text/image のようなsuffixが自動でpartitionに付与されるようになっています

データの削除について

今回のテンプレートでは、クエリ結果およびHEADER_COLUMNS__deleteというフィールドを用意し、値をTRUEにすることで、対象のdatapoint_idのデータが削除されるようになっています。

たとえば商品マスタを定期的にCraft Vector Searchに連携するとき、商品マスタ側で削除された商品をCraft Vector Search側でも削除する必要があります。そういった対応が必要なときには、この__deleteフィールドをFALSEに設定します。

ちなみに同一アイテムに対してテキストベクトルと画像ベクトルの両方を格納している場合、そのどちらも削除されるような仕様になっています。

おわりに

今回はKARTE Datahubのデータを使ってCraft Vector Searchを更新する方法について紹介しました。

Craft Vector Searchを活用したベクトル検索やレコメンデーション機能を実装する際、大量のデータを効率的に投入することが重要です。今回紹介したファンクションのテンプレートを使えば、対象データを抽出するDatahubクエリを作成するだけで、簡単にCraft Vector Searchのデータを更新できます。

なお、ベクトルデータを格納したCraft Vector Searchに対して実際に検索を実行する方法については、次の記事も合わせてご覧ください!

Craft Vector Searchを使ってセマンティック検索を実現する