BigQueryMLを使うことで、BigQuery上のテーブルデータを元にエンベディングを生成し、生成したエンベディングを用いて類似度の計算などが行えます。
BigQuery上のテーブルの特定のカラムに対して、セマンティック検索を試します。
検索元テーブルを用意
pixabayというフリー音源サイトを元に、track名、サイトURL、タグ情報を持つテーブルを作成しました。
タグ情報を元にセマンティック検索できるようにします。
BigQueryからVertexAIのモデルを使用するための準備
クラウドリソースへの接続を作成
データセットと同じロケーションに接続を作成します。
コマンドラインで接続を作成するには以下を実行。
bq mk --connection --location=REGION --project_id=PROJECT_ID \
--connection_type=CLOUD_RESOURCE CONNECTION_ID
次の値を自身の環境に合わせて置き換えます。
-
REGION
: データセットと同じリージョン。(asia-northeast1 など) -
PROJECT_ID
: Google CloudのプロジェクトID -
CONNECTION_ID
: 接続のID。 bqml_test_connection などと適当に命名してください。
作成されたサービスアカウントは以下コマンドで確認できます。
bq show --connection PROJECT_ID.REGION.CONNECTION_ID
サービスアカウントにアクセス権を付与する
先ほど作成した接続の使用権限をサービスアカウントに付与します。
gcloud projects add-iam-policy-binding 'PROJECT_NUMBER' --member='serviceAccount:MEMBER' --role='roles/aiplatform.user' --condition=None
次の値を自身の環境に合わせて置き換えます。
-
PROJECT_NUMBER
: Google Cloudのプロジェクト番号 -
MEMBER
: 先ほど作成したサービスアカウントのID
モデルをBigQuery上に作成
textembedding-gecko モデルをリモートモデルとして登録します。
CREATE OR REPLACE MODEL `DATASET_ID.MODEL_ID`
REMOTE WITH CONNECTION `PROJECT_ID.REASION.CONNECTION_ID`
OPTIONS (REMOTE_SERVICE_TYPE = 'CLOUD_AI_TEXT_EMBEDDING_MODEL_V1');
次の値を自身の環境に合わせて置き換えます。
-
DATASET_ID
: 今回使用するデータセットのID -
MODEL_ID
: 作成するモデルのID。 embedding_model などと適当に命名してください。 -
PROJECT_ID
: Google CloudのプロジェクトID -
REGION
: データセットと同じリージョン -
CONNECTION_ID
: 先ほど作成した接続のID
テーブルにEmbedding列を追加
登録したモデルを ML.GENERATE_TEXT_EMBEDDING という BigQuery ML 関数を介して呼び出すことでエンべディングを生成します。
CREATE OR REPLACE TABLE `DATASET_ID.music_list_embedding` AS (
-- music_listテーブルのtag列からEmbedding列を作成
WITH tag_embedding AS (
SELECT *
FROM ML.GENERATE_TEXT_EMBEDDING(
MODEL `DATASET_ID.embedding_model`,
(
SELECT
track_id,
tag as content
FROM
`DATASET_ID.music_list`
),
STRUCT(TRUE AS flatten_json_output)
)
)
-- music_listテーブルにtext_embedding列を追加
SELECT
music_list.*,
tag_embedding.text_embedding
FROM `DATASET_ID.music_list` as music_list
JOIN tag_embedding
ON music_list.track_id = tag_embedding.track_id
);
ML.GENERATE_TEXT_EMBEDDINGの第二引数で、変換する対象のテキストを渡します。
今回はtag列のテキストを変換します。
このとき、Embeddingする対象のカラム名をcontent
として渡す必要があります。
FLOAT型 REPEATEDモードのtext_embedding列が追加されました。
セマンティック検索してみる
ML.DISTANCE という BigQuery ML 関数を使ってベクトル間の距離を計算します。
検索元テーブルの各行との距離が最も近い(数値が低い)曲を今回は検索結果として解釈します。
-- 質問文をベクトル化
WITH search_word_embedding AS (
SELECT *
FROM ML.GENERATE_TEXT_EMBEDDING(
MODEL `DATASET_ID.embedding_model`,
(SELECT "都会の夜道で聞きたいlofiな曲" AS content),
STRUCT(TRUE AS flatten_json_output)
)
)
-- 質問文と music_list のベクトル空間上の距離を計算し、近い順に出力する
SELECT
m_list.track_id AS track_id,
m_list.track_name AS track_name,
m_list.url AS track_url,
m_list.tag AS track_tag,
s_word.content AS search_word,
ML.DISTANCE(m_list.text_embedding, s_word.text_embedding, 'COSINE') AS distance
FROM
`DATASET_ID.music_list_embedding` AS m_list,
search_word_embedding AS s_word
ORDER BY distance ASC;
「都会の夜道で聞きたいlofiな曲」と検索した場合が以下。
「lofi」や「都市」などの文字に反応してちゃんとlofiな曲がレコメンドされた。
検索でマッチした曲:https://pixabay.com/ja/music/good-night-160166/
もう少し難易度を上げて、直接的にマッチするタグがない状態での検索も試します。
「サッカーに合う曲」と検索した場合が以下。
今回の検索語の場合、直接的にマッチするタグ情報を持つ曲はありませんが、
「スポーツ」や「パワー」、「過激」などのサッカーと類似してそうなタグを持つ曲が最近傍と算出されました。
検索でマッチした曲:https://pixabay.com/ja/music/for-future-bass-159125/