Examples
========

パイプラインは、 EDB Postgres
AIでAIワークフローを定義する主な方法です。各パイプラインは、データが線形に流れる1つ以上の連続したステップで構成されています。ステップ1の出力はステップ2の入力などになります。

パイプラインの作成テーブルソース
--------------------------------

標準のPostgresテーブルをデータソースとして使用してパイプラインを作成するには、
``aidb.create_pipeline()``
ファンクションを使用します。次の例は、シングルステップとマルチステップのパイプラインの両方をセットアップする方法を示しています。

シングルステップパイプライン
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

この例では、
Postgresテーブルからナレッジベースを作成します。パイプラインを実行した後、セマンティック検索のために結果の埋め込みを照会できます。

.. code:: sql

   SELECT aidb.create_pipeline(
     name => kb_pipeline_table,
     source => source_table,
     source_key_column => id,
     source_data_column => content,
     step_1 => KnowledgeBase,
     step_1_options => aidb.knowledge_base_config(
        model => bert,  -- this is a pre-defined locally running model
        data_format => Text
      )
   );

マルチステップパイプライン
^^^^^^^^^^^^^^^^^^^^^^^^^^

複数の操作を連鎖させることができます。この例では、最初にHTMLを解析し、結果のテキストをチャンクに分割します。

.. code:: sql

   SELECT aidb.create_pipeline(
      name => html_processing_pipeline,
      source => web_data_table,
      source_key_column => id,
      source_data_column => html_content,
      step_1 => ParseHtml,
      step_2 => ChunkText
   );

パイプラインの作成 ボリュームソース
-----------------------------------

データが外部ストレージS3バケットなどにある場合、最初にストレージの場所とボリュームを定義する必要があります。

ステップ1ストレージとボリュームを定義する
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

PGFSストレージの場所とAIDBボリュームを作成します。

.. code:: sql

   SELECT pgfs.create_storage_location(s3_bucket_location, s3://my-ai-data,
       options => {"region": "us-east-1", "skip_signature": "true"}
   );
   SELECT aidb.create_volume(source_volume, s3_bucket_location, /, Text);

ステップ2パイプラインを作成する
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code:: sql

   SELECT aidb.create_pipeline(
      name => pipeline_from_s3,
      source => source_volume,
      step_1 => KnowledgeBase,
      step_1_options => aidb.knowledge_base_config(
        model => dummy,
        data_format => Text
      )
   );

パイプラインの実行と更新
------------------------

パイプラインは、作成時にデフォルトで無効になっています。それらは手動でトリガーするか、自動処理を有効にすることができます。

手動実行
^^^^^^^^

既存のすべてのデータに対してパイプラインを1回実行します。

.. code:: sql

   SELECT aidb.run_pipeline(kb_pipeline_table);

自動処理を有効にする
^^^^^^^^^^^^^^^^^^^^

ソースデータの変更に応じてパイプラインを最新の状態に保ちます。

.. code:: sql

   SELECT aidb.update_pipeline(
     name => kb_pipeline_table,
     auto_processing => Live
   );

モニタリングと削除
------------------

既存のパイプラインとその構成を表示するには、 ``aidb.pipelines``
ビューを照会します。

.. code:: sql

   SELECT * FROM aidb.pipelines;
   __OUTPUT__
         name      | source_type | source_schema |       source       | source_key_column | source_data_column | destination_type | destination_schema |       destination       | destination_key_column | destination_data_column |                                                 steps                                                  | auto_processing | batch_size | background_sync_interval |              owner_role             
   - ---------------+-------------+---------------+--------------------+-------------------+--------------------+------------------+--------------------+-------------------------+------------------------+-------------------------+--------------------------------------------------------------------------------------------------------+-----------------+------------+--------------------------+--------------------------------------
    pipeline__8989 | Table       | public        | source_table__8989 | id                | content            | Table            | public             | pipeline_pipeline__8989 | source_id              | value                   | [{"options": {"max_length": null, "desired_length": 1000}, "operation": "ChunkText", "step_order": 1}] | Live            |         42 | @ 42 mins                | role_pipeline_management_single_step
   (1 row)

