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

ApsaraDB RDS:ApsaraDB RDS for PostgreSQL を使用して RAG アプリケーションを作成する

最終更新日:Feb 26, 2025

ApsaraDB RDS for PostgreSQL は、強力なベクトルストレージと効率的な全文検索機能を提供します。 これにより、ApsaraDB RDS for PostgreSQL は、キーワードベースの取得を実装するための取得拡張生成 (RAG) アプリケーションの理想的なベクトルデータベースとなります。

はじめに

このトピックでは、ApsaraDB RDS for PostgreSQL を使用して専用のチケットチャットボットを作成する方法の例を示し、RAG アプリケーションの作成における ApsaraDB RDS for PostgreSQL の利点を示します。 このトピックを読んだ後、以下の情報を取得できます。

  • 手順: ApsaraDB RDS for PostgreSQL を使用して専用のチケットチャットボットを作成する手順と、関連する拡張機能と関数の使用方法

  • : マルチパスリコールの例で、RAG における ApsaraDB RDS for PostgreSQL の強力な機能と使いやすさを体験する

手順

ApsaraDB RDS for PostgreSQL を使用して専用のチケットチャットボットを作成するには、データ処理、マルチパスリコール、マージソート、Q&A分析といういくつかの重要な手順が必要です。

  • データ処理

    公式ドキュメント、ナレッジベース、過去のチケットからのデータを含むソースデータは、処理されて ApsaraDB RDS for PostgreSQL インスタンスに保存されます。 データ処理は、データのセグメント化と埋め込みで構成されます。

  • マルチパスリコール

    • ドキュメントキーワードベースのリコール: 類似検索を実行して、ユーザーの質問とドキュメントテーブル内のキーワードを照合し、類似度の最も高い上位 N 件のドキュメントを返します。

    • コンテンツキーワードベースのリコール: ドキュメントコンテンツのキーワードに基づいて類似検索を実行し、ユーザーの質問とキーワードを照合します。

    • BM25 ベースのリコール: 単語の頻度、単語の距離、単語が属するドキュメントモジュールの重要性に基づいて関連性スコアを統計分析し、スコアの高いコンテンツを返します。

    • 埋め込みベースのリコール: 質問を埋め込みに変換し、そのコサイン類似度を計算してから、類似度の高いコンテンツを返します。

  • マージソート

    逆順位融合 (RRF) アルゴリズムとオープンソースの bce-reranker-base_v1 モデルを使用して、マルチパスリコールの結果を正確にソートします。

  • Q&A分析

    質問とその回答はデータベースに保存されます。 テストフェーズでは、Q&A パフォーマンスがスコアリングされ、さまざまな取得ポリシーの効果が評価されます。

データ処理

公式ドキュメント、ナレッジベース、過去のチケットからのデータを含むソースデータは、処理されて RDS インスタンスに保存されます。 データ処理は、データのセグメント化と埋め込みで構成されます。

データ取得

関連データは、RAG アプリケーションの目的に基づいて取得されます。 このトピックでは、ApsaraDB RDS for PostgreSQL ベースの DingTalk チケットチャットボットを例として使用して、ヘルプドキュメント、ナレッジベース、過去のチケットからデータを収集します。

データ処理

ソースデータは処理され、特定の形式で RDS インスタンスに保存されます。 たとえば、LangChain フレームワークで提供されている HTMLHeaderTextSplitter クラスを使用して、H1 や H2 などの HTML 階層に基づいてヘルプドキュメントのテキストをセグメント化できます。 データのセグメント化サイズとデータの重複サイズを指定して、テキストのセグメント化パフォーマンスを柔軟に制御できます。 詳細については、LangChain で提供されているさまざまなテキストスプリッターを参照してください。

説明

Markdown ドキュメントを処理する必要がある場合は、MarkdownHeaderTextSplitter クラスと # や ## などのフラグを使用して階層分割を実行できます。

データストレージ

