ベクトルストア入門

9.9K Views

February 01, 25

スライド概要

BuriKaigi2025 2025/2/1 ルーム:マス 17:00-

AI 要約:
このセッションでは、ベクトル検索とベクトルストアについて学びます。ベクトル検索は「近いもの」や「似ているもの」を見つける手法であり、ベクトルストアはベクトルとその関連情報を保存・検索するしくみです。主に PostgreSQL と pgvector を使った方法を中心に、感覚的にわかりやすく説明します。

profile-image

Qiita や Zenn でいろいろ書いてます。 https://qiita.com/hmatsu47 https://zenn.dev/hmatsu47 MySQL 8.0 の薄い本 : https://github.com/hmatsu47/mysql80_no_usui_hon Aurora MySQL v1 → v3 移行計画 : https://zenn.dev/hmatsu47/books/aurora-mysql3-plan-book https://speakerdeck.com/hmatsu47

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

ベクトルストア入門 BuriKaigi2025 2025/2/1 まつひさ(hmatsu47)

2.

自己紹介 松久裕保(@hmatsu47) ● https://qiita.com/hmatsu47 ● Web インフラのお守り係をしています ● 普段は JAWS-UG 名古屋(・浜松)や PostgreSQL アンカンファレンスで DB ネタを中心に話しています ● 実務では MySQL 系の DBを中心に扱っています 2/22(土)に PHP カンファレンス名古屋 2025(名古屋駅前・ ウインクあいち)で MySQL 8.4 以降の話をします 2

3.

本日のお題 ● ベクトル検索およびベクトルストアの話をします ○ ベクトル検索:「近いもの」「似ているもの」を探す ○ ベクトルストア:ベクトル(と関連情報)を保存・検索する仕組み 3

4.

おことわり ● 正確さよりも感覚的なわかりやすさを優先します ○ 「数学も機械学習もなんもわからん」人(私)が同じような人に 向けて話します ● ベクトルストアとしては PostgreSQL+pgvector を中心 に扱います ○ 考え方は他のベクトルストアと共通しています 4

5.

ベクトルとベクトル検索 5

6.

ところで…ベクトルって? ● いくつかの意味がある:例えば ○ ①大きさと向きを持った量 ○ ②数字の組(縦や横に並べたもの) ○ … 6

7.

ところで…ベクトルって? ● いくつかの意味がある:例えば ○ ①大きさと向きを持った量 ○ ②数字の組(縦や横に並べたもの) ○ … この話の中で主に扱うのはこれ 縦向き・横向きがあるが、ここでは主に (1, 2, 3, …) のように横向きに表記する (ベクトルストアで扱う上でも横向きがイメージしやすい) 7

8.

ところで…ベクトルって? ● いくつかの意味がある:例えば ○ ①大きさと向きを持った量 ○ ②数字の組(縦や横に並べたもの) ○ … こちらは途中で少しだけ出てくる 8

9.

突然ですが ● A さんに近いのは誰でしょう?(注:名前以外で・以降同じ) 名前 身長 A さん 170.0 cm B さん 174.5 cm C さん 167.2 cm D さん 186.7 cm ?? 9

10.

突然ですが ● A さんに近いのは誰でしょう? 名前 身長 身長差 A さん 170.0 cm B さん 174.5 cm 4.5 cm C さん 167.2 cm 2.8 cm 差を計算すればわかりやすい D さん 186.7 cm 16.7 cm - 10

11.

体重を加えて… ● A さんに近いのは誰でしょう? 名前 身長 体重 A さん 170.0 cm 64.0 kg B さん 174.5 cm 82.7 kg C さん 167.2 cm 46.8 kg D さん 186.7 cm 76.2 kg ?? 11

12.

体重を加えて… ● A さんに近いのは誰でしょう? 名前 身長 体重 BMI A さん 170.0 cm 64.0 kg 22.15 B さん 174.5 cm 82.7 kg 27.16 C さん 167.2 cm 46.8 kg D さん 186.7 cm 76.2 kg 16.74 比べたいのは 肥満度? 体型? 21.86 体の大きさ? 12

13.

こんなとき ● 近さや類似度をはかるのに便利なのがベクトル 名前 (身長, 体重) 2次元のベクトル A さん (170.0, 64.0) B さん (174.5, 82.7) C さん (167.2, 46.8) D さん (186.7, 76.2) 13

14.