.. code:: sql

   SELECT name, source, auto_processing FROM aidb.pipelines;
   __OUTPUT__
         name      |       source       | auto_processing
   - ---------------+--------------------+-----------------
    pipeline__8989 | source_table__8989 | Live
   (1 row)

パイプラインを削除すると、パイプラインステップによって生成された宛先テーブルもドロップします。パイプラインを削除するには

.. code:: sql

   SELECT aidb.delete_pipeline(kb_pipeline_table);

エンドツーエンドの例RAGのナレッジベース
---------------------------------------

この例では、内部サポートナレッジベースを介して、完全にSQLで完全にローカルな、完全な検索拡張世代RAGフローを構築します。そして、
**世代**
モデルは、取得された記事に基づいて回答を合成します。この例の縮小バージョンは、
:ref:`AI pipelines landing page <./>`  にあります。

ステップ1モデルを登録する
^^^^^^^^^^^^^^^^^^^^^^^^^

各ステージでは、異なる種類のモデルを使用します。埋め込みモデル
``bge-small-en-v1.5-f16``
は、AIDBインストールのたびに事前登録されるため、リランキングモデルと生成モデルのみが登録が必要です。
``aidb.create_model()`` は、Hugging
Faceから各GGUFファイルをダウンロードして検証しますリランカーは〜420
MB、Llama-3.2-3B〜3.4 GBです。 ``revision``
ピンにより、例が再現可能になります。それらがないと、モデルリポジトリの変更可能な\ ``main``
ブランチが使用されます。

.. code:: sql

   - - Reranking model (cross-encoder)
   SELECT aidb.create_model(
       name     => bge-reranker-v2-m3-Q4,
       provider => llamacpp_reranking,
       config   => jsonb_build_object(
           model,      gpustack/bge-reranker-v2-m3-GGUF,
           model_file, bge-reranker-v2-m3-Q4_K_M.gguf,
           revision,   3093af03b1a635e67b084b1d8c03c5f5e020fd05,
           n_ctx,      2048
       )
   );

   - - Generation model (instruct LLM)
   SELECT aidb.create_model(
       name     => llama-3.2-3b-instruct-Q8_0,
       provider => llamacpp_generate,
       config   => jsonb_build_object(
           model,       unsloth/Llama-3.2-3B-Instruct-GGUF,
           model_file,  Llama-3.2-3B-Instruct-Q8_0.gguf,
           revision,    e7d0997e49c9cb00d88b4c1a6a16aa894b0bbc31,
           n_ctx,       8192,
           temperature, 0.0
       )
   );

!!!note 生成ステージのモデルサイジング
1Bクラス生成モデル事前登録された\ ``llama-3.2-1b-instruct-Q8_0``
を含むは、この例の生成ステージでは信頼できません。テストでは、質問のコンストレインと矛盾するアクションを推奨しました。
Llama-3.2- **3B** -指示は正しく回答し、まだ控えめなローカルモデルです。

ステップ2ソースデータを作成する
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

データベース操作に関する16の短いサポート記事。いくつかはボキャブラリーディスク領域、バキューム、バックアップを意図的に共有します。これが、後の再ランキング段階が目に見えて重要になるものです。

