Configuring external storage
============================

AIDBパイプラインは、2種類のデータソースから読み取ることができます。

- **Postgresテーブル** — ``aidb.create_pipeline()`` の\ ``source``
  パラメーターを使用して、名前で直接テーブルを参照します。 :ref:`Creating pipelines <Creating pipelines>` 
  を参照してください。

- **外部ストレージボリューム** — S3互換オブジェクトストア、Google Cloud
  Storage、Azure、またはローカルファイルシステムをPGFSを介して接続します。このページの残りの部分では、これを設定する方法について説明します。

外部ストレージは、
PostgresファイルシステムPGFS拡張機能を介してアクセスされます。これは、外部ストレージを保存場所としてPostgresにマップします。
AIDBは、各保存場所を名前でパイプライン参照する *ボリューム*
でラップします。ボリュームは `foreign table <https://www.postgresql.org/docs/current/sql-createforeigntable.html>`_ であるため、標準のSQLでオブジェクトをリスト、読み取り、書き込み、および削除できます。

その仕組み
----------

外部ストレージをAIDBパイプラインに接続することには、2つのオブジェクトが関係します。

- **PGFSストレージ場所** —
  外部ストレージプロバイダーのURI、資格情報、および接続オプションを定義します。
  :ref:`pgfs.create_storage_location() <Pipelines API reference>`  で作成されました。

- **AIDBボリューム** —
  PGFSストレージ場所のコンテンツを行として公開する外部テーブル。データフォーマット\ ``Text``
  、\ ``Image`` 、\ ``Pdf`` とオプションのサブパスを保存します。
  ``aidb.create_volume()`` で作成されました。

ボリュームが存在したら、 Postgresテーブルとまったく同じように、
``aidb.create_pipeline()`` の\ ``source`` として参照するか、
SQLで直接照会します。

!!!note
ストレージの場所を作成する前に、PGFS拡張機能をインストールする必要があります。
:ref:`Configuring AIDB <Configuring AIDB>` を参照してください。

ステップ1保存場所を作成する
---------------------------

``pgfs.create_storage_location()``
を使用して、外部ストレージへの接続を定義します。 ``url``
パラメーターは、ストレージバックエンドとパスを識別します。 ``options``
JSONBオブジェクトは、リージョンなどのプロバイダー固有の設定を保持します。
``credentials``
JSONBオブジェクトは、アクセスキーなどの認証シークレットを伝送します。

!!!note ``credentials``
パラメーターの明示的な資格情報は、認証の唯一の方法ではありません。これらを省略すると、S3、Azure、およびGCSストレージの場所は、各クラウドプロバイダーの独自のネイティブ資格情報解決IAMロール、管理対象/ワークロードID、インスタンスメタデータ、アプリケーションのデフォルト資格情報にフォールバックします。Postgresが既にクラウドで実行されている場合に役立ちますIDがアタッチされているため、保存するシークレットはまったくありません。詳細は、
:ref:`PGFS documentation </pg_extensions/pgfs/>` を参照してください。

S3互換オブジェクトストア
^^^^^^^^^^^^^^^^^^^^^^^^

.. code:: sql

   - - Private S3 bucket with credentials
   SELECT pgfs.create_storage_location(
       name        => my_s3_location,
       url         => s3://my-bucket/my-folder,
       options     => {"region": "us-east-1"},
       credentials => {"access_key_id": "<key>", "secret_access_key": "<secret>"}
       -- or omit the credentials argument to use the cloud providers native credential chain (IAM role, managed identity, etc.) instead
   );

   - - Public S3 bucket (no credentials required)
   SELECT pgfs.create_storage_location(
       name    => my_public_bucket,
       url     => s3://aidb-rag-app,
       options => {"region": "eu-central-1", "skip_signature": "true"}
   );

ローカルファイルシステム
^^^^^^^^^^^^^^^^^^^^^^^^

ローカルファイルシステムアクセスの場合、保存場所を作成する前に\ ``postgresql.conf``
で許可されるベースパスを宣言します。
PGFSは、セキュリティのためにこれらのパスへのアクセスを制限します。

.. code:: ini


   #  postgresql.conf

   pgfs.allowed_local_fs_paths = /tmp/pgfs

Postgresを再起動した後、\ ``file://``
URIを使用して保存場所を作成します。