データは、ドキュメントと埋め込みという 2 つのコアテーブルに保存されます。 ドキュメントテーブルはドキュメント情報の保存に使用されます。 埋め込みテーブルは、セグメント化後に埋め込み情報を保存するために使用されます。

  • ドキュメントテーブル

    例:

    \d document
                                               Data table "public.document"
           Field        |            Type             | Collation |  Nullable  |                 Default
    -------------------+-----------------------------+----------+----------+--------------------------------------
     id                | bigint                      |          | not null | nextval('document_id_seq'::regclass)
     title             | character varying(255)      |          |          |
     url               | character varying(255)      |          |          | ''::character varying
     key_word          | character varying(255)      |          |          | ''::character varying
     tag               | character varying(255)      |          |          | ''::character varying
     created           | timestamp without time zone |          | not null | now()
     modified          | timestamp without time zone |          | not null | now()
     key_word_tsvector | tsvector                    |          |          |
     product_name      | character varying(255)      |          |          | ''::character varying
    Indexes:
        "document_pkey" PRIMARY KEY, btree (id)
        "document_key_word_tsvector_gin" gin (key_word_tsvector)
        "document_product_name_key" btree (product_name)
        "document_title_key" UNIQUE CONSTRAINT, btree (title)
    Triggers:
        trigger_update_tsvector BEFORE INSERT OR UPDATE ON document FOR EACH ROW EXECUTE FUNCTION update_tsvector()
    • ドキュメントテーブル

      テーブルには、id、title、url、key_word、tag、created、modified、key_word_tsvector、product_name の各フィールドが含まれています。 key_word フィールドはキーワードを示します。 created フィールドは作成時刻を示します。 modified フィールドは変更時刻を示します。 key_word_tsvector フィールドは、キーワードの重み付き tsvector 値を示します。 key_word_tsvector フィールドは、キーワードの照合と、コンテンツキーワードベースのリコールの一部として使用されます。

    • インデックス

      インデックスには、document_pkey、document_title_key、document_product_name_key、document_key_word_tsvector_gin が含まれます。 document_pkey インデックスはプライマリキー ID のインデックスです。 document_title_key インデックスはドキュメントタイトルのインデックスです。 ドキュメントはドキュメントタイトルに基づいて更新されるため、ドキュメントタイトルは一意である必要があります。 document_product_name_key インデックスは製品名のインデックスです。 document_key_word_tsvector_gin インデックスは、tsvector 値の GIN インデックスです。 ApsaraDB RDS for PostgreSQL では、GIN インデックスが許可されています。

    • トリガー

      ドキュメントテーブルが更新されたり、テーブルにデータが挿入されたりすると、トリガーによって key_word_tsvector 列のコンテンツが自動的に更新されます。

      トリガーを作成するための SQL 文

      1. tag 列のコンテンツにデータの挿入または更新がないかチェックする関数を定義します。 tag フィールドが direct に設定されている場合は、key_word フィールドで指定されたキーワードを tsvector 値に変換し、tsvector 値に重み A を割り当てます。

        説明

        ApsaraDB RDS for PostgreSQL で提供されている setweight 関数を使用して、tsvector 値の重みを指定できます。 重みは降順に A、B、C、D です。 重みを指定してキーワードベースのリコールを使用する場合、tag フィールドが direct に設定されているドキュメントが優先的に照合され、次に tag フィールドが aone に設定されているドキュメントが照合されます。 重みは優先順位に基づいて指定されます。

      2. update_tsvector() 関数を自動的に実行するトリガーを作成します。 この関数は、ドキュメントテーブルが更新されると key_word_tsvector 列のコンテンツを更新します。

      CREATE OR REPLACE FUNCTION update_tsvector()
      RETURNS TRIGGER AS $$
      BEGIN
          IF TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN
              IF NEW.tag = 'direct' THEN
                  NEW.key_word_tsvector := setweight(to_tsvector('jiebacfg', NEW.key_word), 'A');
              ELSIF NEW.tag = 'aone' THEN
                  NEW.key_word_tsvector := setweight(to_tsvector('jiebacfg', NEW.key_word), 'B');
              ELSIF NEW.tag IS NOT NULL THEN
                  NEW.key_word_tsvector := setweight(to_tsvector('jiebacfg', NEW.key_word), 'C');
              ELSE
                  NEW.key_word_tsvector := setweight(to_tsvector('jiebacfg', NEW.key_word), 'D');
              END IF;
          END IF;
      
          RETURN NEW;
      END;
      $$ LANGUAGE plpgsql;
      CREATE FUNCTION
        
      CREATE TRIGGER trigger_update_tsvector
      BEFORE INSERT OR UPDATE ON document
      FOR EACH ROW
      EXECUTE FUNCTION update_tsvector();
      CREATE TRIGGER
  • 埋め込みテーブル

    例:

    \d embedding
                                               Data table "public.embedding"
           Field        |            Type             | Collation |  Nullable  |                 Default
    -------------------+-----------------------------+----------+----------+---------------------------------------
     id                | bigint                      |          | not null | nextval('embedding_id_seq'::regclass)
     doc_id            | integer                     |          |          | '-1'::integer
     content_chunk     | text                        |          | not null |
     content_embedding | vector(1536)                |          | not null |
     created           | timestamp without time zone |          | not null | now()
     modified          | timestamp without time zone |          | not null | now()
     ts_vector_extra   | tsvector                    |          |          |
    Indexes:
        "embedding_pkey" PRIMARY KEY, btree (id)
        "embedding_content_embedding_idx" hnsw (content_embedding vector_cosine_ops) WITH (m='16', ef_construction='64')
        "embedding_doc_id_key" btree (doc_id)
        "embedding_rumidx" rum (ts_vector_extra)
    Triggers:
        embedding_tsvector_update BEFORE INSERT OR UPDATE ON embedding FOR EACH ROW EXECUTE FUNCTION tsvector_update_trigger('ts_vector_extra', 'public.jiebacfg', 'content_chunk')
    • 埋め込みテーブル

      埋め込みテーブルには、id、doc_id、content_chunk、content_embedding、created、modified、ts_vector_extra の各フィールドが含まれています。 doc_id フィールドはドキュメント ID を示します。 content_chunk フィールドは、セグメント化後のチャンクを示します。 content_embedding フィールドは、単語分割後に取得されたチャンクの埋め込みを示します。 created フィールドは作成時刻を示します。 modified フィールドは変更時刻を示します。 ts_vector_extra フィールドは、セグメント化後のチャンクの tsvector 値を示します。

    • インデックス

      インデックスには、embedding_pkey、embedding_doc_id_key、embedding_content_embedding_idx、embedding_rumidx が含まれます。 embedding_pkey インデックスはプライマリキーのインデックスです。 embedding_doc_id_key インデックスはドキュメント ID のインデックスです。 embedding_content_embedding_idx インデックスは、content_embedding 列のベクトルインデックスです。 embedding_rumidx インデックスは、tsvector 値の RUM インデックスです。

    • トリガー

      埋め込みテーブルが更新された場合、またはテーブルにデータが挿入された場合、トリガーによって ts_vector_extra 列のコンテンツが自動的に更新されます。

      トリガーを作成するための SQL 文

      SQL 文は、ドキュメントテーブルのトリガーを作成するために使用される SQL 文と似ています。

      CREATE TRIGGER embedding_tsvector_update
      BEFORE INSERT OR UPDATE ON embedding
      FOR EACH ROW
      EXECUTE PROCEDURE tsvector_update_trigger('ts_vector_extra','public.jiebacfg','content_chunk');

マルチパスリコール

ドキュメントキーワードベースのリコール

ドキュメントキーワードベースのリコールは、類似検索を実行して、ユーザーの質問とドキュメントテーブル内のキーワードを照合し、類似度の最も高い上位 N 件のドキュメントを返します。