近さ・類似度をはかる方法はいくつかある ● マンハッタン距離(L1 ノルム) 縦軸と横軸の和 【注】グラフの表現の都合上、縦軸 で第1次元、横軸で第2次元を表現し ています(以降同じ) 14

15.

近さ・類似度をはかる方法はいくつかある ● ユークリッド距離(L2 ノルム) 直線距離 15

16.

近さ・類似度をはかる方法はいくつかある ● コサイン類似度 向きの近さ(原点から見て) cosθ:-1(全く似ていない)〜 0(無関係)〜 1(同じ) ● 身長・体重の例では(感覚的に) マンハッタン距離・ユークリッド距離は「体の大きさ」 θ コサイン類似度は「体型」 の近さをはかるのに使えそう? 16

17.

近さ・類似度をはかる方法はいくつかある ● コサイン類似度 ほかにも「内積」などがあるが、 ここでは一旦省略 向きの近さ(原点から見て) cosθ:-1(全く似ていない)〜 0(無関係)〜 1(同じ) ● 身長・体重の例では(感覚的に) マンハッタン距離・ユークリッド距離は「体の大きさ」 θ コサイン類似度は「体型」 の近さをはかるのに使えそう? 17

18.

ここで注意! ● 次元ごとに値の単位や値が取る範囲が違うベクトルで は、各次元の「1」が表す意味に差が生じてしまう ○ 例えば身長の単位が「cm」ではなく「mm」だったら計算結果は さらに変わってしまう ○ そういうときは各次元の値を正規化または標準化して使う手も ■ 正規化・標準化(前処理)の方法によっても計算結果が変わるので注意 18

19.

ここで注意! ● 次元ごとに値の単位や値が取る範囲が違うベクトルで は、各次元の「1」が表す意味に差が生じてしまう ○ 例えば身長の単位が「cm」ではなく「mm」だったら計算結果は さらに変わってしまう ○ そういうときは各次元の値を正規化または標準化して使う手も ■ 正規化・標準化(前処理)の方法によっても計算結果が変わるので注意 前処理の結果、全次元の値が「0」になると コサイン類似度が計算できなくなる問題も(ゼロ(零)ベクトル) 19

20.

正規化・標準化してみる ● まずは 0 ~ 1 の範囲に正規化(計算式などは省略) 名前 (身長, 体重) マンハッタン距離 ユークリッド距離 コサイン類似度 A さん (0.144, 0.479) 0.000 0.000 1.0000 B さん (0.374, 1.000) 0.751 0.570 0.9978 C さん (0.000, 0.000) 0.623 0.500 D さん (1.000, 0.819) 1.196 0.921 0.8295 20

21.

正規化・標準化してみる 距離は「同じものが 0」になる 値が小さいほど似ている ● まずは 0 ~ 1 の範囲に正規化(計算式などは省略) 名前 (身長, 体重) マンハッタン距離 ユークリッド距離 コサイン類似度 A さん (0.144, 0.479) 0.000 0.000 1.0000 B さん (0.374, 1.000) 0.751 0.570 0.9978 C さん (0.000, 0.000) 0.623 0.500 D さん (1.000, 0.819) 1.196 0.921 0.8295 21

22.

正規化・標準化してみる 類似度は「同じものが 1」に 値が大きいほど似ている ● まずは 0 ~ 1 の範囲に正規化(計算式などは省略) 名前 (身長, 体重) マンハッタン距離 ユークリッド距離 コサイン類似度 A さん (0.144, 0.479) 0.000 0.000 1.0000 B さん (0.374, 1.000) 0.751 0.570 0.9978 C さん (0.000, 0.000) 0.623 0.500 D さん (1.000, 0.819) 1.196 0.921 0.8295 22

23.

正規化・標準化してみる 長さ・向きが0 (ゼロベクトル) ● まずは 0 ~ 1 の範囲に正規化(計算式などは省略) 名前 (身長, 体重) マンハッタン距離 ユークリッド距離 コサイン類似度 A さん (0.144, 0.479) 0.000 0.000 1.0000 B さん (0.374, 1.000) 0.751 0.570 0.9978 C さん (0.000, 0.000) 0.623 0.500 D さん (1.000, 0.819) 1.196 0.921 0.8295 23

24.