.. code:: sql

   SELECT pgfs.create_storage_location(
       name => local_tmp_pgfs,
       url  => file:///tmp/pgfs/
   );

S3、GCS、およびAzureのストレージ場所オプションの詳細については、
:ref:`PGFS documentation </pg_extensions/pgfs/>`  を参照してください。

!!!注 オブジェクトストアへの外向きの制限
PGFSは、ストレージの場所へのアクセス時にPGFSが到達できるホストを制限するオプションのアウトバウンドホワイトリスト\ ``pgfs.egress_allowlist``
、共有フォールバックとして\ ``edb.egress_allowlist``
をサポートします。これは、AIDBのモデルプロバイダートラフィックの許可リストとは無関係です。両方を一緒に構成できます。
:ref:`PGFS — Network egress </pg_extensions/pgfs/configuring#network-egress>` および :ref:`AIDB — Network egress <Configuring AIDB>` を参照してください。

ステップ2ボリュームを作成する
-----------------------------

``aidb.create_volume()``
を使用して、PGFS記憶場所をAIDBに公開する外部テーブルを作成します。ボリューム名は、パイプラインとSQLクエリーで参照する外部テーブルの名前です。

.. code:: sql

   SELECT aidb.create_volume(
       name        => my_volume,
       server_name => my_s3_location,
       path        => /,
       data_format => Text
   );

パラメーター

.. csv-table::
  :header: Parameter,Description
  :widths: 10,30
  :align: left
  :class: longtable

  `name`,ボリュームの一意の名前。有効な引用符なしのPostgreSQL識別子である必要があります小文字、文字またはアンダースコアで始まり、文字、数字、アンダースコアのみが含まれます-ダッシュやスペースは含まれません。外部テーブル名として使用されます。
  `server_name`,アタッチするPGFSストレージ場所の名前。
  `path`,保存場所内のオプションのサブパス。以下の :ref:`パス処理<パス処理>` を参照してください。
  `data_format`,このボリュームのデータの種類。 `Text`、`Image`、または`Pdf`のいずれか。パイプラインはこれを使用して、正しい解析ステップを選択します。

!!!note ``data_format``
はメタデータです。オブジェクトを処理する方法をAIDBに指示しますが、フィルタリングはしません。ボリュームには、宣言されたフォーマットのオブジェクトのみが含まれていることを確認します。

パス処理
^^^^^^^^

``path``
引数は、作成時に正規化されます。先頭と後続のスラッシュが削除され、後続のスラッシュが1つだけ追加されます。これは、次のすべてが\ ``foo/``
として保存されることを意味します。

- ``foo``

- ``/foo``

- ``foo/``

- ``/foo/``

``NULL`` または\ ``/`` を渡すと、\ ``/``
として保存されます。これは、ストレージの場所のルートをターゲットとします。正規値とは、\ ``aidb.volumes``
で表示されるもの、およびオブジェクトキーの計算に使用されるものです。

例S3のPDF
^^^^^^^^^

.. code:: sql

   SELECT pgfs.create_storage_location(
       pdf_bucket,
       s3://my-docs-bucket,
       options     => {"region": "us-east-1"},
       credentials => {"access_key_id": "<key>", "secret_access_key": "<secret>"}
       -- or omit the credentials argument to use the cloud providers native credential chain instead
   );

   SELECT aidb.create_volume(pdf_volume, pdf_bucket, /, Pdf);