ドキュメントキーワードベースのリコールでは、ApsaraDB RDS for PostgreSQL で事前に定義された GIN インデックスを使用して、RDS インスタンス内のキーワードとユーザーの質問を効率的に照合します。

  1. ドキュメント内のキーワードを tsvector 値に変換し、tsvector 値の重みを割り当てます。

    変換中は、単語分割モードを指定する必要があります。 ほとんどの場合、中国語単語分割拡張機能である pg_jiebazhparser が使用されます。 拡張機能のインストール方法の詳細については、「拡張機能を管理する」をご参照ください。

    to_tsvector 関数を使用してキーワードをセグメント化し、setweight 関数を使用してセグメント化後の文字列の重みを指定できます。 これにより、位置情報に重み情報が追加されます。 たとえば、pg_jieba 拡張機能を使用し、単語分割モードを jiebacfg に設定し、setweight 関数を使用してドキュメントキーワードの重みを A に設定します。

    SELECT setweight(to_tsvector('jiebacfg', 'PostgreSQLは世界で最も先進的なオープンソースのリレーショナルデータベースです'), 'A');
                                       setweight
    -------------------------------------------------------------------------------
     'postgresql':1A '世界':3A '先進':5A '的':6A 'オープンソース':7A 'リレーショナルデータベース':10A '最も':4A
    
  2. ユーザーの質問を tsquery 値に変換し、tsquery 値とドキュメントキーワードを照合します。

    ApsaraDB RDS for PostgreSQL の全文検索機能を使用して、ユーザーの質問とドキュメントキーワードを照合します。 ステートメントの例:

    SELECT 
        id, 
        title, 
        url, 
        key_word, 
        ts_rank(
            key_word_tsvector, 
            to_tsquery(replace(text(plainto_tsquery('jiebacfg', '%s')), '&', '|'))
        ) AS score 
    FROM 
        public.document 
    WHERE 
        key_word_tsvector @@ to_tsquery(replace(text(plainto_tsquery('jiebacfg', '%s')), '&', '|')) 
        AND product_name = '%s' 
    ORDER BY 
        score DESC 
    LIMIT 1;
    • to_tsquery 関数

      to_tsquery 関数を使用して、ユーザーの質問を tsquery 値に変換します。 例:

      SELECT to_tsquery('jiebacfg', 'PostgreSQLは世界で最も先進的なオープンソースのリレーショナルデータベースです');
                                         to_tsquery
      --------------------------------------------------------------------------------
       'postgresql' <2> '世界' <2> '先進' <-> 'オープンソース' <-> 'リレーショナルデータベース'
      

      <2> は 2 つの単語間の距離を示します。<-> は隣接関係を示します。 たとえば、オープンソースリレーショナルデータベース は隣接している必要があります。 また、 などのストップワードは自動的に削除されます。 アンパサンド (&) は AND を、縦棒 (|) は OR を、感嘆符 (!) は NOT を示します。 重みを指定することもできます。 例:

      SELECT to_tsquery('jiebacfg', 'postgresql:A');
         to_tsquery
      ----------------
       'postgresql':A
      

      to_tsquery 関数への入力は、tsquery の演算子の要件を満たしている必要があります。 ユーザーの質問が tsquery 値に正常に変換されるようにするには、to_tsquery 関数の代わりに plainto_tsquery 関数を使用すると、無効な演算子を効果的に無視できます。 例:

      SELECT to_tsquery('jiebacfg','ログ|&ヒープ');
      ERROR:  tsquery の構文エラー: "ログ|&ヒープ"
        
      SELECT plainto_tsquery('jiebacfg','ログ|&ヒープ');
       plainto_tsquery
      -----------------
       'ログ' & 'ヒープ'
      

      text 関数を使用して、plainto_tsquery 関数によって返された結果をテキスト値に変換します。 次に、replace 関数を使用して &| に置き換えることで、一致条件を AND から OR に変換します。 例:

      -- plainto_tsquery 関数を使用します。
      SELECT plainto_tsquery('jiebacfg', 'PostgreSQLは世界で最も先進的なオープンソースのリレーショナルデータベースです');
                                plainto_tsquery
      --------------------------------------------------------------------
       'postgresql' & '世界' & '先進' & 'オープンソース' & 'リレーショナルデータベース'
      
      -- plainto_tsquery、text、replace 関数を使用します。
      SELECT replace(text(plainto_tsquery('jiebacfg', 'PostgreSQLは世界で最も先進的なオープンソースのリレーショナルデータベースです')), '&', '|');
                                    replace
      --------------------------------------------------------------------
       'postgresql' | '世界' | '先進' | 'オープンソース' | 'リレーショナルデータベース'
      
      -- to_tsquery、plainto_tsquery、text、replace 関数を使用します。
      SELECT to_tsquery(replace(text(plainto_tsquery('jiebacfg', 'PostgreSQLは世界で最も先進的なオープンソースのリレーショナルデータベースです')), '&', '|'));
                                   to_tsquery
      --------------------------------------------------------------------
       'postgresql' | '世界' | '先進' | 'オープンソース' | 'リレーショナルデータベース'
      

      pg_jieba 拡張機能のカスタム単語分割機能を使用して、カスタム単語分割メソッドを作成します。 たとえば、リレーショナルデータベース をカスタム辞書に追加する前のテキスト分割結果は 'リレーショナル' & 'データベース' で、カスタム辞書に追加した後は 'リレーショナルデータベース' です。

      -- リレーショナルデータベース を重み 100000 でカスタム辞書 0 に自動的に追加します。
      INSERT INTO jieba_user_dict VALUES ('リレーショナルデータベース',0,100000);
      
      -- カスタム辞書 0 をロードします。 最初の 0 はカスタム辞書のシーケンス番号を示し、2 番目の 0 はデフォルト辞書がロードされることを示します。
      SELECT jieba_load_user_dict(0,0);
       jieba_load_user_dict
      ----------------------
      
      -- ユーザーの質問を tsquery 値に変換します。
      SELECT to_tsquery(replace(text(plainto_tsquery('jiebacfg', 'PostgreSQLは世界で最も先進的なオープンソースのリレーショナルデータベースです')), '&', '|'));
                                   to_tsquery
      --------------------------------------------------------------------
       'postgresql' | '世界' | '先進' | 'オープンソース' | 'リレーショナルデータベース'
      
    • 演算子

      ApsaraDB RDS for PostgreSQL は、さまざまな 演算子 を提供して、単語分割後の tsvector 値と tsquery 値に対する操作を実行します。 たとえば、@@ を使用して、tsvector 値が tsquery 値と一致するかどうかを示すことができます。

      SELECT to_tsvector('jiebacfg', 'PostgreSQLは世界で最も先進的なオープンソースのリレーショナルデータベースです') @@ to_tsquery('jiebacfg', 'postgresql:A');
       ?column?
      ----------
       f
      
      
      SELECT setweight(to_tsvector('jiebacfg', 'PostgreSQLは世界で最も先進的なオープンソースのリレーショナルデータベースです'),'A') @@ to_tsquery('jiebacfg', 'postgresql:A');
       ?column?
      ----------
       t
      

      クエリ条件は、重み A の単語 postgresql です。 この場合、クエリ対象の tsvector 値に単語 postgresql が含まれていても、重み A が割り当てられていないため、false が返されます。 ただし、setweight 関数を使用してクエリ対象の tsvector 値に重み A が割り当てられている場合は、true が返されます。

    • ts_rank 関数

      ts_rank 関数を使用して、tsquery 値とクエリ対象の tsvector 値の間の一致度を計算します。 たとえば、クエリ条件が postgresql | オープンソース の場合、クエリ対象の行には、postgresqlオープンソース キーワードの少なくとも 1 つが含まれている必要があります。 最初の文には両方のキーワードが含まれています。 そのスコアは、オープンソース キーワードのみを含む 2 番目の文よりも高くなります。 3 番目の文は、postgresqlオープンソース も含まれていないため、@@ 演算子によってスキップされます。

      WITH sentence AS (
          SELECT 'PostgreSQLは世界で最も先進的なオープンソースのリレーショナルデータベースです' AS content
          UNION ALL
          SELECT 'MySQLは広く使用されているオープンソースのリレーショナルデータベースです'
          UNION ALL
          SELECT 'MySQLは世界中で非常に人気があります'
      )
      SELECT content,
             ts_rank(to_tsvector('jiebacfg', content), to_tsquery('jiebacfg', 'postgresql | オープンソース')) AS score
      FROM sentence
      WHERE to_tsvector('jiebacfg', content) @@ to_tsquery('jiebacfg', 'postgresql | オープンソース')
      ORDER BY score DESC;
      
                        content                   |    score
      --------------------------------------------+-------------
       PostgreSQLは世界で最も先進的なオープンソースのリレーショナルデータベースです |  0.06079271
       MySQLは広く使用されているオープンソースのリレーショナルデータベースです          | 0.030396355
      

      極端な場合、単語分割の問題が発生したり、入力が不正な文字を含んでいると、ドキュメントが一致しない可能性があります。 この問題を防ぐために、ApsaraDB RDS for PostgreSQL では、pg_bigm 拡張機能を使用してあいまい一致ベースの検索を実行できます。 bigm_similarity 関数を使用して、類似度の最も高いドキュメントを返すことができます。 例:

      WITH sentence AS (
          SELECT 'PostgreSQLは世界で最も先進的なオープンソースのリレーショナルデータベースです' AS content
          UNION ALL
          SELECT 'MySQLは広く使用されているオープンソースのリレーショナルデータベースです'
          UNION ALL
          SELECT 'MySQLは世界中で非常に人気があります'
      )
      SELECT 
          content, 
          bigm_similarity(content, 'postgres | オープンソース製品') AS score 
      FROM 
          sentence
      ORDER BY 
          score DESC;
      
                        content                   |   score
      --------------------------------------------+------------
         PostgreSQLは世界で最も先進的なオープンソースのリレーショナルデータベースです | 0.23076923
         MySQLは広く使用されているオープンソースのリレーショナルデータベースです          | 0.05263158
         MySQLは世界中で非常に人気があります                      |        0.0
      (3 rows)
      

      bigm_similarity 関数は、2 つの入力テキストを、2 つの連続した文字または 2 つの単語の組み合わせである 2-gram 要素に変換します。 次に、この関数は入力テキスト間の要素の数を計算します。 有効な値: [0, 1]。 値 1 は、テキストが同じであることを示します。 セグメント化が不正確な場合、スペルミスが存在する場合、または省略形が使用されている場合は、pg_bigm 拡張機能を使用してあいまい一致ベースの検索を実行できます。 詳細については、「pg_bigm 拡張機能を使用してあいまい一致ベースのクエリを実行する」をご参照ください。

