BigQuery Advent Calendar 2020の6日目の記事です。
下記のようなテーブルデータで、各アイテム同士のコサイン距離やユークリッド距離をさくっとBigQueryで計算する方法を解説します。(セルフジョインっぽいやり方をしていて、BigQuery的に良いやり方ではないかもしれません..少量のデータでサクッと計算したいときにご参考ください。もっと良いやり方がありましたら、教えて下さい。)
今回のデータは、各アイテムに3つの属性値が付いていて、それを元に似ているをアイテムを抽出したい場合を考えます。また、各アイテムの属性は今後増えていくことも想定して、その場合でも対応できるクエリを考えます。
WITH
item_vectors AS (
SELECT
item_id,
ARRAY_AGG(attribute_value
ORDER BY
attribute_index) AS attribute_values
FROM
`xxx-yyy-zzz.sandbox.items`
GROUP BY
item_id )
SELECT
item_vectors1.item_id,
item_vectors2.item_id,
(
SELECT
1-SUM(value1 * value2)/ SQRT(SUM(value1 * value1))/ SQRT(SUM(value2 * value2))
FROM
UNNEST(item_vectors1.attribute_values) AS value1
WITH
OFFSET
pos1
JOIN
UNNEST(item_vectors2.attribute_values) AS value2
WITH
OFFSET
pos2
ON
pos1 = pos2 ) AS cosine_distance,
(
SELECT
SQRT( SUM((value1 - value2)*(value1 - value2)))
FROM
UNNEST(item_vectors1.attribute_values) AS value1
WITH
OFFSET
pos1
JOIN
UNNEST(item_vectors2.attribute_values) AS value2
WITH
OFFSET
pos2
ON
pos1 = pos2 ) AS euclidean_distance
FROM
item_vectors item_vectors1
JOIN
item_vectors item_vectors2
ON
item_vectors1.item_id != item_vectors2.item_id
ORDER BY
item_vectors1.item_id,
item_vectors2.item_id
まずは、各アイテムごとに集約して、属性値をArrayとして持ちます。その後に、セルフジョインして、アイテム×アイテムの類似度を計算していきます。
コサイン距離やユークリッドの計算には、UNNESTとOFFSETを利用することで、計算を簡単にすることができます。