例ローカルディレクトリ内の画像
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code:: sql

   SELECT pgfs.create_storage_location(local_tmp_pgfs, file:///tmp/pgfs/);

   SELECT aidb.create_volume(ocr_input_volume, local_tmp_pgfs, ocr_input/, Image);

ステップ3ボリュームをパイプラインソースとして使用する
-----------------------------------------------------

``aidb.create_pipeline()`` の\ ``source``
パラメーターをボリューム名に設定します。ボリュームソースは、パイプラインの観点からテーブルソースと同じように動作します。

.. code:: sql

   SELECT aidb.create_pipeline(
       name       => my_pdf_pipeline,
       source     => pdf_volume,
       step_1     => ParsePdf,
       step_2     => ChunkText,
       step_3     => KnowledgeBase,
       step_3_options => aidb.knowledge_base_config(bert_local, Text)
   );

完全なウォークスルーについては、 :ref:`Create a pipeline <Creating pipelines>` を参照してください。

ボリュームの管理
----------------

ボリュームのリスト
^^^^^^^^^^^^^^^^^^

``aidb.volumes`` ビューを介してすべてのボリュームをリストします。

.. code:: sql

   SELECT * FROM aidb.volumes;
   __OUTPUT__
    schema |    volume    | storage_location |    path
   - -------+--------------+------------------+---------------
    public | pdf_volume   | pdf_bucket       | /
    public | text_bucket  | text_bucket      | aidb-rag-app/
   (2 rows)

ビューは、\ ``schema`` 、\ ``volume`` 、\ ``storage_location``
、および\ ``path`` 正規化された4つの列を結果ます。

ボリュームの削除
^^^^^^^^^^^^^^^^

.. code:: sql

   SELECT aidb.delete_volume(my_volume);

!!!note
PGFSストレージ場所を削除すると、その上に構築されたすべてのボリュームも削除されます。

SQLを使用してボリュームコンテンツにアクセスする
-----------------------------------------------

ボリュームはPGFSによってバッキングされる外部テーブルであるため、ストレージ場所のオブジェクトは行として公開されます。列は次のとおりです。

.. csv-table::
  :header: Column,Type,Description
  :widths: 12,15,25
  :align: left
  :class: longtable

  `key`,TEXT,ボリュームの`path`を基準としたオブジェクトキーファイルパス。
  `size`,BIGINT,バイト単位のオブジェクトサイズ。
  `last_modified`,TIMESTAMPTZ,ストレージバックエンドによって報告された最終変更タイムスタンプ。
  `e_tag`,TEXT,ストレージバックエンドによって報告されるエンティティタグETag利用可能な場合。
  `body`,BYTEA,オブジェクトの内容。クエリーに`WHERE key = '<exact-key>'`が含まれる場合にのみ入力されます。以下の注を参照してください。

!!!note ``body`` 列は、\ ``WHERE key = '...'``
で単一のキーでフィルタリングを選択した場合にのみ取得されます。キーフィルタなしで\ ``body``
を選択すると、 ``NULL``
が返されます。これは、ボリューム内のすべてのオブジェクトを誤ってダウンロードすることに対する安全対策です。

ボリューム内のオブジェクトのリスト
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code:: sql

   SELECT key, size, last_modified
   FROM my_volume
   ORDER BY key;
   __OUTPUT__
          key              | size |       last_modified
   - -----------------------+------+------------------------
    Test 1.html            | 1093 | 2026-05-14 15:49:32+00
    Test 2.html            | 1563 | 2026-05-14 15:50:02+00
    Test 3.html            | 1395 | 2026-05-14 15:49:32+00
   (3 rows)

``LIMIT``
はストレージバックエンドにプッシュダウンされるため、大きなバケットを安全に覗き見できます。

.. code:: sql

   SELECT key, size FROM my_volume LIMIT 5;

単一オブジェクトの読み取り
^^^^^^^^^^^^^^^^^^^^^^^^^^

正確なキーをフィルタリングしてオブジェクト本体を取得します。

.. code:: sql

   - - Read a binary file as BYTEA
   SELECT body FROM my_volume WHERE key = report.pdf;

   - - Read a text file as text
   SELECT convert_from(body, utf8)
   FROM my_volume
   WHERE key = notes.txt;

オブジェクトの書き込み、上書き、および削除
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

ボリュームは、標準の\ ``INSERT`` 、\ ``UPDATE`` 、および\ ``DELETE``
をサポートしています。 ``body`` は\ ``BYTEA``
です。必要に応じてテキストをbyteaにキャストします。

.. code:: sql

   - - Upload a new object
   INSERT INTO my_volume (key, body)
   VALUES (hello.txt, Hello, world::bytea);

   - - Overwrite an existing object
   UPDATE my_volume
   SET body = Hello again::bytea
   WHERE key = hello.txt;

   - - Delete an object
   DELETE FROM my_volume WHERE key = hello.txt;

!!!note
オブジェクトストアの書き込みはトランザクションではありません。成功した\ ``INSERT``
、\ ``UPDATE`` 、または\ ``DELETE``
は、周囲のPostgreSQLトランザクションが中断してもロールバックされません。

キーの名前の変更\ ``UPDATE my_volume SET key = ...``
はサポートされていません。