.. code:: sql

   CREATE TABLE support_articles (
       id    INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
       title TEXT NOT NULL,
       body  TEXT NOT NULL
   );

   INSERT INTO support_articles (title, body) VALUES
   (Reclaiming disk space with VACUUM FULL,
    VACUUM FULL rewrites a table into a new file and returns unused disk space to the operating system. It takes an ACCESS EXCLUSIVE lock, so all reads and writes to the table are blocked until it completes.),
   (Reducing table bloat without downtime,
    The pg_repack extension rebuilds bloated tables and indexes online. It holds only brief locks, so applications can continue reading and writing while space is reclaimed. It requires free disk space roughly equal to the table size.),
   (Monitoring database disk usage,
    Use pg_database_size() and pg_total_relation_size() to track how much disk space databases and tables occupy. Configure alerts well before storage volumes reach capacity.),
   (Resolving "too many connections" errors,
    The error "FATAL: sorry, too many clients already" means the max_connections limit is reached. Find idle sessions in pg_stat_activity and terminate them with pg_terminate_backend(), or introduce a connection pooler.),
   (Connection pooling with PgBouncer,
    PgBouncer multiplexes thousands of client connections onto a small pool of database sessions. Transaction pooling mode provides the highest connection density for typical web application workloads.),
   (Diagnosing streaming replication lag,
    Compare pg_current_wal_lsn() on the primary with pg_last_wal_replay_lsn() on the standby to measure replication lag. Common causes include network saturation and long-running queries on the standby holding back WAL replay.),
   (Creating a hot standby with pg_basebackup,
    Run pg_basebackup to clone the primary server, then start the clone with a standby.signal file. The standby serves read-only queries while continuously replaying WAL from the primary.),
   (Replicating selected tables with logical replication,
    Logical replication publishes row changes for selected tables to subscriber databases and keeps them continuously synchronized. Unlike streaming replication, it can replicate a subset of tables and works across major versions.),
   (Point-in-time recovery with WAL archiving,
    With continuous WAL archiving enabled, you can restore a base backup and set recovery_target_time to roll the database forward to a specific moment, such as just before an accidental data deletion.),
   (Logical backups with pg_dump,
    pg_dump exports a database or single tables to a portable archive that can be restored into newer PostgreSQL versions. Dumps are consistent snapshots but offer no incremental or point-in-time capability.),
   (Reading query plans with EXPLAIN ANALYZE,
    EXPLAIN ANALYZE executes a query and reports the actual time spent in each plan node. Look for row-estimate mismatches and sequential scans on large tables to find missing indexes.),
   (Finding and removing unused indexes,
    Query pg_stat_user_indexes for indexes with zero scans. Unused indexes slow down every write and consume disk space; dropping them is a safe, immediate win.),
   (Tuning work_mem for large sorts,
    When sorts or hash joins exceed work_mem, they spill to temporary files on disk and slow down dramatically. Raise work_mem session-locally for reporting queries rather than globally.),
   (Restricting data access with row-level security,
    Row-level security policies filter which rows each role can see or modify. Policies are enforced by the server itself, so they apply uniformly to every client and application.),
   (Auditing database activity with pgaudit,
    The pgaudit extension produces detailed audit logs of reads, writes, and DDL for compliance requirements. Configure log classes narrowly to control log volume.),
   (Upgrading major versions with pg_upgrade,
    pg_upgrade migrates a cluster to a new major version by relinking data files instead of dumping and reloading. With the --link option, downtime is typically minutes even for large clusters.);

ステップ3ナレッジベースパイプラインを作成して実行する
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code:: sql

   SELECT aidb.create_pipeline(
       name               => support_kb,
       source             => support_articles,
       source_key_column  => id,
       source_data_column => body,
       step_1             => KnowledgeBase,
       step_1_options     => aidb.knowledge_base_config(
           model       => bge-small-en-v1.5-f16,
           data_format => Text
       ),
       auto_processing    => Disabled
   );

   SELECT aidb.run_pipeline(support_kb);

ステップ4取得
^^^^^^^^^^^^^

セマンティック検索は、クエリが共有するキーワードがほとんどまたはまったくない場合でも、適切な記事を見つけます。生のエラーテキストを貼り付け、解像度を取得します。

