すべてのプロダクト
Search
ドキュメントセンター

AnalyticDB:V7.0 におけるベクトル検索と全文検索に基づく双方向検索

最終更新日:Apr 30, 2025

ほとんどの場合、ベクトル検索 メソッドのみで、ベクトル類似性検索の高い再現率を実現できます。ただし、特定のシナリオでは、埋め込みモデルのパフォーマンスが低い場合や、クエリが複雑な場合、生成されたベクトルが取得対象のデータからかけ離れてしまう可能性があります。この場合、ベクトル検索メソッドのみを使用しても、期待される結果は得られません。再現率を高めるには、ベクトル検索と全文検索に基づく双方向検索メソッドを使用できます。

AnalyticDB for PostgreSQL の双方向検索メソッドは、ベクトル検索と全文検索を使用してデータのサブセットを個別に取得し、マージされた検索結果を再ランク付けおよび後処理して、効果を高めます。

  1. ベクトル検索: 密ベクトル表現に基づいて、AnalyticDB for PostgreSQL は、近似最近傍探索 (ANNS) アルゴリズムを使用してセマンティックな関連性を取得し、TopK 類似アイテムを取得します。

  2. 全文検索: AnalyticDB for PostgreSQL は、単語頻度や逆文書頻度などの統計的特徴に基づいて正確なマッチングを実行し、キーワード関連性の高い結果を補完します。AnalyticDB for PostgreSQL V6.0 では、全文検索は GIN インデックスに依存しています。V7.0 では、pgsearch ベースの BM25 インデックスを使用して、検索効率と関連性を向上させています。

  3. 再ランク付けと後処理: AnalyticDB for PostgreSQL は、双方向で取得されたデータをマージし、さらにランキングと処理を実行して、最終結果の関連性と精度を確保します。

このトピックでは、AnalyticDB for PostgreSQL V7.0 でベクトル検索と全文検索に基づく双方向検索を実行する方法について説明します。 AnalyticDB for PostgreSQL V6.0 インスタンスを使用している場合は、「ベクトル検索と全文検索に基づく双方向検索」をご参照ください。

サポートされているバージョン

AnalyticDB for PostgreSQL V7.0 インスタンス V7.2.1.0 以降。

説明

AnalyticDB for PostgreSQL インスタンスのマイナーバージョンの表示方法については、「インスタンスのマイナーバージョンの表示」をご参照ください。インスタンスが上記の要件を満たしていない場合は、インスタンスのマイナーバージョンを更新してください。詳細については、「UpgradeDBVersion」をご参照ください。

前提条件

  • ベクター検索エンジン最適化 機能は、AnalyticDB for PostgreSQL インスタンスで有効になっています。

  • pgsearch 拡張機能がインストールされていること。 pgsearch 拡張機能をインストールしている場合、pgsearch という名前のスキーマがスキーマリストに含まれています。 pgsearch 拡張機能をインストールしていない場合は、チケットを送信する してインストールのサポートを受けてください。 pgsearch 拡張機能をインストールした後、インスタンスを再起動する必要があります。

手順

ステップ 1: サンプルテーブルを作成する

documents という名前のサンプルテーブルを作成し、テーブルに 5 行のデータを挿入します。

-- vector 列はベクトルデータを指定します。
CREATE TABLE IF NOT EXISTS documents(
                id TEXT,
                docname TEXT,
                title TEXT,
                vector real[],
                text TEXT);
-- vector 列のストレージモードを PLAIN に設定します。
ALTER TABLE documents ALTER COLUMN vector SET STORAGE PLAIN;
-- サンプルデータを挿入します。
INSERT INTO documents (id, docname, title, vector, text) VALUES
('1', 'doc_1', 'Exploring the Universe', 
'{0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}', 
'The universe is vast, filled with mysteries and astronomical wonders waiting to be discovered.'),

('2', 'doc_2', 'The Art of Cooking', 
'{0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1}', 
'Cooking combines ingredients artfully, creating flavors that nourish and bring people together.'),

('3', 'doc_3', 'Technology and Society', 
'{0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2}', 
'Technology transforms society, reshaping communication, work, and our daily interactions significantly.'),

('4', 'doc_4', 'Psychology of Happiness', 
'{0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3}', 
'Happiness is complex, influenced by relationships, gratitude, and the pursuit of meaningful experiences.'),

('5', 'doc_5', 'Sustainable Living Practices', 
'{0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4}', 
'Sustainable living involves eco-friendly choices, reducing waste, and promoting environmental awareness.');

ステップ 2: インデックスを作成する

  • vector 列にベクトルインデックスを作成します。

    CREATE INDEX documents_idx ON documents USING ann(vector) WITH (dim = 10, algorithm = hnswflat, distancemeasure = L2, vector_include = 0);
  • text 列に全文インデックスを作成します。

    CALL pgsearch.create_bm25(
        index_name => 'documents_bm25_idx',
        table_name => 'documents',
        text_fields => '{text: {}}'
    );

ステップ 3: 双方向検索を実行する

最初の一時テーブル t1 は 全文検索 を使用して 1 行のデータを取得し、2 番目の 一時テーブル t2 は ベクトル検索 を使用して 5 行のデータを取得します。FULL OUTER JOIN を使用して BM25 とベクトル類似性スコアに基づいて最終スコアを取得し、最終スコアでソートされた結果を返します。

