© 2024 NTT DATA Group Corporation
© 2024 NTT DATA Group Corporation
生成AI時代のPostgreSQLハイブリッド検索
第50回PostgreSQLアンカンファレンス@オンライン
2024/12/20
NTTデータグループ 技術革新統括本部 イノベーション技術部 石井愛弓
© 2024 NTT DATA Group Corporation 2
はじめに
生成AIとPostgreSQLを連携することで、生成AIは、データベースに保存したデータに基づいた回答を行えるようになります。
例えば、社内のクローズドな情報を連携させれば、生成AIが社内情報を駆使した回答を出力することができます。
この技術は、Retrieval-Augmented Generation (RAG) と呼ばれます。
PostgreSQLを使ったRAGについては、別資料(*)で詳しく解説しています。
基本から知りたい場合は、こちらをご覧ください。
本資料では、応用として、RAGにおいて必須となるベクトル検索に加えて、別の検索方法を組み合わせたハイブリッド検索について
解説します。
• ハイブリッド検索とは何か
• ハイブリッド検索のパターン
• 各パターンでハイブリッド検索を行うために必要な前提知識とサンプル
*https://www.slideshare.net/slideshow/postgresql-pgvector-chatgpt-pgcon23j-nttdata/263745966
© 2024 NTT DATA Group Corporation 3
ベクトル検索とは?
生成AIのAPIを使うと、自然言語をベクトル化できる。
ベクトルは、自然言語の意味を捉えることができるので、意味が近い言葉は、近いベクトルになる。
お菓子
チョコ
PostgreSQL
MySQL
データベース
デザート
ベクトル間の距離を計算することで、
単語の類似度を計算できるようになる。
※実際は1536次元だが、2次元でイメージ
ベクトル検索が有用なのはRAGだけでなく、
意味検索ができるところ!
© 2024 NTT DATA Group Corporation 4
pgvector
• PostgreSQLでベクトル類似性検索ができるようになる拡張機能
• 現在の最新バージョンはv0.8.0(2024年12月現在)
• 頻繁に機能追加&リリースされている
• sparsevec(0.7.0~)
• halfvec (0.7.0~)
• ビットベクトル(0.7.0~)
• Iterative Index Scans(0.8.0~)
• サブベクトル(0.7.0~)
• …etc
• 本資料では新しい機能を駆使しながらハイブリッド検索について紹介
© 2024 NTT DATA Group Corporation 5
ハイブリッド検索とは
画像の類似検索
(ベクトル検索)
属性値検索
キーワード検索
ハイブリッド検索とは、複数の検索を組み合わせること。
単一の検索方法では、よい結果を得ようとすると、インデックスサイズやクエリのレイテンシが犠牲になりやすい。
ハイブリッド検索は、サイズやレイテンシを抑えながらよい結果を得るための解決策の1つ。
複雑な問いあわせにおいては、ベクトル検索以外の検索も組み合わせるとよいケースもある。
例)
「画像と同じデザインの〇〇ブランドのワンピースのMサイズの在庫はありますか?」
© 2024 NTT DATA Group Corporation 6
ハイブリッド検索のパターン
ハイブリッド検索のパターン
1. ベクトル検索+スカラー属性フィルタリング
例)商品名:意味的に似ている(ベクトル検索) & 値段:〇〇円以下(スカラーフィルタリング)
2. ベクトル検索+全文検索
例)商品の説明:意味的に似ている(ベクトル検索)& 商品の説明:キーワードが含まれる(全文検索)
3. ベクトル検索+疎ベクトル検索
例)商品の説明:意味的に似ている(ベクトル検索)& 商品の説明:キーワードが含まれる(疎ベクトル検索)
※ベクトル検索=密ベクトル検索とする。
© 2024 NTT DATA Group Corporation 7
パターン1:
ベクトル検索+スカラー属性フィルタリング
© 2024 NTT DATA Group Corporation 8
1.ベクトル検索+スカラー属性フィルタリング
例)商品名:意味的に似ている(ベクトル検索) & カテゴリ:5(スカラーフィルタリング)
SELECT * FROM items WHERE category_id = 5 ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
☆高速に検索するためには?
• 一致する行の割合が小さいとき…
• フィルタ列に対するインデックスを作成する
• CREATE INDEX ON items (category_id);
• 近似インデックスは使わないので、抜け漏れが発生しない
• 一致する行の割合が大きいとき…
• ベクトル列に対する近似インデックスを作成する
• CREATE INDEX ON items USING hnsw (embedding vector_l2_ops);
• 近似インデックスなので、完全に正確ではない
• 取得される結果が少なくなる可能性あり →後述
© 2024 NTT DATA Group Corporation 9
近似インデックス+フィルタリングの課題
• HNSWなどの近似インデックスでは、インデックスがスキャンされた後にフィルタリングされる
• フィルタリング条件によっては、返される結果が少なくなる可能性がある
• 例えばフィルタ条件が行の 10% に一致する場合、デフォルトhnsw.ef_searchの 40 では、4 件のみ取得
• フィルタ条件に指定した集団がターゲットベクトルの近くにない場合、結果が0件になる可能性も
• 十分検索結果を得るには、 取得数(hnsw.ef_search)を増やして検索範囲を広げるしかなかった。
対策
1. 部分インデックス
2. パーティション分割
3. Iterative Index Scans (反復インデックススキャン)
© 2024 NTT DATA Group Corporation 10
部分インデックス/パーティション
• フィルタリングの値が絞られているときは、部分インデックスが効果的。
• CREATE INDEX ON items USING hnsw (embedding vector_l2_ops) WHERE (category_id = 5);
• インデックス検索を行うことで、フィルタリングも兼ねているので、高速
• 色々な値でフィルタリングする場合は、パーティションを使う方法がある。
• CREATE TABLE items (embedding vector(3), category_id int) PARTITION BY LIST(category_id);
• 個々のパーティションにインデックスを作成
© 2024 NTT DATA Group Corporation 11
Iterative Index Scans (反復インデックススキャン)
• 0.8.0から実装された機能
• デフォルトはOFF
• 十分な結果が見つかるまで自動的にインデックスをさらにスキャンする
IVFFlatの場合、次に近い集団をスキャン
1
2
3
引用元:https://www.pinecone.io/learn/series/faiss/hnsw/
HNSWの場合、一番下の層で捨てた候補を拾う
さらに必要な場合は、エントリポイントを次に近い候補にして探索
© 2024 NTT DATA Group Corporation 12
Iterative Index Scansの結果順序のオプション
iterative_scanオプション
• off: 反復インデックススキャンを利用しない。デフォルト。
• strict_order:取得結果が厳密に距離順になる。HNSWのみ。 IVFFlatは選択できない。
• relaxed_order:取得結果が厳密に距離順でない。ただし、取りこぼしがない。IVFFlatはこっちだけ。
⇒近い集団からまずスキャンするので、基本的に見つかるベクトルとの距離は徐々に遠くなっていく
が、前のスキャンよりも短い距離のベクトルが見つかることもある。
relaxed_orderは、これをそのまま出力するので、距離順が一部入れ替わっている箇所が発生しうる
strict_orderは、短い距離のベクトルが見つかったら、結果を破棄するので、必ず昇順になるが、結果が減る
結果を失わず、順序を厳密にしたいときは?
• relaxed_orderで取得した結果を、マテリアライズドCTEとして、最後に並び替える
例)
WITH nearest_results AS MATERIALIZED (
SELECT id, embedding <-> '[1,2,3]' AS distance FROM items ORDER BY distance LIMIT 5
) SELECT * FROM nearest_results WHERE distance < 5 ORDER BY distance;
© 2024 NTT DATA Group Corporation 13
Iterative Index Scansを終了するタイミングを制御するオプション
十分な結果がなかなか得られない場合、どんどん探索範囲が広がっていく
大部分をスキャンするのはコストがかかるので、十分な結果が得られない場合も上限値に達したら終了する
HNSW
• 探索するタプルの最大数
• hnsw.max_scan_tuples = 20000;
• 使用するメモリの最大量(work_memの倍数を指定する)
• hnsw.scan_mem_multiplier = 2;
IVFFlat
• 何個のクラスタを探索するか(プローブ)の最大数
• ivfflat.max_probes = 100;
© 2024 NTT DATA Group Corporation 14
パターン2:
ベクトル検索+全文検索
© 2024 NTT DATA Group Corporation 15
2.全文検索とベクトル検索
例)商品の説明:意味的に似ている(ベクトル検索)& 商品の説明:キーワードが含まれる(全文検索)
商品の説明(vector型)
embedding
商品の説明(text型)
[0.00058671045, -
0.004581401, .......]
世界的デザイナーAyumi Ishiiが
デザインした爽やかなグリーンの
レースをあしらったスカートです。
検索:「Ayumi Ishii 緑 スカート」
意味的な検索
⇒ 文脈や、緑=グリーンなどを捉えられる。
キーワード検索
⇒(Ayumi Ishiiなど必須なキーワードを捉えられる)
ベクトル化
© 2024 NTT DATA Group Corporation 16
2.全文検索とベクトル検索
SELECT
searches.id, searches.description, sum(rrf_score(searches.rank)) AS score
FROM ((
SELECT
id, description, rank() OVER (ORDER BY $1 <=> embedding) AS rank
FROM products
ORDER BY $1 <=> embedding
LIMIT 40
)UNION ALL(
SELECT
id, description, rank() OVER (ORDER BY
ts_rank_cd(to_tsvector(description), plainto_tsquery('travel computer')) DESC) AS rank
FROM products
WHERE
plainto_tsquery('english', 'travel computer') @@ to_tsvector('english', description)
ORDER BY rank
LIMIT 40
)) searches
GROUP BY searches.id, searches.description
ORDER BY score DESC
LIMIT 10;
ベクトル検索で40件ピックアップ
全文検索で40件ピックアップ
両方の検索結果をあわせて、全体の順位付けをする
全体の上位10件ピックアップ
© 2024 NTT DATA Group Corporation 17
ハイブリッド検索のスコアリング (RRF)
• Reciprocal Rank Fusion (RRF)
• 複数の検索で取得した結果をあわせて、類似度の高い順に並べ替えるためのアルゴリズム
• 検索方法が違うと類似度を単純に比較できないので、それぞれの順位をスコアに利用する
• 各検索方法のスコア = 1/(順位+k) を足し合わせる
例)k=60のとき
結果 順位 スコア
りんご 1 1/61
みかん 2 1/62
いちご 3 1/63
結果 順位 スコア
れもん 1 1/61
みかん 2 1/62
りんご 3 1/63
最終順位 結果 スコア
1 りんご 1/61 + 1/63 = 0.03226
2 みかん 1/62 + 1/62 = 0.03225
3 れもん 0 + 1/61 = 0.01639
4 いちご 1/63 + 0 = 0.01587
全文検索結果 ベクトル検索結果
順位が高いほど、
スコアも高くなる
1位:1 点
2位:1/2 点
3位:1/3 点
※K=0
© 2024 NTT DATA Group Corporation 20
もう1つの再ランク付け方法:cross encoder
引用:https://www.sbert.net/examples/applications/cross-encoder/README.html
質問文と文書をそれぞれベクトル化し、
2つのベクトルの類似度を計算する
(RAGで通常使われる方法)
質問文と文書をペアにして類似度を計算する
2つの文章の関連を評価するので、Bi-Encoderより
細部の関連性を拾うことができ、精度が高い。
必ずペアの入力が必要なので、計算量が多い。
Bi-Encoderで類似度の高いも
のをある程度絞り込み、
Cross-Encoderで再ランク付け
して精度を上げれば
効率がよい!
←使い方は以下参照
https://github.com/pgvector/pgvector-
python/blob/master/examples/hybrid_search/cross_encoder.
py
© 2024 NTT DATA Group Corporation 21
パターン3:
ベクトル検索+疎ベクトル検索
© 2024 NTT DATA Group Corporation 22
3.ベクトル検索+疎ベクトル検索
疎ベクトルとは(対義語:密ベクトル)
• ほとんどの要素が0のベクトル [0, 0, 1, 0, 0 …]など。
• 圧縮して保存できるので、精度を落とさずサイズを小さくできる
• pgvectorでは0.7.0からsparsevec型が追加された。
CREATE TABLE items (id bigserial PRIMARY KEY, embedding sparsevec(5));
INSERT INTO items (embedding) VALUES ('{1:1,3:2,5:3}/5'), ('{1:4,3:5,5:6}/5’);
表記方法
• {インデックス:値, インデックス:値,…}/次元数
• 値が0以外のところだけ書く。あとは0。
• インデックスは1から始まる(0ではないので注意)
{1:1,3:2,5:3}/5 は、[1, 0, 2, 0, 3]
© 2024 NTT DATA Group Corporation 23
疎ベクトルの使いどころ
OpenAIのembeddingモデルなどの出力結果は、密ベクトル。
文脈を理解するときに使うのは密ベクトル。
→疎ベクトルはどんなときに使う?
• ある文章に対し、事前に用意された単語集をもとに、各単語の出現回数をカウントし、ベクトルとする
• このとき、ほとんどの単語は含まれないので、作成したベクトルは疎ベクトルになる
• 単語集に含まれる特定のキーワードを検索したいとき、この疎ベクトルを参照すれば、単語の出現頻度がすぐにわかる
• キーワード検索に使える
密ベクトル
文章の意味をとらえて数値にしたとき
使いどころ例)
靴/スニーカー⇒「くつ」と検索したとき、文字は違う
が意味が似ているので検索結果に出る
疎ベクトル
文章の文字情報を整理したとき
使いどころ例)
23cm/24cm⇒「23cm」と検索すれば、23cmと一致
するものだけ出る
© 2024 NTT DATA Group Corporation 24
ベクトル検索+疎ベクトル検索
• 疎ベクトルは、キーワード検索の代わりになる
• やりたいことは、全文検索+密ベクトルと同じだが、ベクトル検索だけで、意味ベース&キーワードベースの両方の検索を実現で
きるのがメリット
• BGE-M3など密ベクトルと疎ベクトルを両方取得できるモデルも存在する。
• 2つの検索結果を合わせて、ランク付けして上位を取り出す
• BGE-M3の場合はRerankerモデル(再ランク付け)が用意されている
• このRerankerは、前述のcross encoderアプローチ(計算コストは高いが精度も高い)
使い方の例)
• テーブルに密ベクトルの列(vector)、疎ベクトルの列(svector)を作成する。
• 密ベクトルと疎ベクトルで、それぞれ上位50件取得
• Rerankerモデルで100件を並び替える
© 2024 NTT DATA Group Corporation 25
ハイブリッド検索の価値は? BGE-M3で動かしてみる。
from FlagEmbedding import BGEM3FlagModel
model = BGEM3FlagModel('BAAI/bge-m3', use_fp16=True)
sentences_1 = ["デリシャスパーティプリキュアの主人公は誰ですか。"]
sentences_2 = ["ひろがるスカイ!プリキュアの主人公ソラ・ハレワタールはスカイランドという異世界から来た人です。",
"デリシャスパーティプリキュアの和実ゆいは、すぐにお腹が減ります。コメコメに力をわけてもらい、キュアプ
レシャスに変身します。" ]
sentence_pairs = [[i,j] for i in sentences_1 for j in sentences_2]
print(model.compute_score(
sentence_pairs,
max_passage_length=128,
weights_for_different_modes=[0.4, 0.4, 0.2]))
密ベクトル、疎ベクトルそれぞれのスコアを計算する
↑密:疎=1:1の重みでスコアを計算
質問①
答え①
答え②
[質問①ー答え①]のペアと、[質問①ー答え②]のペア
© 2024 NTT DATA Group Corporation 26
この場合の結果
"dense": [
0.47555941343307495,
0.4559279978275299
],
"sparse": [
0.10498249530792236,
0.13451407849788666
],
"sparse+dense": [
0.29027095437049866,
0.2952210307121277
],
デリシャスパーティプリキュアの主人公は誰ですか。
1. ひろがるスカイ!プリキュアの主人公ソラ・ハレワタールはスカイランドという異世界から来た人です。
2. デリシャスパーティプリキュアの和実ゆいは、すぐにお腹が減ります。コメコメに力をわけてもらい、キュアプレシャスに変身します。
疎ベクトル(キーワードベース)では2が上。
密ベクトル(意味ベース)では1が上。
疎:密=1:1で結果を合わせると、2が上。
より正解に近いほうが
上位に来た
© 2024 NTT DATA Group Corporation 27
結果について
• このケースでは、密ベクトルだけでなく、疎ベクトルを考慮することで、順位が入れ替わった。
• より正解に近い答えを持つ文章の類似度が上がった。
• キーワードが重要な場合、疎ベクトルとのハイブリッド検索は有用である可能性あり
• しかし…色々な文章で試したところ、疎ベクトルと密ベクトルの順位が逆転しないケースも多かった
• ケースによっては、密ベクトルだけで十分というケースもある
© 2024 NTT DATA Group Corporation 28
まとめ
• フィルタリングを行う場合は、部分インデックス、パーティション、反復インデックススキャンを検討する
• 意味ベース&キーワードベースの組み合わせで、よりよい結果が得られるかも
• ベクトル検索(意味ベース)だけでも優秀だが、固有名詞、略語、記号、専門用語などが含まれる場合、キーワード検索
も組み合わせると精度があがる
• キーワードベースは全文検索で可能だが、疎ベクトルを使う方法もある
• 2つの検索結果をどう再ランク付けするかも奥が深い(RRF, cross encoder)
記載されている会社名、商品名、又はサービス名は、
各社の登録商標又は商標です。

生成AI時代のPostgreSQLハイブリッド検索 (第50回PostgreSQLアンカンファレンス@オンライン 発表資料)

  • 1.
    © 2024 NTTDATA Group Corporation © 2024 NTT DATA Group Corporation 生成AI時代のPostgreSQLハイブリッド検索 第50回PostgreSQLアンカンファレンス@オンライン 2024/12/20 NTTデータグループ 技術革新統括本部 イノベーション技術部 石井愛弓
  • 2.
    © 2024 NTTDATA Group Corporation 2 はじめに 生成AIとPostgreSQLを連携することで、生成AIは、データベースに保存したデータに基づいた回答を行えるようになります。 例えば、社内のクローズドな情報を連携させれば、生成AIが社内情報を駆使した回答を出力することができます。 この技術は、Retrieval-Augmented Generation (RAG) と呼ばれます。 PostgreSQLを使ったRAGについては、別資料(*)で詳しく解説しています。 基本から知りたい場合は、こちらをご覧ください。 本資料では、応用として、RAGにおいて必須となるベクトル検索に加えて、別の検索方法を組み合わせたハイブリッド検索について 解説します。 • ハイブリッド検索とは何か • ハイブリッド検索のパターン • 各パターンでハイブリッド検索を行うために必要な前提知識とサンプル *https://www.slideshare.net/slideshow/postgresql-pgvector-chatgpt-pgcon23j-nttdata/263745966
  • 3.
    © 2024 NTTDATA Group Corporation 3 ベクトル検索とは? 生成AIのAPIを使うと、自然言語をベクトル化できる。 ベクトルは、自然言語の意味を捉えることができるので、意味が近い言葉は、近いベクトルになる。 お菓子 チョコ PostgreSQL MySQL データベース デザート ベクトル間の距離を計算することで、 単語の類似度を計算できるようになる。 ※実際は1536次元だが、2次元でイメージ ベクトル検索が有用なのはRAGだけでなく、 意味検索ができるところ!
  • 4.
    © 2024 NTTDATA Group Corporation 4 pgvector • PostgreSQLでベクトル類似性検索ができるようになる拡張機能 • 現在の最新バージョンはv0.8.0(2024年12月現在) • 頻繁に機能追加&リリースされている • sparsevec(0.7.0~) • halfvec (0.7.0~) • ビットベクトル(0.7.0~) • Iterative Index Scans(0.8.0~) • サブベクトル(0.7.0~) • …etc • 本資料では新しい機能を駆使しながらハイブリッド検索について紹介
  • 5.
    © 2024 NTTDATA Group Corporation 5 ハイブリッド検索とは 画像の類似検索 (ベクトル検索) 属性値検索 キーワード検索 ハイブリッド検索とは、複数の検索を組み合わせること。 単一の検索方法では、よい結果を得ようとすると、インデックスサイズやクエリのレイテンシが犠牲になりやすい。 ハイブリッド検索は、サイズやレイテンシを抑えながらよい結果を得るための解決策の1つ。 複雑な問いあわせにおいては、ベクトル検索以外の検索も組み合わせるとよいケースもある。 例) 「画像と同じデザインの〇〇ブランドのワンピースのMサイズの在庫はありますか?」
  • 6.
    © 2024 NTTDATA Group Corporation 6 ハイブリッド検索のパターン ハイブリッド検索のパターン 1. ベクトル検索+スカラー属性フィルタリング 例)商品名:意味的に似ている(ベクトル検索) & 値段:〇〇円以下(スカラーフィルタリング) 2. ベクトル検索+全文検索 例)商品の説明:意味的に似ている(ベクトル検索)& 商品の説明:キーワードが含まれる(全文検索) 3. ベクトル検索+疎ベクトル検索 例)商品の説明:意味的に似ている(ベクトル検索)& 商品の説明:キーワードが含まれる(疎ベクトル検索) ※ベクトル検索=密ベクトル検索とする。
  • 7.
    © 2024 NTTDATA Group Corporation 7 パターン1: ベクトル検索+スカラー属性フィルタリング
  • 8.
    © 2024 NTTDATA Group Corporation 8 1.ベクトル検索+スカラー属性フィルタリング 例)商品名:意味的に似ている(ベクトル検索) & カテゴリ:5(スカラーフィルタリング) SELECT * FROM items WHERE category_id = 5 ORDER BY embedding <-> '[3,1,2]' LIMIT 5; ☆高速に検索するためには? • 一致する行の割合が小さいとき… • フィルタ列に対するインデックスを作成する • CREATE INDEX ON items (category_id); • 近似インデックスは使わないので、抜け漏れが発生しない • 一致する行の割合が大きいとき… • ベクトル列に対する近似インデックスを作成する • CREATE INDEX ON items USING hnsw (embedding vector_l2_ops); • 近似インデックスなので、完全に正確ではない • 取得される結果が少なくなる可能性あり →後述
  • 9.
    © 2024 NTTDATA Group Corporation 9 近似インデックス+フィルタリングの課題 • HNSWなどの近似インデックスでは、インデックスがスキャンされた後にフィルタリングされる • フィルタリング条件によっては、返される結果が少なくなる可能性がある • 例えばフィルタ条件が行の 10% に一致する場合、デフォルトhnsw.ef_searchの 40 では、4 件のみ取得 • フィルタ条件に指定した集団がターゲットベクトルの近くにない場合、結果が0件になる可能性も • 十分検索結果を得るには、 取得数(hnsw.ef_search)を増やして検索範囲を広げるしかなかった。 対策 1. 部分インデックス 2. パーティション分割 3. Iterative Index Scans (反復インデックススキャン)
  • 10.
    © 2024 NTTDATA Group Corporation 10 部分インデックス/パーティション • フィルタリングの値が絞られているときは、部分インデックスが効果的。 • CREATE INDEX ON items USING hnsw (embedding vector_l2_ops) WHERE (category_id = 5); • インデックス検索を行うことで、フィルタリングも兼ねているので、高速 • 色々な値でフィルタリングする場合は、パーティションを使う方法がある。 • CREATE TABLE items (embedding vector(3), category_id int) PARTITION BY LIST(category_id); • 個々のパーティションにインデックスを作成
  • 11.
    © 2024 NTTDATA Group Corporation 11 Iterative Index Scans (反復インデックススキャン) • 0.8.0から実装された機能 • デフォルトはOFF • 十分な結果が見つかるまで自動的にインデックスをさらにスキャンする IVFFlatの場合、次に近い集団をスキャン 1 2 3 引用元:https://www.pinecone.io/learn/series/faiss/hnsw/ HNSWの場合、一番下の層で捨てた候補を拾う さらに必要な場合は、エントリポイントを次に近い候補にして探索
  • 12.
    © 2024 NTTDATA Group Corporation 12 Iterative Index Scansの結果順序のオプション iterative_scanオプション • off: 反復インデックススキャンを利用しない。デフォルト。 • strict_order:取得結果が厳密に距離順になる。HNSWのみ。 IVFFlatは選択できない。 • relaxed_order:取得結果が厳密に距離順でない。ただし、取りこぼしがない。IVFFlatはこっちだけ。 ⇒近い集団からまずスキャンするので、基本的に見つかるベクトルとの距離は徐々に遠くなっていく が、前のスキャンよりも短い距離のベクトルが見つかることもある。 relaxed_orderは、これをそのまま出力するので、距離順が一部入れ替わっている箇所が発生しうる strict_orderは、短い距離のベクトルが見つかったら、結果を破棄するので、必ず昇順になるが、結果が減る 結果を失わず、順序を厳密にしたいときは? • relaxed_orderで取得した結果を、マテリアライズドCTEとして、最後に並び替える 例) WITH nearest_results AS MATERIALIZED ( SELECT id, embedding <-> '[1,2,3]' AS distance FROM items ORDER BY distance LIMIT 5 ) SELECT * FROM nearest_results WHERE distance < 5 ORDER BY distance;
  • 13.
    © 2024 NTTDATA Group Corporation 13 Iterative Index Scansを終了するタイミングを制御するオプション 十分な結果がなかなか得られない場合、どんどん探索範囲が広がっていく 大部分をスキャンするのはコストがかかるので、十分な結果が得られない場合も上限値に達したら終了する HNSW • 探索するタプルの最大数 • hnsw.max_scan_tuples = 20000; • 使用するメモリの最大量(work_memの倍数を指定する) • hnsw.scan_mem_multiplier = 2; IVFFlat • 何個のクラスタを探索するか(プローブ)の最大数 • ivfflat.max_probes = 100;
  • 14.
    © 2024 NTTDATA Group Corporation 14 パターン2: ベクトル検索+全文検索
  • 15.
    © 2024 NTTDATA Group Corporation 15 2.全文検索とベクトル検索 例)商品の説明:意味的に似ている(ベクトル検索)& 商品の説明:キーワードが含まれる(全文検索) 商品の説明(vector型) embedding 商品の説明(text型) [0.00058671045, - 0.004581401, .......] 世界的デザイナーAyumi Ishiiが デザインした爽やかなグリーンの レースをあしらったスカートです。 検索:「Ayumi Ishii 緑 スカート」 意味的な検索 ⇒ 文脈や、緑=グリーンなどを捉えられる。 キーワード検索 ⇒(Ayumi Ishiiなど必須なキーワードを捉えられる) ベクトル化
  • 16.
    © 2024 NTTDATA Group Corporation 16 2.全文検索とベクトル検索 SELECT searches.id, searches.description, sum(rrf_score(searches.rank)) AS score FROM (( SELECT id, description, rank() OVER (ORDER BY $1 <=> embedding) AS rank FROM products ORDER BY $1 <=> embedding LIMIT 40 )UNION ALL( SELECT id, description, rank() OVER (ORDER BY ts_rank_cd(to_tsvector(description), plainto_tsquery('travel computer')) DESC) AS rank FROM products WHERE plainto_tsquery('english', 'travel computer') @@ to_tsvector('english', description) ORDER BY rank LIMIT 40 )) searches GROUP BY searches.id, searches.description ORDER BY score DESC LIMIT 10; ベクトル検索で40件ピックアップ 全文検索で40件ピックアップ 両方の検索結果をあわせて、全体の順位付けをする 全体の上位10件ピックアップ
  • 17.
    © 2024 NTTDATA Group Corporation 17 ハイブリッド検索のスコアリング (RRF) • Reciprocal Rank Fusion (RRF) • 複数の検索で取得した結果をあわせて、類似度の高い順に並べ替えるためのアルゴリズム • 検索方法が違うと類似度を単純に比較できないので、それぞれの順位をスコアに利用する • 各検索方法のスコア = 1/(順位+k) を足し合わせる 例)k=60のとき 結果 順位 スコア りんご 1 1/61 みかん 2 1/62 いちご 3 1/63 結果 順位 スコア れもん 1 1/61 みかん 2 1/62 りんご 3 1/63 最終順位 結果 スコア 1 りんご 1/61 + 1/63 = 0.03226 2 みかん 1/62 + 1/62 = 0.03225 3 れもん 0 + 1/61 = 0.01639 4 いちご 1/63 + 0 = 0.01587 全文検索結果 ベクトル検索結果 順位が高いほど、 スコアも高くなる 1位:1 点 2位:1/2 点 3位:1/3 点 ※K=0
  • 18.
    © 2024 NTTDATA Group Corporation 20 もう1つの再ランク付け方法:cross encoder 引用:https://www.sbert.net/examples/applications/cross-encoder/README.html 質問文と文書をそれぞれベクトル化し、 2つのベクトルの類似度を計算する (RAGで通常使われる方法) 質問文と文書をペアにして類似度を計算する 2つの文章の関連を評価するので、Bi-Encoderより 細部の関連性を拾うことができ、精度が高い。 必ずペアの入力が必要なので、計算量が多い。 Bi-Encoderで類似度の高いも のをある程度絞り込み、 Cross-Encoderで再ランク付け して精度を上げれば 効率がよい! ←使い方は以下参照 https://github.com/pgvector/pgvector- python/blob/master/examples/hybrid_search/cross_encoder. py
  • 19.
    © 2024 NTTDATA Group Corporation 21 パターン3: ベクトル検索+疎ベクトル検索
  • 20.
    © 2024 NTTDATA Group Corporation 22 3.ベクトル検索+疎ベクトル検索 疎ベクトルとは(対義語:密ベクトル) • ほとんどの要素が0のベクトル [0, 0, 1, 0, 0 …]など。 • 圧縮して保存できるので、精度を落とさずサイズを小さくできる • pgvectorでは0.7.0からsparsevec型が追加された。 CREATE TABLE items (id bigserial PRIMARY KEY, embedding sparsevec(5)); INSERT INTO items (embedding) VALUES ('{1:1,3:2,5:3}/5'), ('{1:4,3:5,5:6}/5’); 表記方法 • {インデックス:値, インデックス:値,…}/次元数 • 値が0以外のところだけ書く。あとは0。 • インデックスは1から始まる(0ではないので注意) {1:1,3:2,5:3}/5 は、[1, 0, 2, 0, 3]
  • 21.
    © 2024 NTTDATA Group Corporation 23 疎ベクトルの使いどころ OpenAIのembeddingモデルなどの出力結果は、密ベクトル。 文脈を理解するときに使うのは密ベクトル。 →疎ベクトルはどんなときに使う? • ある文章に対し、事前に用意された単語集をもとに、各単語の出現回数をカウントし、ベクトルとする • このとき、ほとんどの単語は含まれないので、作成したベクトルは疎ベクトルになる • 単語集に含まれる特定のキーワードを検索したいとき、この疎ベクトルを参照すれば、単語の出現頻度がすぐにわかる • キーワード検索に使える 密ベクトル 文章の意味をとらえて数値にしたとき 使いどころ例) 靴/スニーカー⇒「くつ」と検索したとき、文字は違う が意味が似ているので検索結果に出る 疎ベクトル 文章の文字情報を整理したとき 使いどころ例) 23cm/24cm⇒「23cm」と検索すれば、23cmと一致 するものだけ出る
  • 22.
    © 2024 NTTDATA Group Corporation 24 ベクトル検索+疎ベクトル検索 • 疎ベクトルは、キーワード検索の代わりになる • やりたいことは、全文検索+密ベクトルと同じだが、ベクトル検索だけで、意味ベース&キーワードベースの両方の検索を実現で きるのがメリット • BGE-M3など密ベクトルと疎ベクトルを両方取得できるモデルも存在する。 • 2つの検索結果を合わせて、ランク付けして上位を取り出す • BGE-M3の場合はRerankerモデル(再ランク付け)が用意されている • このRerankerは、前述のcross encoderアプローチ(計算コストは高いが精度も高い) 使い方の例) • テーブルに密ベクトルの列(vector)、疎ベクトルの列(svector)を作成する。 • 密ベクトルと疎ベクトルで、それぞれ上位50件取得 • Rerankerモデルで100件を並び替える
  • 23.
    © 2024 NTTDATA Group Corporation 25 ハイブリッド検索の価値は? BGE-M3で動かしてみる。 from FlagEmbedding import BGEM3FlagModel model = BGEM3FlagModel('BAAI/bge-m3', use_fp16=True) sentences_1 = ["デリシャスパーティプリキュアの主人公は誰ですか。"] sentences_2 = ["ひろがるスカイ!プリキュアの主人公ソラ・ハレワタールはスカイランドという異世界から来た人です。", "デリシャスパーティプリキュアの和実ゆいは、すぐにお腹が減ります。コメコメに力をわけてもらい、キュアプ レシャスに変身します。" ] sentence_pairs = [[i,j] for i in sentences_1 for j in sentences_2] print(model.compute_score( sentence_pairs, max_passage_length=128, weights_for_different_modes=[0.4, 0.4, 0.2])) 密ベクトル、疎ベクトルそれぞれのスコアを計算する ↑密:疎=1:1の重みでスコアを計算 質問① 答え① 答え② [質問①ー答え①]のペアと、[質問①ー答え②]のペア
  • 24.
    © 2024 NTTDATA Group Corporation 26 この場合の結果 "dense": [ 0.47555941343307495, 0.4559279978275299 ], "sparse": [ 0.10498249530792236, 0.13451407849788666 ], "sparse+dense": [ 0.29027095437049866, 0.2952210307121277 ], デリシャスパーティプリキュアの主人公は誰ですか。 1. ひろがるスカイ!プリキュアの主人公ソラ・ハレワタールはスカイランドという異世界から来た人です。 2. デリシャスパーティプリキュアの和実ゆいは、すぐにお腹が減ります。コメコメに力をわけてもらい、キュアプレシャスに変身します。 疎ベクトル(キーワードベース)では2が上。 密ベクトル(意味ベース)では1が上。 疎:密=1:1で結果を合わせると、2が上。 より正解に近いほうが 上位に来た
  • 25.
    © 2024 NTTDATA Group Corporation 27 結果について • このケースでは、密ベクトルだけでなく、疎ベクトルを考慮することで、順位が入れ替わった。 • より正解に近い答えを持つ文章の類似度が上がった。 • キーワードが重要な場合、疎ベクトルとのハイブリッド検索は有用である可能性あり • しかし…色々な文章で試したところ、疎ベクトルと密ベクトルの順位が逆転しないケースも多かった • ケースによっては、密ベクトルだけで十分というケースもある
  • 26.
    © 2024 NTTDATA Group Corporation 28 まとめ • フィルタリングを行う場合は、部分インデックス、パーティション、反復インデックススキャンを検討する • 意味ベース&キーワードベースの組み合わせで、よりよい結果が得られるかも • ベクトル検索(意味ベース)だけでも優秀だが、固有名詞、略語、記号、専門用語などが含まれる場合、キーワード検索 も組み合わせると精度があがる • キーワードベースは全文検索で可能だが、疎ベクトルを使う方法もある • 2つの検索結果をどう再ランク付けするかも奥が深い(RRF, cross encoder)
  • 27.