.. code:: sql

   SELECT a.title, r.distance::numeric(5,3) AS distance
   FROM aidb.retrieve_key(support_kb,
           application logs show: FATAL: sorry, too many clients already, 3) r
   JOIN support_articles a ON a.id = r.key::int
   ORDER BY r.distance;
   __OUTPUT__
                     title                  | distance
   - ----------------------------------------+----------
    Resolving "too many connections" errors |    0.507
    Tuning work_mem for large sorts         |    0.844
    Connection pooling with PgBouncer       |    0.908
   (3 rows)

または、回答と共通のツール名またはキーワードを持たない症状を説明します。

.. code:: sql

   SELECT a.title, r.distance::numeric(5,3) AS distance
   FROM aidb.retrieve_key(support_kb,
           A developer accidentally deleted rows from a table yesterday. How do we get the data back?, 3) r
   JOIN support_articles a ON a.id = r.key::int
   ORDER BY r.distance;
   __OUTPUT__
                      title                   | distance
   - ------------------------------------------+----------
    Point-in-time recovery with WAL archiving |    0.795
    Reducing table bloat without downtime     |    0.806
    Finding and removing unused indexes       |    0.846
   (3 rows)

``aidb.retrieve_text()``
は、結合を必要とせずに、記事本文を直接返します。出力テーブルでタイトルが読みやすいため、結合バリアントが表示されています。

ステップ5:再ランキング
^^^^^^^^^^^^^^^^^^^^^^

デモの質問
*「データベースのディスク領域が不足していますが、アプリケーションをオフラインにして修正することはできません。」*

ベクトル検索だけでは、 *ポイントインタイムリカバリ*
—ディスク領域の問題には明らかに役に立たない—が1位にランクされ、正しい記事
*pg_repack* がほぼ同点で2位です。

.. code:: sql

   SELECT a.title, r.distance::numeric(5,3) AS distance
   FROM aidb.retrieve_key(support_kb,
           The database is running out of disk space, but we cannot take the application offline to fix it., 5) r
   JOIN support_articles a ON a.id = r.key::int
   ORDER BY r.distance;
   __OUTPUT__
                      title                   | distance
   - ------------------------------------------+----------
    Point-in-time recovery with WAL archiving |    0.808   ← wrong
    Reducing table bloat without downtime     |    0.838   ← correct answer, near-tie
    Tuning work_mem for large sorts           |    0.851
    Monitoring database disk usage            |    0.865
    Resolving "too many connections" errors   |    0.883
   (5 rows)

クロスエンコーダーは、質問と各記事を一緒に読み取り、思い切って再注文します。
``aidb.rerank_text()`` は\ ``(text, logit_score, id)``
を返します。ここで、 ``id``
は、入力配列内の0ベースの位置であり、より高い\ ``logit_score``
ほど関連性が高いことを意味します。 ``id + 1``
は、そのインデックスを1ベースのSQL配列にマップします。

.. code:: sql

   WITH candidates AS (
       SELECT array_agg(a.title ORDER BY r.distance) AS titles,
              array_agg(a.body  ORDER BY r.distance) AS bodies
       FROM aidb.retrieve_key(support_kb,
               The database is running out of disk space, but we cannot take the application offline to fix it., 5) r
       JOIN support_articles a ON a.id = r.key::int
   )
   SELECT c.titles[r.id + 1] AS title, r.logit_score::numeric(7,3) AS logit_score
   FROM candidates c,
        aidb.rerank_text(bge-reranker-v2-m3-Q4,
               The database is running out of disk space, but we cannot take the application offline to fix it.,
               c.bodies) r
   ORDER BY r.logit_score DESC;
   __OUTPUT__
                      title                   | logit_score
   - ------------------------------------------+-------------
    Reducing table bloat without downtime     |      -2.742   ← promoted to #1, clear margin
    Monitoring database disk usage            |      -3.116
    Point-in-time recovery with WAL archiving |      -7.037   ← demoted
    Tuning work_mem for large sorts           |      -8.836
    Resolving "too many connections" errors   |      -9.216
   (5 rows)