コンテンツキーワードベースのリコール

ドキュメントコンテンツを検索するには、「ドキュメントキーワードベースのリコール」で使用したのと同じ方法を使用できます。 ほとんどの場合、ドキュメントコンテンツはキーワードよりも長くなります。 全文検索を実行する場合は、RUM 拡張機能 を使用して検索を高速化することをお勧めします。 たとえば、サンプルクエリプランを使用して類似検索を実行し、ユーザーの質問とドキュメントコンテンツのキーワードを照合できます。

  • RUM 拡張機能は GIN インデックスに基づいており、単語の位置やタイムスタンプなどの追加情報を保存します。 次のクエリプランでは、RUM 拡張機能の実行プランを使用し、embedding_rumidx インデックスを使用し、データをフィルタリングし、類似度を計算し、結果をソートします。 すべての操作はインデックスによって完了するため、クエリの効率が保証されます。 クエリには 3.219 ミリ秒かかります。

    RUM 拡張機能を使用して全文検索を実行する

    EXPLAIN ANALYZE
    SELECT
        id,
        doc_id,
        content_chunk,
        ts_vector_extra <=> to_tsquery(
            REPLACE(
                TEXT(plainto_tsquery('jiebacfg', 'walログヒープはどうすればよいですか')),
                '&',
                '|'
            )
        ) AS similarity
    FROM
        embedding
    WHERE
        ts_vector_extra @@ to_tsquery(
            REPLACE(
                TEXT(plainto_tsquery('jiebacfg', 'walログヒープはどうすればよいですか')),
                '&',
                '|'
            )
        )
    ORDER BY
        similarity
    LIMIT
        10;
                                                                     QUERY PLAN
    --------------------------------------------------------------------------------------------------------------------------------------------
     Limit  (cost=10.15..22.14 rows=10 width=521) (actual time=3.117..3.182 rows=10 loops=1)
       ->  Index Scan using embedding_rumidx on embedding  (cost=10.15..6574.53 rows=5474 width=521) (actual time=3.115..3.179 rows=10 loops=1)
             Index Cond: (ts_vector_extra @@ to_tsquery('''wal'' | ''ログ'' | ''ヒープ'''::text))
             Order By: (ts_vector_extra <=> to_tsquery('''wal'' | ''ログ'' | ''ヒープ'''::text))
     Planning Time: 0.296 ms
     Execution Time: 3.219 ms
    (6 rows)
  • 次のクエリプランでは、冗長な ts_vector_extra 列に基づいて構築されたネイティブ GIN インデックスを使用します。 ネイティブ GIN インデックスの実行プランは、RUM 拡張機能の実行プランよりも複雑です。 ネイティブ GIN インデックスの実行プランは 2 つのプロセスを開始し、RUM のインデックススキャンの代わりにビットマップインデックススキャンを使用します。 具体的には、インデックスを使用してクエリ条件を満たすすべての行のビットマップを取得し、embedding_ts_vector_gin で指定されたインデックスを使用して関連行を特定します。 セカンダリフィルターを実行して有効な結果を検索します。 次に、Top-N アルゴリズムを使用して結果をソートし、プロセスで gather merge を実行して結果を結合します。 クエリには 14.234 ミリ秒かかります。

    ネイティブ GIN インデックスを使用してクエリを高速化する

    EXPLAIN ANALYZE
    SELECT
        id,
        doc_id,
        content_chunk,
        ts_rank(
            ts_vector_extra,
            to_tsquery(
                REPLACE(
                    TEXT(plainto_tsquery('jiebacfg', 'walログヒープはどうすればよいですか')),
                    '&',
                    '|'
                )
            )
        ) AS similarity
    FROM
        embedding
    WHERE
        ts_vector_extra @@ to_tsquery(
            REPLACE(
                TEXT(plainto_tsquery('jiebacfg', 'walログヒープはどうすればよいですか')),
                '&',
                '|'
            )
        )
    ORDER BY
        similarity
    LIMIT
        10;
                                                                           QUERY PLAN
    ---------------------------------------------------------------------------------------------------------------------------------------------------------
     Limit  (cost=7178.59..7179.76 rows=10 width=520) (actual time=10.526..14.192 rows=10 loops=1)
       ->  Gather Merge  (cost=7178.59..7718.33 rows=4626 width=520) (actual time=10.525..14.189 rows=10 loops=1)
             Workers Planned: 2
             Workers Launched: 2
             ->  Sort  (cost=6178.57..6184.35 rows=2313 width=520) (actual time=6.879..6.880 rows=10 loops=3)
                   Sort Key: (ts_rank(ts_vector_extra, to_tsquery('''wal'' | ''ログ'' | ''ヒープ'''::text)))
                   Sort Method: top-N heapsort  Memory: 37kB
                   Worker 0:  Sort Method: top-N heapsort  Memory: 39kB
                   Worker 1:  Sort Method: top-N heapsort  Memory: 40kB
                   ->  Parallel Bitmap Heap Scan on embedding  (cost=56.47..6128.59 rows=2313 width=520) (actual time=0.567..6.367 rows=1637 loops=3)
                         Recheck Cond: (ts_vector_extra @@ to_tsquery('''wal'' | ''ログ'' | ''ヒープ'''::text))
                         Heap Blocks: exact=1515
                         ->  Bitmap Index Scan on embedding_ts_vector_gin  (cost=0.00..55.08 rows=5551 width=0) (actual time=0.794..0.794 rows=4910 loops=1)
                               Index Cond: (ts_vector_extra @@ to_tsquery('''wal'' | ''ログ'' | ''ヒープ'''::text))
     Planning Time: 0.291 ms
     Execution Time: 14.234 ms
    
  • GIN インデックスは to_tsvector('jiebacfg'::regconfig, content_chunk) に構築されます。 これらの GIN インデックスの実行プランは、ts_vector_extra 列に構築された GIN インデックスの実行プランと似ています。 WHERE 条件は同じで、ランキングステージに入る行数も同様です。 主な違いは ts_rank の計算にあります。 ts_rank 関数には単語の位置情報が必要です。 GIN インデックスが作成されると、位置情報は保存されません。 ts_rank 関数を使用すると、to_tsvector 関数が各行で実行されるため、時間がかかります。 クエリには 1081.547 ミリ秒かかります。

    to_tsvector('jiebacfg'::regconfig, content_chunk) に構築された GIN インデックス

    EXPLAIN ANALYZE
    SELECT
        id,
        doc_id,
        content_chunk,
        ts_rank(
            to_tsvector('jiebacfg', content_chunk),
            to_tsquery(
                REPLACE(
                    TEXT(plainto_tsquery('jiebacfg', 'walログヒープはどうすればよいですか')),
                    '&',
                    '|'
                )
            )
        ) AS similarity
    FROM
        embedding
    WHERE
        to_tsvector('jiebacfg', content_chunk) @@ to_tsquery(
            REPLACE(
                TEXT(plainto_tsquery('jiebacfg', 'walログヒープはどうすればよいですか')),
                '&',
                '|'
            )
        )
    ORDER BY
        similarity
    LIMIT
        10;
                                                                          QUERY PLAN
    -------------------------------------------------------------------------------------------------------------------------------------------------------
     Limit  (cost=8253.58..8254.75 rows=10 width=521) (actual time=1079.289..1081.510 rows=10 loops=1)
       ->  Gather Merge  (cost=8253.58..8786.55 rows=4568 width=521) (actual time=1079.287..1081.508 rows=10 loops=1)
             Workers Planned: 2
             Workers Launched: 2
             ->  Sort  (cost=7253.56..7259.27 rows=2284 width=521) (actual time=1073.189..1073.191 rows=10 loops=3)
                   Sort Key: (ts_rank(to_tsvector('jiebacfg'::regconfig, content_chunk), to_tsquery('''wal'' | ''ログ'' | ''ヒープ'''::text)))
                   Sort Method: top-N heapsort  Memory: 43kB
                   Worker 0:  Sort Method: top-N heapsort  Memory: 42kB
                   Worker 1:  Sort Method: top-N heapsort  Memory: 37kB
                   ->  Parallel Bitmap Heap Scan on embedding  (cost=55.93..7204.20 rows=2284 width=521) (actual time=2.127..1072.159 rows=1637 loops=3)
                         Recheck Cond: (to_tsvector('jiebacfg'::regconfig, content_chunk) @@ to_tsquery('''wal'' | ''ログ'' | ''ヒープ'''::text))
                         Heap Blocks: exact=1028
                         ->  Bitmap Index Scan on embedding_content_gin  (cost=0.00..54.56 rows=5481 width=0) (actual time=0.808..0.809 rows=4910 loops=1)
                               Index Cond: (to_tsvector('jiebacfg'::regconfig, content_chunk) @@ to_tsquery('''wal'' | ''ログ'' | ''ヒープ'''::text))
     Planning Time: 0.459 ms
     Execution Time: 1081.547 ms
    (16 rows)