正規化・標準化してみる ● 標準化(平均 0・標準偏差 1・計算式などは省略) 名前 (身長, 体重) マンハッタン距離 ユークリッド距離 コサイン類似度 A さん (-0.617, -0.251) 0.000 0.000 1.0000 B さん (-0.013, 1.117) 1.972 1.495 -0.3660 C さん (-0.993, -1.509) 1.634 1.313 0.8240 D さん ( 1.623, 0.642) 3.133 2.411 -1.0000 24

25.

正規化・標準化してみる こっちはまあわかる? ● 標準化(平均 0・標準偏差 1・計算式などは省略) 名前 (身長, 体重) マンハッタン距離 ユークリッド距離 コサイン類似度 A さん (-0.617, -0.251) 0.000 0.000 1.0000 B さん (-0.013, 1.117) 1.972 1.495 -0.3660 C さん (-0.993, -1.509) 1.634 1.313 0.8240 D さん ( 1.623, 0.642) 3.133 2.411 -1.0000 25

26.

正規化・標準化してみる こっちはピンとこないかも? 「平均値から見てどうか?」の視点が必要? ● 標準化(平均 0・標準偏差 1・計算式などは省略) 名前 (身長, 体重) マンハッタン距離 ユークリッド距離 コサイン類似度 A さん (-0.617, -0.251) 0.000 0.000 1.0000 B さん (-0.013, 1.117) 1.972 1.495 -0.3660 C さん (-0.993, -1.509) 1.634 1.313 0.8240 D さん ( 1.623, 0.642) 3.133 2.411 -1.0000 26

27.

イメージしやすくするために ● 今回は正規化・標準化せずに比較してみる 名前 (身長, 体重) マンハッタン距離 ユークリッド距離 コサイン類似度 A さん (170.0, 64.0) 0 0 1.0000 B さん (174.5, 82.7) 23.2 19.2 0.9966 C さん (167.2, 46.8) 20.0 17.4 0.9962 D さん (186.7, 76.2) 28.9 20.7 0.9996 27

28.

イメージしやすくするために どちらの距離も 「Cさんが一番近い」と判定 ● 今回は正規化・標準化せずに比較してみる 名前 (身長, 体重) マンハッタン距離 ユークリッド距離 コサイン類似度 A さん (170.0, 64.0) 0 0 1.0000 B さん (174.5, 82.7) 23.2 19.2 0.9966 C さん (167.2, 46.8) 20.0 17.4 0.9962 D さん (186.7, 76.2) 28.9 20.7 0.9996 28

29.

イメージしやすくするために 「Dさんが最も似ている」 ● 今回は正規化・標準化せずに比較してみる 名前 (身長, 体重) マンハッタン距離 ユークリッド距離 コサイン類似度 A さん (170.0, 64.0) 0 0 1.0000 B さん (174.5, 82.7) 23.2 19.2 0.9966 C さん (167.2, 46.8) 20.0 17.4 0.9962 D さん (186.7, 76.2) 28.9 20.7 0.9996 29

30.

要素(次元)が増えても大丈夫 ● 「腹囲」が増えた 名前 (身長, 体重, 腹囲) マンハッタン距離 ユークリッド距離 コサイン類似度 A さん (170.0, 64.0, 77.0) 0 0 1.0000 B さん (174.5, 82.7, 86.6) 32.8 21.5 0.9969 C さん (167.2, 46.8, 71.8) 25.2 18.2 0.9967 D さん (186.7, 76.2, 67.1) 38.8 22.9 0.9965 30

31.

Bさんに変わった 要素(次元)が増えても大丈夫 (Dさんお腹周りが細すぎ?) ● 「腹囲」が増えた 名前 (身長, 体重, 腹囲) マンハッタン距離 ユークリッド距離 コサイン類似度 A さん (170.0, 64.0, 77.0) 0 0 1.0000 B さん (174.5, 82.7, 86.6) 32.8 21.5 0.9969 C さん (167.2, 46.8, 71.8) 25.2 18.2 0.9967 D さん (186.7, 76.2, 67.1) 38.8 22.9 0.9965 31

32.

もう一つ注意 ● 次元数が異なるベクトルの比較はできない ○ 例:MLB 2023 日本人選手 名前 大谷翔平 オオタニサン 鈴木誠也 セイヤサン 吉田正尚 マッチョマン 打率 本塁打 打点 盗塁 勝利 .304 44 95 20 .285 20 74 6 .289 15 72 8 10 敗戦 5 セーブ 防御率 0 3.14 32

33.