これは古典的な2段階の取得パターンです。ベクトルインデックスここでは5、運用環境では20〜100を使用して候補を安くオーバーフェッチし、より精度が高いがより高価なクロスエンコーダーに最終的な注文を選択させます。リランカーは、候補ごとに完全なモデルのフォワードパスを実行します。テーブル全体をリランクしないでください。

ステップ6生成
^^^^^^^^^^^^^

1つのステートメントで完全なRAG。5つの候補を取得し、再ランク付けしてベスト3を維持し、根拠のある回答を生成します。最初の2つのCTEは、上記のステップ4およびステップ5コマンドとまったく同じです。
``\set``
はpsql機能です。他のクライアントでは、質問テキストを直接インラインします。

.. code:: sql

   \set question The database is running out of disk space, but we cannot take the application offline to fix it. What should we do?

   WITH candidates AS (
       -- Stage 1: vector search over the knowledge base (over-fetch 5 candidates)
       SELECT array_agg(a.title ORDER BY r.distance) AS titles,
              array_agg(a.body  ORDER BY r.distance) AS bodies
       FROM aidb.retrieve_key(support_kb, :question, 5) r
       JOIN support_articles a ON a.id = r.key::int
   ),
   reranked AS (
       -- Stage 2: cross-encoder reranking, keep the best 3
       SELECT c.titles[r.id + 1] AS title,
              c.bodies[r.id + 1] AS body,
              r.logit_score
       FROM candidates c,
            aidb.rerank_text(bge-reranker-v2-m3-Q4, :question, c.bodies) r
       ORDER BY r.logit_score DESC
       LIMIT 3
   ),
   context AS (
       SELECT string_agg(###  || title || E\n || body, E\n\n
                         ORDER BY logit_score DESC) AS articles
       FROM reranked
   )
   - - Stage 3: grounded answer generation
   SELECT aidb.generate_text(
       llama-3.2-3b-instruct-Q8_0,
       EKnowledge base articles:\n\n || context.articles ||
       E\n\nQuestion:  || :question ||
       E\n\nAnswer the question using only the facts in the articles above. Recommend one course of action and mention its caveats.,
       {
           "system_prompt": "You are a database support assistant. Be accurate and concise; do not invent facts that are not in the provided articles.",
           "max_tokens": 250,
           "temperature": 0.0
       }::json
   ) AS answer
   FROM context;

出力\ ``temperature: 0.0``
での決定性—繰り返し実行により同じ回答が生成されます。

::

   Based on the provided articles, I recommend using the `pg_repack` extension to reduce table
   bloat without downtime.

   According to the article, `pg_repack` rebuilds bloated tables and indexes online, holding only
   brief locks, allowing applications to continue reading and writing while space is reclaimed.
   This approach does not require taking the application offline.

   However, there is a caveat: `pg_repack` requires free disk space roughly equal to the table
   size. This means that you need to ensure there is sufficient free disk space available before
   running `pg_repack`, which may require some planning and preparation.

この回答を含む単一の記事はありません。モデルは、質問からの制約「オフラインにできない」を2つの競合する記事からの事実VACUUM
FULLブロックの読み取りと書き込み。pg_repackはオンラインで動作し、空きディスク領域の警告を引き継ぎました。
—逐語的な結果ではなく、合成。

同じステートメントは、ホストされたものを含む登録された世代モデルで動作します。モデル名のみが変更されます。ホストされたGPT-5.x推論モデルの注意事項が1つあります。推論構成から\ ``"temperature"``
を省略します。彼らはパラメーターを拒否します。

ステップ7:ティアダウン
^^^^^^^^^^^^^^^^^^^^^^

.. code:: sql

   SELECT aidb.delete_pipeline(support_kb);
   DROP TABLE support_articles;
   SELECT aidb.delete_model(llama-3.2-3b-instruct-Q8_0);
   SELECT aidb.delete_model(bge-reranker-v2-m3-Q4);