WITH t1 AS (
    SELECT
            id,
            docname,
            title,
            text,
            text @@@ pgsearch.config('text:astronomical') AS score,
            2 AS source
    FROM
        documents
    ORDER BY score
    LIMIT 10
),
t2 AS (
    SELECT
        id,
        docname,
        title,
        text,
        cosine_similarity(vector,ARRAY[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1]::real[]) AS score,
        1 AS source
    FROM
        documents
    ORDER BY vector <-> ARRAY[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1]
    LIMIT 10
)
SELECT t2.*, COALESCE(ABS(t1.score), 0.0) * 0.2 + COALESCE(t2.score, 0.0) * 0.8 AS hybrid_score
-- スコアの重み分布はデモ用です。ビジネス要件に基づいて適切なパラメータと計算方法を選択できます。
FROM t1
FULL OUTER JOIN t2 ON t1.id = t2.id 
ORDER BY  hybrid_score DESC;

逆順位融合 (RRF) を使用して最終スコアを計算することもできます。 RRF は、ベクトル検索と全文検索のランキングに基づいて、検索結果の最終ランキングを決定します。通常、検索結果が両方の検索方法で上位にランクされている場合、最終スコアは高くなります。

RRF 式のパラメータ k は、ランキングが最終スコアに与える影響を滑らかにするために使用されます。 k 値が大きいほど、異なるランキング間のスコア差が小さくなり、より良い平滑化効果が得られます。デフォルトでは、k の値は 60 に設定されています。

RRF の例

WITH bm25 AS (
        SELECT
            id,
            docname,
            title,
            text,
            text @@@ pgsearch.config('text:astronomical') AS score,
            2 AS source,
            ROW_NUMBER() OVER () AS rank_bm25
        FROM
            documents
        ORDER BY score
        LIMIT 10
), hnsw AS (
        SELECT
            id,
            docname,
            title,
            text,
            vector <-> ARRAY[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1] AS score,
            1 AS source,
            ROW_NUMBER() OVER (ORDER BY vector <-> ARRAY[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1]) AS rank_hnsw
        FROM
            documents
        ORDER BY vector <-> ARRAY[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1]
        LIMIT 10
)
SELECT 
    COALESCE(bm25.id, hnsw.id) AS id,
    COALESCE(bm25.docname, hnsw.docname) AS docname,
    COALESCE(bm25.title, hnsw.title) AS title,
    COALESCE(bm25.text, hnsw.text) as text,
    CASE 
        WHEN bm25.rank_bm25 > 0 AND hnsw.rank_hnsw > 0 THEN 
            COALESCE(1.0 / (60 + bm25.rank_bm25), 0) + COALESCE(1.0 / (60 + hnsw.rank_hnsw), 0)
        WHEN bm25.rank_bm25 > 0 THEN 
            COALESCE(1.0 / (60 + bm25.rank_bm25), 0)
        WHEN hnsw.rank_hnsw > 0 THEN 
            COALESCE(1.0 / (60 + hnsw.rank_hnsw), 0)
        ELSE 0
    END AS hybrid_score
FROM 
    bm25
FULL OUTER JOIN hnsw ON bm25.id = hnsw.id 
ORDER BY hybrid_score DESC;

ステップ 4: (オプション) 関数をカプセル化して呼び出す

ステップ 3 のクエリを関数としてカプセル化して、呼び出しを簡素化します。

  1. クエリを関数としてカプセル化します。

    CREATE OR REPLACE FUNCTION search_documents(
        table_name TEXT,
        vector_column TEXT,
        text_column TEXT,
        search_keyword TEXT,
        search_vector REAL[],
        limit_size INT,
        hnsw_weight FLOAT8 DEFAULT 0.8  -- hnsw のデフォルトの重み
    )
    RETURNS TABLE (
        id TEXT,
        docname TEXT,
        title TEXT,
        text TEXT,
        hybrid_score FLOAT8
    ) AS $$
    DECLARE
        query_string TEXT;
        bm25_weight FLOAT8;
    BEGIN
        bm25_weight := 1.0 - hnsw_weight;
    
        query_string := 'WITH t1 AS (
                                SELECT
                                    id,
                                    docname,
                                    title,
                                    ' || text_column || ',
                                    ' || text_column || ' @@@ pgsearch.config(''' || search_keyword || ''') AS score,
                                    2 AS source
                                FROM
                                    ' || table_name || '
                                ORDER BY score	
                                LIMIT ' || limit_size || '
                        ), t2 AS (
                                SELECT
                                    id,
                                    docname,
                                    title,
                                    ' || text_column || ',
                                    cosine_similarity(' || vector_column || ', $1) AS score,
                                    1 AS source
                                FROM
                                    ' || table_name || '
                                ORDER BY ' || vector_column || ' <-> $1
                                LIMIT ' || limit_size || '
                        )
                        SELECT t2.id, t2.docname, t2.title, t2.' || text_column || ', 
                        COALESCE(ABS(t1.score), 0.0) * ' || bm25_weight || ' + 
                        COALESCE(t2.score, 0.0) * ' || hnsw_weight || ' AS hybrid_score
                        FROM t1
                        FULL OUTER JOIN t2 ON t1.id = t2.id 
                        ORDER BY hybrid_score DESC;';
        
     RETURN QUERY EXECUTE query_string USING search_vector;
    END; $$
    LANGUAGE plpgsql;
  2. カプセル化された search_documents() 関数を呼び出します。

    SELECT * 
    FROM search_documents(
        'documents', 
        'vector',
        'text', 
        'astronomical', 
        ARRAY[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1], 
        10,
        0.8
    );

関連情報

ハイブリッド検索を使用して、ベクトル検索と全文検索に基づく双方向検索を実行します。