BM25 ベースのリコール

BM25 は、単語頻度 (TF) と逆文書頻度 (IDF) の影響を考慮した古典的なテキストマッチングアルゴリズムです。 TF が大きい単語は、ドキュメントに頻繁に出現し、強い関連性があることを示します。 IDF が大きい単語は、複数のドキュメントに出現し、重要度が低いことを示します。 BM25 アルゴリズムは、TF-IDF アルゴリズムを最適化し、クエリ効果を向上させるためのパラメータを導入しています。

BM25 ベースのリコールはキーワードベースの取得方法として使用され、ApsaraDB RDS for PostgreSQL のキーワードベースの取得方法と比較されます。 ApsaraDB RDS for PostgreSQL のキーワードベースの取得方法では、ts_rank などのビルトイン関数を使用し、ドキュメントの各部分における単語の頻度、単語の距離、単語の重要度を考慮します。 BM25 ベースのリコール結果は、キーワードベースの取得結果の一部と見なすことができ、取得精度を向上させます。

埋め込みベースのリコール

ApsaraDB RDS for PostgreSQL は、高次元ベクトル類似検索 (pgvector) 拡張機能と ベクトル生成 (rds_embedding) 拡張機能をサポートしています。 pgvector 拡張機能は、必要なベクトルデータ型と、ベクトル間の距離や類似度の計算などの基本的なベクトルデータ操作をサポートしています。 rds_embedding 拡張機能は、高次元テキストを埋め込みに変換するだけです。 詳細については、「pgvector 拡張機能を使用して高次元ベクトル類似検索を実行する」および「rds_embedding 拡張機能を使用してベクトルを生成する」をご参照ください。