打者成績だけで 比較する必要がある もう一つ注意 ● 次元数が異なるベクトルの比較はできない ○ 例:MLB 2023 日本人選手 名前 大谷翔平 オオタニサン 鈴木誠也 セイヤサン 吉田正尚 マッチョマン 打率 本塁打 打点 盗塁 勝利 .304 44 95 20 .285 20 74 6 .289 15 72 8 10 敗戦 5 セーブ 防御率 0 3.14 33

34.

ここまでのまとめ ● 近さや類似度をはかるのに便利なのがベクトル ● ベクトルが近い・似ているものを探すのがベクトル検索 ○ 近さ・類似度をはかる方法はいくつかある ■ どれを選ぶかは対象が持つ性質や探す切り口による ● 比較可能なベクトルを使う必要がある ○ 単位や値の範囲が違う場合は正規化・標準化を検討 ○ 次元数は合わせる 34

35.

ベクトル検索の使い道 35

36.

ベクトル検索の使い道の例 [1] ● レコメンド(推薦)システム ○ 例:オンラインショップで閲覧中の商品に似た商品を「お勧め」 欄に表示 ■ あらかじめ商品の属性(分類や性質など)をベクトル化 ■ ベクトルが近いほうから順に、いくつかの商品をピックアップ ○ 後述のキーワード検索に近い手法を取ることも ■ 商品の入れ替わりが速い・一点ものの販売→属性を個別に登録するのは煩雑 ■ 商品名や説明文を単語に分解してベクトル化 36

37.

ベクトル検索の使い道の例 [2] ● キーワード検索 ○ キーワードの一致度高→検索結果上位に表示 ○ あらかじめ文章を単語別に分解してベクトル化 ○ 例文: ■ ①ブリ会議に来た ■ ②ブリ会議でブリを食べる ■ ③ハマチを食べたい これを形態素解析などの方法で単語に分解して… 37

38.

ベクトル検索の使い道の例 [2] ● キーワード検索 ○ 例えば、単語ごとの出現回数をカウントしてベクトル化する 例文 No. ブリ 会議 に 来 た で を 食べ る ハマチ たい ① 1 1 1 1 1 0 0 0 0 0 0 ② 2 1 0 0 0 1 1 1 1 0 0 ③ 0 0 0 0 0 0 1 1 0 1 1 38

39.

ベクトル検索の使い道の例 [2] ● キーワード検索 ○ 「ブリ会議」でベクトル検索:①と②が上位の候補に 例文 No. ○ ブリ 会議 に 来 た で を 食べ る ハマチ たい ① 1 1 1 1 1 0 0 0 0 0 0 ② 2 1 0 0 0 1 1 1 1 0 0 ③ 0 0 0 0 0 0 1 1 0 1 1 39

40.

ベクトル検索の使い道の例 [2] 「0」の次元がたくさん →疎ベクトル ● キーワード検索 ○ 「ブリ会議」でベクトル検索:①と②が上位の候補に 例文 No. ブリ 会議 に 来 た で を 食べ る ハマチ たい ① 1 1 1 1 1 0 0 0 0 0 0 ② 2 1 0 0 0 1 1 1 1 0 0 ③ 0 0 0 0 0 0 1 1 0 1 1 40

41.

ベクトル検索の使い道の例 [2] ● キーワード検索 ○ 実際には単純に単語の出現回数をカウントするのではなく、 文章中に占める(その)単語の割合 対象となる全文章の中での単語のレア度 などを加味してベクトル化する → TF-IDF・(Okapi)BM25 など 41

42.

ベクトル検索の使い道の例 [3] ● セマンティック検索 ○ キーワードの一致度ではなく意味の近さで文章を検索 ○ 文章のベクトル化には主に LLM の埋め込みモデルを使う ■ 数百~数千次元の高次元ベクトル化 ■ 文章を適切な長さ(チャンクサイズ)に分割してベクトル化する ○ RAG(検索拡張生成)の仕組みの中で使われている ■ LLM が持たない外部知識を追加情報として渡す際に、外部知識をベクトルス トアから検索して取り出す 42