エンベディングモデルは削除されません。\ ``bge-small-en-v1.5-f16``
は、事前登録されたデフォルトの1つです。

エンドツーエンドの例 中間ストレージを使用したマルチステップパイプライン
-----------------------------------------------------------------------

このエンドツーエンドの例では、中間ストレージを利用するEDB Postgres
AIでマルチステップパイプラインを構成する方法を示します。

``intermediate_destination``
を定義することにより、個々のステップの結果テキストチャンクなどを次のステージ要約などに渡す前に永続化できます。これは、処理されたデータのデバッグまたは再利用に役立ちます。デフォルトではオフであり、ステップ構成ヘルパー\ ``aidb.chunk_text_config()``
などにはそのパラメーターがあります。以下の両方の例は、ヘルパー独自のオプションとともにプレーンなJSONとして追加します。クエリー時に\ ``deduplicate``
と相互作用する方法を含む完全なリファレンスについては、
:ref:`エンドツーエンドの例 中間ストレージを使用したマルチステップパイプライン <エンドツーエンドの例 中間ストレージを使用したマルチステップパイプライン>` を参照してください。

**この例の主な機能**

- **マルチステップワークフロー** ``ChunkText``
  ステップ1を\ ``SummarizeText`` ステップ2にチェーンします。

- **自動処理**
  新しいデータがソーステーブルに挿入されるたびに、パイプラインは自動的にトリガーされます。

- **中間ストレージ**
  中間テーブルを明示的に名前付ける方法と、システムに中間テーブルを自動生成させる方法を示します。

例1名前付けた中間宛先
^^^^^^^^^^^^^^^^^^^^^

このシナリオでは、チャンクステップの出力を保存するテーブルに手動で名前を付けます。

- 生テキストのソーステーブルを作成します。

.. code:: sql

     CREATE TABLE source_table_demo(
       id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
       content TEXT NOT NULL
     );

- カスタム中間テーブルを使用してパイプラインを定義します。

.. code:: sql

     SELECT * from aidb.create_pipeline(
       name => complex_pipeline_v1,
       source => source_table_demo,
       source_key_column => id,
       source_data_column => content,
       auto_processing => Live,
       step_1 => ChunkText,
       step_1_options => jsonb_build_object(
           desired_length, 20,
           intermediate_destination, jsonb_build_object(
               enabled, true,
               destination, my_custom_chunk_storage -- Explicitly named
           )
       ),
       step_2 => SummarizeText
     );

- 自動処理をトリガーするデータを挿入します。

.. code:: sql

     INSERT INTO source_table_demo (content)
     VALUES (This is a long text example that will be split into segments for easier processing.);

- チャンクと最終的なサマリーを表示します。

.. code:: sql

     -- View intermediate chunked output
     SELECT * FROM my_custom_chunk_storage;

     -- View the final summarized output
     SELECT * FROM pipeline_complex_pipeline_v1;

例2 自動中間宛先
^^^^^^^^^^^^^^^^

中間ストレージを有効にしても名前を指定しない場合、システムはパターン\ ``pipeline_[name]_step_[n]``
に従ってテーブルを生成します。

- 自動名前付けの中間ストレージを使用してパイプラインを作成します。

.. code:: sql

     SELECT * from aidb.create_pipeline(
       name => auto_named_pipeline,
       source => source_table_demo_2,
       source_key_column => id,
       source_data_column => content,
       auto_processing => Live,
       step_1 => ChunkText,
       step_1_options => jsonb_build_object(
           desired_length, 20,
           intermediate_destination, jsonb_build_object(enabled, true)
       ),
       step_2 => SummarizeText
     );

- 自動生成された中間テーブルにアクセスします。

.. code:: sql

     -- View intermediate chunked output (auto-generated table name)
     SELECT * FROM pipeline_auto_named_pipeline_step_1;

エンドツーエンドの例 スキャンされたPDFを検索可能なナレッジベースに
------------------------------------------------------------------