ApsaraDB RDS for PostgreSQL では、ベクトルを配列として保存できます。 ただし、データ型はベクトル型として定義する必要があります。 ベクトル計算とランキングを実行する場合、ベクトル型のインデックスを作成しないと、全表スキャンとランキングのオーバーヘッドが大幅に増加します。

pgvector 拡張機能は、近似最近傍探索 (ANN) のための階層型ナビゲーションスモールワールド (HNSW) と反転ファイルとフラット圧縮 (IVFFlat) のインデックス作成方法をサポートしています。 HNSW インデックス作成ではデータの挿入は不要で、IVFFlat インデックス作成よりも高速なクエリ速度を実現します。 そのため、この方法では HNSW インデックス作成が使用されます。

SELECT 
    embedding.id, 
    doc_id, 
    content_chunk, 
    content_embedding <=> '%s' AS similarity 
FROM 
    public.embedding 
LEFT JOIN 
    document ON document.id = embedding.doc_id 
WHERE 
    product_name = '%s' 
ORDER BY 
    similarity 
LIMIT %s;
説明

マージソート

この方法では、RRF アルゴリズムとオープンソースの bce-reranker-base_v1 モデルを使用して、ドキュメントキーワードベースのリコール、コンテンツキーワードベースのリコール、BM25 ベースのリコール、埋め込みベースのリコールの結果を正確にソートします。

  • RRF アルゴリズムは理解しやすいものです。 次の式では、 は必要なドキュメントを、 はシステム 内のドキュメント のランキングを、 は定数を示します。 k は 60 または他の値に設定できます。 個のシステム内のドキュメントのランキングを合計して、最終結果を取得できます。 ランキングが高いほど、逆順で取得される値が大きくなります。 その結果、計算される RRF 値も大きくなります。 ドキュメントが複数のシステムで上位にランクされている場合、ドキュメントの RRF 値は大幅に増加します。 RRF アルゴリズムを使用すると、マルチパスリコールのチャンクを効果的にソートできます。

  • bce-reranker-base_v1 は、セマンティック検索結果と関連性ランキングを最適化することを目的とした、クロスランゲージセマンティック表現アルゴリズムモデルです。 このモデルは、中国語、英語、日本語、韓国語をサポートし、強力なファインランキング機能を備えています。 実際のシナリオでは、このモデルは、特に多数のチャンクをソートする必要がある場合、リコールの実行よりもファインランキングに時間がかかります。 これはセッションの流暢さに影響を与える可能性があります。 専用チケットチャットボットからの応答を高速化するには、シンプルで効率的な RRF アルゴリズムを使用して結果をソートするか、RRF ランキング後にファインランキングを実行できます。 高い精度が必要な場合は、bce-reranker-base_v1 モデルを直接使用して結果をソートできます。

Q&A分析

専用チケットチャットボットがさまざまなデータソースに応答するために、さまざまなポリシーが定義されています。 これにより、大規模モデルが呼び出されたときに prompt_content フィールドのコンテンツが予期せず処理されるのを防ぐのに役立ちます。

  • ナレッジベースのコンテンツは、大規模モデルが処理するための prompt_content フィールドの入力としては使用されません。 代わりに、コンテンツが直接提供されます。

  • 公式ドキュメントのコンテンツは、取得した HTML ファイルがセグメント化され、レイアウトの問題やコンテンツの重複が発生する可能性があるため、大規模モデルによって要約およびフォーマットされます。

  • 大規模モデルのコンテンツは、ナレッジベースと公式ドキュメントが必要な回答を提供できない場合にのみ直接提供されます。 大規模モデルは、少数のシナリオで問題を解決するために直接呼び出されます。 ほとんどの場合、大規模モデルは一般的なナレッジアシスタントとして機能します。

  • 過去のチケットのコンテンツは、チケット名と URL のみで提供されます。

回答の各部分について、関連ドキュメントとそのリンクが提供されます。 回答に基づいて問題を解決できない場合は、元のドキュメントを確認して、より包括的で正確なコンテンツを取得することをお勧めします。

テストフェーズでは、最新の質問と回答のスコアを、現在のポリシーの有効性の予備評価として使用できます。 コードを作成して複数のポリシーを作成し、テストに基づいて最適なリコールポリシーを決定できます。

prompt = f'''以下のコンテンツを整理してフォーマットし、出力フォーマットを整理してください。
        ```
        {prompt_content}
        ```
        自分の能力に基づいて回答してください。私の質問は{question}です。
        '''

DingTalk チャットボットに接続する

Streamlit を使用して Web アプリを作成したり、DingTalk チャットボットに接続したりできます。 Web アプリは、自己テストとドキュメント管理に使用されます。 DingTalk チャットボットを使用すると、すべてのユーザーがサービスにアクセスできます。

DingTalk グループの各 Q&A セッションでは、データベースレベルで新しい接続を確立する必要があります。 頻繁な接続の確立は、時間とメモリの消費など、パフォーマンスの問題を引き起こす可能性があります。 接続がすぐに解放されない場合、接続数が上限に達し、データベースへの新しい接続を確立できなくなる可能性があります。 プロジェクトで接続プールを使用すると、短期間の接続が頻繁に発生するのを防ぐことができます。 ApsaraDB RDS for PostgreSQL のビルトイン PgBouncer 接続プール を使用することもできます。

この例では、マルチパスリコールを使用して、RAG における ApsaraDB RDS for PostgreSQL の強力な機能と使いやすさを説明します。 この例では、ユーザーが PostgreSQL の紹介 という質問をします。 3 つの取得方法の結果が得られます。