43.
[beta]
ベクトル検索の使い道の例 [3]
● Cohere embed-multilingual-v3.0 ベクトル出力例
$ curl --location --request POST 'https://api.cohere.com/v1/embed' \
>
--header 'Authorization: BEARER XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' \
>
--header 'Content-Type: application/json' \
>
--data-raw '{
>
"model": "embed-multilingual-v3.0",
>
"texts": ["ブリ会議に参加。懇親会でブリしゃぶを食べたい。"],
>
"input_type": "search_document",
>
"truncate": "NONE"
>
}'
{"id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","texts":["ブリ会議に参加。懇親会でブリしゃぶを食べた
い。"],"embeddings":[[-0.0034770966,0.025360107,0.023635864,-0.032226562,-0.002254486,-0.0002734661,-0.01
8218994,-0.0670166,0.0074768066,-0.011772156,0.0061912537,0.04937744,0.00060653687,0.01663208,0.00049591
064,0.026382446,0.026748657,-0.013877869,0.018661499,0.00058841705,-0.0084991455,0.012893677,0.040649414
,-0.057739258,-0.036499023,0.013702393,0.013961792,0.007835388,-0.044769287,-0.037078857,-0.051116943,0.
03189087,-0.018127441,0.012649536,-0.018310547,-0.020614624,0.005836487,-0.042907715,0.00037646294,0.030
349731,0.02104187,0.01335144,-0.027267456,0.027236938,-0.035064697,0.020706177,0.028259277,0.038238525,0
.025512695,0.039093018,0.023162842,-0.050354004,0.016677856,0.023254395,0.033294678,-0.002363205,…
43

44.

【参考】LLM の埋め込みモデルの多くでは ● コサイン類似度を推奨しているが内積で代用可能 ○ OpenAI「Vector embeddings」のページ ■ https://platform.openai.com/docs/guides/embeddings Which distance function should I use? コサイン類似度を推奨 We recommend cosine similarity. The choice of distance function typically doesn't matter much. 長さを1に正規化 OpenAI embeddings are normalized to length 1, which means that: ドット積(内積)の ● Cosine similarity can be computed slightly faster using just a dot product ほうがわずかに速い ● Cosine similarity and Euclidean distance will result in the identical ranking 44

45.

【参考】LLM の埋め込みモデルの多くでは ● コサイン類似度を推奨しているが内積で代用可能 ○ OpenAI「Vector embeddings」のページ ■ https://platform.openai.com/docs/guides/embeddings Which distance function should I use? We recommend cosine similarity. The choice of distance function typically doesn't matter much. OpenAI embeddings are normalized to length 1, which means that: ユークリッド距離でも 同じランキングになる ● Cosine similarity can be computed slightly faster using just a dot product ● Cosine similarity and Euclidean distance will result in the identical ranking 45

46.

【参考】LLM の埋め込みモデルの多くでは ● コサイン類似度を推奨しているが内積で代用可能 → → → B → → ○ 内積:𝒂・𝒃 = |𝒂| |𝒃| cosθ 𝒃 → A θ → 𝒂 と 𝒃 の長さを 1 に正規化すると「cosθ」だけが残る →内積で代用可能 → O 𝒂 46

47.

【参考】LLM の埋め込みモデルの多くでは ● コサイン類似度を推奨しているが内積で代用可能 ○ 同時に、コサイン類似度↑でユークリッド距離↓ B → 𝒃 コサイン類似度が高い(A と B が近い)ほど A θ ユークリッド距離(青色の⇔)は小さくなる → O 𝒂 → LLM の埋め込みモデルではベクトルの長さを 1 に正規化しているか、または 正規化できるケースが多い 47

48.

ここまでのまとめ ● ベクトル検索にはいくつかの使い道がある ○ レコメンドシステム、キーワード/セマンティック検索など ■ (例示したもの以外にも異常検出や感情分析などがあるがここでは省略) ● 使い道によってベクトルの扱い方・生成方法が異なる ○ キーワード検索では文章を単語に分解して疎ベクトル化する ○ セマンティック検索では主に LLM の埋め込みモデルを使ってベ クトル化する 48

49.

ベクトルストアの機能 49

50.

ベクトルストアの機能 [1] ● ベクトルを含むデータ(行・レコード)の保管・更新 ○ PostgreSQL+pgvector(RDB のベクトルストア)ではテーブル内の データとして保管(ベクトルはベクトル型カラムへ) ■ Pinecone のような非 RDB のベクトルストアではベクトルデータをインデッ クスとして保管し、ベクトル以外の属性をメタデータとして保管(ベクトル のフィルタリング・絞り込みに使う) 50

51.

ベクトルストアの機能 [1] ● PostgreSQL+pgvector の例(以降同じ) ○ 先の A さん〜 D さんのデータを登録・保管 // pgvector有効化 postgres=# CREATE EXTENSION vector; CREATE EXTENSION // テーブル作成 postgres=# CREATE TABLE persons (id bigserial PRIMARY KEY, name varchar(50) NOT NULL, physique vector(3)); CREATE TABLE vector 32ビット精度・2000次元まで // データ登録 halfvec 16ビット精度・4000次元まで postgres=# INSERT INTO persons (name, physique) VALUES ('Aさん', '[170.0,64.0,77.0]') ,('Bさ bit 1ビット(バイナリ)64000次元まで(後述) ん', '[174.5,82.7,86.6]'), ('Cさん', ('Dさん', '[186.7,76.2,67.1]'); sparsevec '[167.2,46.8,71.8]'), 疎ベクトル(0以外の値を持つ次元1000まで) INSERT 0 4 51

52.

ベクトルストアの機能 [1] ● PostgreSQL+pgvector の例(以降同じ) ○ 先の A さん〜 D さんのデータを登録・保管 // pgvector有効化 postgres=# CREATE EXTENSION vector; CREATE EXTENSION // テーブル作成 postgres=# CREATE TABLE persons (id bigserial PRIMARY KEY, name varchar(50) NOT NULL, physique vector(3)); CREATE TABLE // データ登録 postgres=# INSERT INTO persons (name, physique) VALUES ('Aさん', '[170.0,64.0,77.0]') ,('Bさ ん', '[174.5,82.7,86.6]'), ('Cさん', '[167.2,46.8,71.8]'), ('Dさん', '[186.7,76.2,67.1]'); INSERT 0 4 52

53.

ベクトルストアの機能 [1] ● PostgreSQL+pgvector の例 ○ 登録データを確認 // 登録データ確認 postgres=# SELECT * FROM persons; id | name | physique ----+-------+------------------1 | Aさん | [170,64,77] 2 | Bさん | [174.5,82.7,86.6] 3 | Cさん | [167.2,46.8,71.8] 4 | Dさん | [186.7,76.2,67.1] (4 rows) 53

54.

ベクトルストアの機能 [2] ● ベクトルを含むデータ(行・レコード)の検索 ○ 例:A さんとユークリッド距離が近い(小さい)順に表示 // ユークリッド距離が近い順に表示 postgres=# SELECT name FROM persons WHERE id != 1 ORDER BY physique <-> (SELECT physique FROM persons WHERE id = 1); name idでフィルタ ------<+> マンハッタン距離 Cさん <-> ユークリッド距離 Bさん <=> コサイン距離 Dさん (1-コサイン類似度) (3 rows) <#> 負の内積(-1✖内積) 54

55.

ベクトルストアの機能 [3] ● ベクトル間の距離・類似度の計算 ○ 例:A さんとのコサイン距離(1-コサイン類似度)を表示 // コサイン距離を表示(コサイン距離の昇順) コサイン類似度とは大小が逆になる(値の範囲:0〜2) postgres=# SELECT name, cosine_distance((SELECT physique FROM persons WHERE id = 1), physique) AS dist FROM persons WHERE id != 1 ORDER BY dist; name | dist -------+----------------------唐突に出てきた「コサイン距離」について Bさん | 0.0030710384673471314 「小さいほうが近い」を表すために、ベクトル検索ではコサイン類似度 Cさん | 0.0032670664285965323 Dさん | 0.0035040553323729684 よりもコサイン距離が使われるケースが多い (3 rows) (数学的な距離の公理を満たしていない→擬距離) 55

56.

ベクトルストアの機能 [3] ● ベクトル間の距離・類似度の計算 ○ 例:A さんとのコサイン距離(1-コサイン類似度)を表示 // コサイン距離を表示(コサイン距離の昇順) postgres=# SELECT name, cosine_distance((SELECT physique FROM persons WHERE id = 1), physique) AS dist FROM persons WHERE id != 1 ORDER BY dist; name | dist -------+----------------------l1_distance(vector, vector) マンハッタン距離 Bさん | 0.0030710384673471314 l2_distance(vector, vector) ユークリッド距離 Cさん | 0.0032670664285965323 cosine_distance(vector, vector) コサイン距離 Dさん | 0.0035040553323729684 (1-コサイン類似度) (3 rows) inner_product(vector, vector) 内積 56

57.

ベクトルストアの機能 [4] ● 近似最近傍探索(ANN)用インデックス ○ ベクトル検索では、検索対象となるデータ全てのベクトルとの間 で距離や類似度の計算が必要になる ○ 「近いベクトル」を効率的に探すためのインデックスを作成して 計算量とデータスキャン量を減らすことができる ■ ただし「近似」であり完全に正確な結果を返せない可能性もある 57

58.

ベクトルストアの機能 [4] ● 例:HNSW(Hierarchical Navigable Small World)Index ○ 階層的なグラフ構造を持つインデックス ○ 多くのベクトルストアでサポートされている ○ 近さをはかるのに使う「距離」の種類を指定して作成する ■ 近いもの同士をグラフで繋げる→距離のはかり方が違えばグラフの構造も変 わる可能性がある 58

59.

ベクトルストアの機能 [4] ● HNSW Index での検索例(注:イメージです) ID x y A 18 15 B 4 14 C 8 17 D 5 5 E 9 11 F 14 8 G 19 4 H 13 13 この2次元ベクトルの 中から (8, 8) に最も近いものを検索 するときの流れ (3層のグラフ構造を持つ HNSW Indexを検索) 59

60.

ベクトルストアの機能 [4] ● HNSW Index での検索例 ID x y A 18 15 B 4 14 C 8 17 D 5 5 E 9 11 F 14 8 G 19 4 H 13 13 第3層のグラフの始点A から探索開始 (8, 8) に近いのは? →B 60

61.

ベクトルストアの機能 [4] ● HNSW Index での検索例 ID x y A 18 15 B 4 14 C 8 17 D 5 5 E 9 11 F 14 8 G 19 4 H 13 13 第2層のグラフはBを 始点に探索開始 B→H→Fと進む DはFより遠い →Fが最も近い 61

62.

ベクトルストアの機能 [4] ● HNSW Index での検索例 ID x y A 18 15 B 4 14 C 8 17 D 5 5 E 9 11 F 14 8 G 19 4 H 13 13 第1層のグラフはFを 始点に探索開始 F→Eと進む グラフで繋がる別の点 はEより遠い →Eが最も近い 62

63.

ベクトルストアの機能 [4] ● PostgreSQL+pgvector で HNSW Index 作成 ○ 例:ユークリッド距離用の HNSW Index を作成 // ユークリッド距離用の HNSW INDEXを作成 postgres=# CREATE INDEX ON persons USING hnsw (physique vector_l2_ops); CREATE INDEX vector_l1_ops マンハッタン距離用 vector_l2_ops ユークリッド距離用 vector_cosine_ops コサイン距離用 vector_ip_ops 内積用 63

64.

ベクトルストアの機能 [5] ● ベクトルの圧縮・量子化 ○ 一般的に、ベクトル 1 次元は 32 ビット(浮動小数点数) ■ 次元数 × データ数が多いと容量が膨大に ○ メモリ容量を超えるベクトルデータを検索すると遅くなる ■ HNSW Index は構造的にランダムアクセスが多くなるため、メモリ容量を超 えるサイズになると検索も作成も極端に遅くなる 64

65.

ベクトルストアの機能 [5] ● ベクトルの圧縮・量子化 ○ 大量のベクトルデータは圧縮・量子化して容量を削減すると良い ■ 例:32 ビットを 1 ビットに→バイナリ量子化 ○ PostgreSQL+pgvector ではベクトルデータを量子化せずに ANN インデックスだけ量子化する方法もある 65

66.

ベクトルストアの機能 [5] ● PostgreSQL+pgvector でバイナリインデックス ○ 例:LLM の埋め込みモデルを使用して Re-rank 検索 ■ https://zenn.dev/hmatsu47/articles/pgvector070-binaryvector (一部改変) ■ バイナリインデックスではハミング距離(「0」「1」が異なる次元の数)を 使って「近さ」をはかる ■ 埋め込みモデルとして Amazon の Titan Text Embeddings V2を使用 (1024 次元・正規化有効) 66

67.

ベクトルストアの機能 [5] ● PostgreSQL+pgvector でバイナリインデックス ○ テーブル・インデックス作成 // テーブル作成( 1024次元のTitan Text Embeddings V2埋め込み用) CREATE TABLE rerank_test (id INTEGER PRIMARY KEY, data TEXT, embedding vector(1024)); // バイナリインデックス作成( HNSW・ハミング距離用・ 1次元を1ビットに) CREATE INDEX ON rerank_test USING hnsw ((binary_quantize(embedding)::bit(1024)) bit_hamming_ops); バイナリ量子化を指定 バイナリ量子化 bit バイナリ精度 67

68.

ベクトルストアの機能 [5] ● PostgreSQL+pgvector でバイナリインデックス ○ テーブル・インデックス作成 // テーブル作成( 1024次元のTitan Text Embeddings V2埋め込み用) CREATE TABLE rerank_test (id INTEGER PRIMARY KEY, data TEXT, embedding vector(1024)); // バイナリインデックス作成( HNSW・ハミング距離用・ 1次元を1ビットに) CREATE INDEX ON rerank_test USING hnsw ((binary_quantize(embedding)::bit(1024)) bit_hamming_ops); bit_hamming_ops ハミング距離用 bit_jaccard_ops ジャッカード距離用 (いずれもバイナリ量子化ベクトル用の距離) 68

69.

ベクトルストアの機能 [5] ● PostgreSQL+pgvector でバイナリインデックス ○ Re-rank 検索(低精度のインデックスで抽出したものを元の精度でソート) // バイナリインデックスを使用して Re-rank検索 // (バイナリインデックスで上位 20件抽出→32ビット精度でコサイン距離を比較して上位 5件抽出) SELECT id, (embedding <=> (SELECT embedding FROM rerank_test WHERE id = 100000)) AS dist, data FROM <~> ハミング距離 (SELECT * FROM rerank_test WHERE id < 100000 <%> ジャッカード距離 ORDER BY binary_quantize(embedding)::bit(1024) <~> (SELECT binary_quantize(embedding)::bit(1024) FROM rerank_test WHERE id = 100000) LIMIT 20) ORDER BY dist LIMIT 5; // 結果表示は省略 69

70.

ベクトルストアの機能 [6] その他 ● 近似最近傍探索(ANN)用インデックスの進化系として ○ メモリ容量を超えても実用になる DiskANN Index ■ マイクロソフトが開発 ■ PostgreSQL+pgvector では対応していないが pgvectorscale で同系統の StreamingDiskANN Index に対応 ■ Azure Database for PostgreSQL の pg_dikann で DiskANN Index にプレビュー対応 ■ 参考:https://engineers.ntt.com/entry/202412-diskann/entry 70

71.

ベクトルストアの機能 [6] その他 ● バイナリ量子化の改良版として ○ 値の範囲を意識して「0」「1」に分割→統計的バイナリ量子化 ■ 通常のバイナリ量子化では「0 または負の数」「正の数」でざっくり分割し て「0」「1」にしてしまうため、(-1 ~ 1 への)正規化や標準化をしてい ないベクトルには向かない(この資料の例の大半がそう) ■ PostgreSQL+pgvector では対応していないが pgvectorscale で対応 71

72.

ベクトルストアの機能 [6] その他 ● 他にも ○ ベクトル検索+全文検索のハイブリッド検索など 72

73.

ここまでのまとめ ● ベクトルストアにはベクトル(と関連データ)を管理し検索 するための機能が実装されている ○ 関連データ(メタデータ)によるフィルタ ○ 距離比較のための関数・演算子 ○ 近似最近傍探索用インデックス ○ 圧縮・量子化 など ● ベクトル数・容量などに応じて適切に機能を使うと良い 73

74.

全体のまとめ ● 近さや類似度をはかるのに便利なのがベクトル ● ベクトルが近い・似ているものを探すのがベクトル検索 ○ 検索の使い道によってベクトルの扱い方・生成方法が異なる ● ベクトルストアにはベクトル(と関連データ)を管理し検索 するための機能が実装されている ○ ベクトル数・容量などに応じて適切に機能を使うと良い 74

75.

参考資料 ● 九州大学 数理・データサイエンス教育研究センター 講義資料 ○ https://mdsc.kyushu-u.ac.jp/wp/wp-content/uploads/2023/07/a85dfe612a31b1a1e0a4b399a9b 073bf.pdf ○ https://mdsc.kyushu-u.ac.jp/wp/wp-content/uploads/2023/07/458290da747eff72c614ee500e1b aa27.pdf ● Pinecone 社の Hierarchical Navigable Small Worlds (HNSW) 説明ページ ○ ● https://www.pinecone.io/learn/series/faiss/hnsw/ Timescale 社のブログ記事 ○ https://www.timescale.com/blog/how-we-made-postgresql-as-fast-as-pinecone-for-vector-data 75