この例では、スキャンされたPDFドキュメントのコレクションをベクトル検索可能なナレッジベースに変換する完全なパイプラインを構築する方法を示します。
3つの連続したステップを使用します。

1. **PdfToImage** 各PDFページを画像としてレンダリングします。

2. **PerformOcr**
   OCRモデルを使用して、各レンダリング画像からテキストを抽出します。

3. **KnowledgeBase**
   抽出されたテキストを埋め込み、セマンティック検索のために保存します。

このパターンは、スキャンされた文書、テキストレイヤーのない古いPDF、および
**ParsePdf** が空または低品質のテキストを返すコンテンツに最適です。
中間ストレージを活用することで、ナレッジベースにフィードする前にOCR出力を検査し、データ品質を保証し、ワークフローの問題をデバッグできます。

前提条件
^^^^^^^^

登録されたNVIDIA NIM
PaddleOCRモデルと登録された埋め込みモデルが必要です。
これらをまだお持ちでない場合は、最初に登録します。

.. code:: sql

   - - Register the OCR model
   SELECT aidb.create_model(
       my_paddle_ocr_model,
       nim_paddle_ocr,
       credentials => {"api_key": "<NVIDIA_NIM_API_KEY>"}::JSONB  -- or credentials_env to read this from an environment variable instead
   );

埋め込みモデルbertはプリインストールされており、登録は必要ありません。別のモデルを使用している場合は、ここに登録します。

ステップ1ソーステーブルを作成する
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

生のPDFデータを保持するテーブルを作成します。

.. code:: sql

   CREATE TABLE scanned_pdfs (
       id      INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
       name    TEXT NOT NULL,
       pdf_data BYTEA NOT NULL
   );

ステップ2PDFをテーブルにロードする
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

PDFドキュメントをバイナリデータとして挿入します。次の例では、
``pg_read_binary_file()``
を使用してサーバーのファイルシステムからファイルをロードします。

.. code:: sql

   INSERT INTO scanned_pdfs (name, pdf_data)
   VALUES (quarterly_report.pdf, pg_read_binary_file(/path/to/quarterly_report.pdf));

S3互換ボリュームからPDFをロードすることもできます。
:ref:`Configuring external storage <Configuring external storage>` および :ref:`パイプラインの作成 ボリュームソース <パイプラインの作成 ボリュームソース>` を参照してください。

ステップ3パイプラインを作成する
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code:: sql

   SELECT aidb.create_pipeline(
       name               => scanned_pdf_kb,
       source             => scanned_pdfs,
       source_key_column  => id,
       source_data_column => pdf_data,
       step_1             => PdfToImage,
       step_1_options     => {"dpi": 150}::jsonb,
       step_2             => PerformOcr,
       step_2_options     => aidb.ocr_config(model => my_paddle_ocr_model),
       step_3             => KnowledgeBase,
       step_3_options     => aidb.knowledge_base_config(
           model             => bert,
           data_format       => Text,
           distance_operator => Cosine
       ),
       auto_processing    => Live
   );

``auto_processing`` を\ ``Live``
に設定すると、新しいPDFが\ ``scanned_pdfs``
テーブルに挿入されるたびに、パイプラインが自動的に実行されます。

ステップ4既存のデータでパイプラインを実行する
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

パイプラインを有効にする前に行を挿入した場合、ここで処理します。

.. code:: sql

   SELECT aidb.run_pipeline(scanned_pdf_kb);

ステップ5ナレッジベースを照会する
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

パイプラインが完了したら、セマンティック検索を使用して結果を照会します。

.. code:: sql

   SELECT * FROM aidb.retrieve_text(
       scanned_pdf_kb,
       quarterly revenue figures,
       5  -- return top 5 matches
   );

結果の各行は、PDFページから抽出されたテキストブロックに対応し、クエリーとの意味的な類似性によってランク付けされます。