データを準備する

  1. 特権アカウントを使用して、必要なデータベースで次の SQL 文を実行し、pg_jieba、pgvector、RUM、rds_embedding 拡張機能をインストールします。

    重要
    • pg_jieba 拡張機能をインストールする前に、shared_preload_libraries パラメータの に pg_jieba を追加する必要があります。 shared_preload_libraries パラメータの変更方法の詳細については、「ApsaraDB RDS for PostgreSQL インスタンスのパラメータを変更する」をご参照ください。

    • SELECT * FROM pg_extension; 文を実行して、インストールされている拡張機能を表示できます。

    CREATE EXTENSION IF NOT EXISTS pg_jieba;
    CREATE EXTENSION IF NOT EXISTS vector;
    CREATE EXTENSION IF NOT EXISTS rum;
    CREATE EXTENSION IF NOT EXISTS rds_embedding;
  2. RDS インスタンスが外部モデルにアクセスできるように、RDS インスタンスが存在する仮想プライベートクラウド (VPC) の NAT ゲートウェイを作成します。 詳細については、「rds_embedding 拡張機能を使用してベクトルを生成する」をご参照ください。

    説明

    デフォルトでは、インターネット経由で RDS インスタンスに接続することはできません。 Alibaba Cloud ModelScope で提供されているテキスト埋め込みモデルなどの外部大規模モデルを使用する場合は、RDS インスタンスが外部モデルにアクセスできるように、RDS インスタンスが存在する VPC の NAT ゲートウェイを作成する必要があります。

  3. 必要なデータベースで次の SQL 文を実行して、doc と embed という名前のテストテーブルを作成し、テーブルのインデックスを作成します。

    --doc テストテーブルとテーブルのインデックスを作成します。
    DROP TABLE IF EXISTS doc;
    
    CREATE TABLE doc (
        id bigserial PRIMARY KEY,
        title character varying(255) UNIQUE,
        key_word character varying(255) DEFAULT ''
    );
    
    CREATE INDEX doc_gin ON doc 
    USING GIN (to_tsvector('jiebacfg', key_word));
    
    --embed テストテーブルとテーブルのインデックスを作成します。
    DROP TABLE IF EXISTS embed;
    
    CREATE TABLE embed (
        id bigserial PRIMARY KEY,
        doc_id integer,
        content text,
        embedding vector(1536),
        ts_vector_extra tsvector
    );
    
    CREATE INDEX ON embed 
    USING hnsw (embedding vector_cosine_ops) 
    WITH (
        m = 16, 
        ef_construction = 64
    );
  4. 次の SQL 文を実行してトリガーを作成します。 embed テーブルの行が更新されたり、行にデータが挿入されたりすると、ts_vector_extra 列が自動的に更新されます。

    -- キーワードに基づいて全文検索を実行するために、テキストを tsvector 値に変換します。
    CREATE TRIGGER embed_tsvector_update 
    BEFORE UPDATE OR INSERT 
    ON embed 
    FOR EACH ROW 
    EXECUTE PROCEDURE tsvector_update_trigger('ts_vector_extra', 'public.jiebacfg', 'content');
  5. 次の SQL 文を実行します。 embed テーブルで挿入または更新が実行されるたびに、挿入または更新されたコンテンツに基づいて埋め込みが生成され、embedding 列に保存されます。

    重要

    この例では、Alibaba Cloud ModelScope で提供されているテキスト埋め込みモデルが使用されています。 Alibaba Cloud ModelScope をアクティブ化し、必要な API キーを取得する必要があります。 詳細については、「API キーを取得する」をご参照ください。

    -- 質問を埋め込みに変換します。 ビジネス要件に基づいて api_key パラメータを指定します。
    CREATE OR REPLACE FUNCTION update_embedding()
    RETURNS TRIGGER AS $$
    BEGIN
        NEW.embedding := rds_embedding.get_embedding_by_model('dashscope', 'sk-****', NEW.content)::real[];
        RETURN NEW;
    END;
    $$ LANGUAGE plpgsql;
    CREATE TRIGGER set_embedding BEFORE INSERT OR UPDATE ON embed FOR EACH ROW EXECUTE FUNCTION update_embedding();
  6. テーブルにテストデータを挿入します。

    INSERT INTO doc(id, title, key_word) VALUES 
    (1, 'PostgreSQL紹介', 'PostgreSQL プラグイン'), 
    (2, 'MySQL紹介', 'MySQL MGR'), 
    (3, 'SQL Server紹介', 'SQL Server Microsoft');
    
    INSERT INTO embed(doc_id, content) VALUES 
    (1, 'PostgreSQLは、カリフォルニア大学バークレー校のコンピュータサイエンス学部で開発された POSTGRES バージョン 4.2 をベースにしたオブジェクトリレーショナルデータベース管理システム (ORDBMS) です。 POSTGRES の先進的な多くの概念は、ずっと後に一部の商用データベースシステムに登場しました'), 
    (1, 'PostgreSQLは、最初のバークレーコードのオープンソースの後継です。 ほとんどの SQL 標準をサポートし、複雑なクエリ、外部キー、トリガー、更新可能なビュー、トランザクションの整合性、マルチバージョン同時実行制御など、多くの最新の機能を提供します。 また、PostgreSQLは、新しいデータ型、関数、演算子、集約関数、インデックスメソッド、手続き型言語などを追加するなど、さまざまな方法で拡張できます'), 
    (1, 'また、自由なライセンスにより、誰でも私用、商用、学術研究のいずれの目的でも、PostgreSQLを無料で使用、変更、配布できます。'), 
    (1, 'Ganos プラグインと PostGIS プラグインは、同じスキーマにインストールできません'), 
    (1, '豊富なエコシステム: PostGIS (地理情報処理)、TimescaleDB (時系列データベース)、pg_stat_statements (パフォーマンス監視) など、さまざまなシナリオのニーズを満たすことができる、すぐに使用できるプラグインと拡張機能が多数あります');
    
    INSERT INTO embed(doc_id, content) VALUES 
    (2, 'MySQL という名前の由来は不明です。 10 年以上にわたり、基本ディレクトリと多数のライブラリとツールでプレフィックス「my」を使用してきました。 ただし、共同設立者の Monty Widenius の娘の名前も「My」です。 今日まで、MySQL という名前の由来は謎のままです。'), 
    (2, 'MySQL ソフトウェアはデュアルライセンス方式を採用しています。 ユーザーは、GNU 一般公衆利用許諾契約書 (http://www.fsf.org/licenses/) の条項に基づいて MySQL ソフトウェアをオープンソース製品として使用するか、MySQL AB から標準の商用ライセンスを購入できます。 ライセンスポリシーの詳細については、http://www.mysql.com/company/legal/licensing/ を参照してください。'), 
    (2, 'グループレプリケーション MySQL Group Replication (MGR) は、MySQL 公式が既存の Binlog レプリケーションフレームワーク上に、Paxos プロトコルに基づいて実装した分散レプリケーション形態です。 RDS MySQL クラスタシリーズインスタンスは、グループレプリケーションをサポートしています。 この記事では、レプリケーション方式をグループレプリケーションにする方法について説明します。 グループレプリケーションを使用した MySQL クラスタは、分散 Paxos プロトコルに基づいて自己管理でき、高いデータ信頼性とデータ整合性を備えています。 従来の主備レプリケーション方式と比較して、グループレプリケーションには、データの強整合性、データの強信頼性、グローバルトランザクションの強整合性という利点があります');
    
    INSERT INTO embed(doc_id, content) VALUES 
    (3, 'Microsoft SQL Server は、リレーショナルデータベース管理システム (RDBMS) です。 アプリケーションとツールは SQL Server インスタンスまたはデータベースに接続し、Transact-SQL (T-SQL) を使用して通信します。'), 
    (3, 'SQL Server 2022 (16.x) は以前のバージョンに基づいて構築されており、SQL Server を開発言語、データ型、ローカルまたはクラウド環境、オペレーティングシステムオプションを提供するプラットフォームに発展させることを目的としています。'), 
    (3, 'SQL Server はエンタープライズレベルのアプリケーションで広く使用されており、Excel や Power BI などの他の Microsoft 製品とシームレスに統合して、データ分析を容易にします');

マルチパスリコールを実行する

次の SQL 文を実行して、PostgreSQL の紹介 というクエリテキストを複数の方法で取得し、関連ドキュメントを類似度でソートします。

-- クエリ対象のテキスト。
WITH query AS (
    SELECT 'PostgreSQL の紹介' AS query_text
),
-- 質問を埋め込みに変換します。 sk-**** を Alibaba Cloud ModelScope から取得した API キーに置き換えます。
query_embedding AS (
    SELECT rds_embedding.get_embedding_by_model('dashscope', 'sk-****', query.query_text)::real[]::vector AS embedding
    FROM query
),
-- ドキュメントキーワードに基づいて検索を実行し、ts_rank を使用して結果をソートします。 類似度が高いほどスコアが高くなります。
first_method AS (
    SELECT 
        id, 
        title, 
        ts_rank(to_tsvector('jiebacfg', doc.key_word), 
                to_tsquery(replace(text(plainto_tsquery('jiebacfg', (SELECT query_text FROM query))), '&', '|'))) AS score, 
        'doc_key_word' AS method
    FROM doc
    WHERE 
        to_tsvector('jiebacfg', doc.key_word) @@ 
        to_tsquery(replace(text(plainto_tsquery('jiebacfg', (SELECT query_text FROM query))), '&', '|'))
    ORDER BY 
        score DESC
    LIMIT 3
),
-- コンテンツキーワードに基づいて全文検索を実行し、RUM の <=> 演算子を使用して結果をソートします。 類似度が高いほどスコアが低くなります。
second_method AS (
    SELECT 
        id, 
        doc_id, 
        content, 
        to_tsvector('jiebacfg', content) <=> 
        to_tsquery(replace(text(plainto_tsquery('jiebacfg', (SELECT query_text FROM query))), '&', '|')) AS score,
        'content_key_word' AS method
    FROM embed
    WHERE 
        to_tsvector('jiebacfg', content) @@ 
        to_tsquery(replace(text(plainto_tsquery('jiebacfg', (SELECT query_text FROM query))), '&', '|'))
    ORDER BY 
        score 
    LIMIT 3
),
-- 埋め込みに基づいて全文検索を実行し、pgvector の <=> 演算子を使用して結果をソートします。 類似度が高いほどスコアが低くなります。
third_method AS (
    SELECT 
        embed.id, 
        embed.doc_id, 
        embed.content, 
        embedding <=> (SELECT embedding FROM query_embedding LIMIT 1) AS score, 
        'embedding' AS method
    FROM embed                 
    ORDER BY score
    LIMIT 3
)
-- 結合クエリを実行して、より多くのフィールド情報を取得します。
SELECT 
    first_method.title, 
    embed.id AS chunk_id, 
    SUBSTRING(embed.content FROM 1 FOR 30), 
    first_method.score, 
    first_method.method 
FROM first_method 
LEFT JOIN embed ON first_method.id = embed.doc_id
-- second_method フィールドの出力を結合します。
UNION
SELECT 
    doc.title, 
    second_method.id AS chunk_id, 
    SUBSTRING(second_method.content FROM 1 FOR 30), 
    second_method.score, 
    second_method.method 
FROM second_method 
LEFT JOIN doc ON second_method.doc_id = doc.id
-- third_method フィールドの出力を結合します。
UNION
SELECT 
    doc.title, 
    third_method.id AS chunk_id, 
    SUBSTRING(third_method.content FROM 1 FOR 30), 
    third_method.score, 
    third_method.method 
FROM third_method 
LEFT JOIN doc ON third_method.doc_id = doc.id
ORDER BY method, score;

出力:

     title      | chunk_id |                          substring                           |        score         |      method      
----------------+----------+--------------------------------------------------------------+----------------------+------------------
 PostgreSQL紹介 |        3 | PostgreSQLは、最初のバークレーコードのオープンソースの後継です。 |   13.159472465515137 | content_key_word
 PostgreSQL紹介 |        2 | PostgreSQLは、カリフォルニア大学バークレー校のコンピュータサイ |     16.4493408203125 | content_key_word
 PostgreSQL紹介 |        4 | また、自由なライセンスにより、誰でも私用、商用、学術研究のい |     16.4493408203125 | content_key_word
 PostgreSQL紹介 |        6 | 豊富なエコシステム: PostGIS (地理情報処理)、TimescaleDB  | 0.020264236256480217 | doc_key_word
 PostgreSQL紹介 |        5 | Ganos プラグインと PostGIS プラグインは、同じスキーマにインス | 0.020264236256480217 | doc_key_word
 PostgreSQL紹介 |        3 | PostgreSQLは、最初のバークレーコードのオープンソースの後継です。 | 0.020264236256480217 | doc_key_word
 PostgreSQL紹介 |        2 | PostgreSQLは、カリフォルニア大学バークレー校のコンピュータサイ | 0.020264236256480217 | doc_key_word
 PostgreSQL紹介 |        4 | また、自由なライセンスにより、誰でも私用、商用、学術研究のい | 0.020264236256480217 | doc_key_word
 PostgreSQL紹介 |        2 | PostgreSQLは、カリフォルニア大学バークレー校のコンピュータサイ |   0.2546271233144539 | embedding
 PostgreSQL紹介 |        3 | PostgreSQLは、最初のバークレーコードのオープンソースの後継です。 |  0.28679098231865074 | embedding
 PostgreSQL紹介 |        6 | 豊富なエコシステム: PostGIS (地理情報処理)、TimescaleDB  |  0.41783296077761967 | embedding

関連情報

RAG における ApsaraDB RDS for PostgreSQL のベストプラクティスの詳細については、以下のトピックをご参照ください。