6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

OCI Data Catalog 第4回:Data LakeとADBのRDBMS、Vector Storeを統合し、Select AIとRAGでLakehouseを検索してみた

6
Last updated at Posted at 2026-08-17

説明絵.png

■ はじめに

こんにちは。

OCI Data Catalogシリーズとして、これまで次の内容を実施しました。

内容
第1回 Object Storage上のCSV、ParquetファイルをOCI Data Catalogへハーベスト
第2回 Oracle DatabaseマニュアルPDFと文書インベントリParquetを作成し、文書名、製品バージョン、公式URL、Object Storage上の保存場所などをカタログ化
第3回 Object Storage上のOracle AI Database 26aiマニュアルPDFからVector Indexを作成し、Select AI with RAGで検索
第4回 Data Lakeの文書インベントリ、ADBのRDBMS表、既存Vector Storeを統合し、LakehouseをSelect AIとRAGで検索

第2回では、Oracle Databaseマニュアルを管理するdocument_inventory.parquetを作成しました。

文書インベントリには、次のような構造化Metadataが格納されています。

document_id
document_family_id
product_name
product_version
document_title
document_type
category
subcategory
language_code
document_number
publication_year
publication_month
official_url
object_name
rag_enabled
document_priority
data_owner
tags
bucket_name
object_uri

第3回では、Object Storage上の4つのOracle AI Database 26aiマニュアルをAutonomous AI Databaseへ取り込み、9,590件のチャンクとEmbeddingを持つVector Storeを作成しました。

ただし、ここまでの構成では、次のデータがそれぞれ別の用途で利用されています。

OCI Data Catalog/Data Lake
  → 文書名、製品バージョン、カテゴリ、公式URLなどを管理

ADBのRDBMS表
  → AI利用の承認状態、機密区分、レビュー担当などを管理

Vector Store
  → PDF本文のチャンクとEmbeddingを管理

今回は、OCI Data Catalogから同期したData Lakeの外部表と、Autonomous AI Database内のRDBMS表をJOINします。

さらに、第3回で作成したVector Storeのlocation_uriobject_nameから完全なObject名を再構成し、文書インベントリのobject_nameと結び付けます。これにより、構造化MetadataとPDF本文のチャンクを同じAutonomous AI Database上で参照できるLakehouseを構築します。

そのうえで、次の2つの検索経路を確認します。

  • Data Lake外部表とADB内部表をJOINしたViewを、Select AIのNL2SQLで検索
  • 既存Vector Indexを、Select AI with RAGで検索

ということで今回は、第1回から第3回までに作成したData Lake、RDBMS、Vector Storeを再利用し、Select AIとRAGから検索できるAutonomous AI Database上のLakehouseを構築してみてみます。

■ Agenda

大項目 内容
:white_check_mark: 今回のゴール Data Lake、RDBMS、Vector Storeの3レイヤーと、今回作成するObject・Profileの役割を整理
:white_check_mark: 今回の重要な設計ポイント NL2SQLとRAGを分ける理由、3レイヤーをOracle SQLで統合する考え方を整理
:white_check_mark: 今回の構成 OCI Data Catalog、Object Storage、ADB、Vector Store、Select AIの全体構成を確認
:white_check_mark: 使用するリソース Bucket、Database User、Vector Index、Profile、Viewなど今回使用するリソースを確認
:white_check_mark: 事前準備 第2回の文書インベントリ、第3回のVector StoreとRAG Profileを確認
:white_check_mark: 第2回で作成したLogical Entityを確認 document_inventory Logical EntityとParquet、20 Attributesを確認
:white_check_mark: OCI Data CatalogとAutonomous AI Databaseを同期 Resource Principal、Credential、Data Catalog接続を設定し、Logical EntityをADBへ同期
:white_check_mark: Data LakeのExternal Tableを確認 Data Catalog同期で生成されたSchemaとDOCUMENT_INVENTORY External Tableを確認
:white_check_mark: Data Lake参照用Viewを作成 External Tableを安定した名前で参照するDOCUMENT_INVENTORY_EXT_Vを作成
:white_check_mark: ADBのRDBMS表を作成 AI利用承認、機密区分、レビュー状態を管理するDOCUMENT_GOVERNANCEを作成
:white_check_mark: Data Lake外部表とADB内部表をJOIN document_idで結合し、V_DOCUMENT_LAKEHOUSEを作成
:white_check_mark: Select AI向けにTableとColumnの意味を追加 Viewと主要Columnへコメントを設定し、NL2SQLで意味を理解しやすくする
:white_check_mark: Vector StoreとJOIN Vector Storeの完全Object名を再構成し、V_DOCUMENT_VECTOR_CHUNKSで3レイヤーを統合
:white_check_mark: Lakehouse検索用Select AI Profileを作成 V_DOCUMENT_LAKEHOUSEをNL2SQL対象とするOCI_DB_LAKEHOUSE_SQLを作成
:white_check_mark: Select AIでLakehouseを検索 SQL用Profileを明示し、SHOWSQL、SELECT AI、NARRATEで構造化データを検索
:white_check_mark: Database Actionsから実行する場合 DBMS_CLOUD_AI.GENERATEを使用したSHOWSQL、NARRATEの実行方法を確認
:white_check_mark: Select AI with RAGへ切り替える OCI_DB_MANUAL_RAGへ切り替え、PDF本文をSemantic Search+RAGで検索
:white_check_mark: 第4回で実現できた検索フロー 構造化検索から対象文書を選び、RAG検索へつなぐ一連の流れを整理
:white_check_mark: なぜ1つのProfileへすべて登録しないのか NL2SQL用ProfileとRAG用Profileを分離する理由と責任範囲を整理
:white_check_mark: 第4回で構築したLakehouse Data Lake+RDBMS+Vector Store+Generative AIを統合した構成を整理
:white_check_mark: 運用上の考慮点 Protected Schema、Object公開範囲、AI Providerへ送信されるデータなどを整理
:white_check_mark: トラブルシューティング DBMS_DCAT、Profile JSON、権限、JOIN、Profile切替などのエラー対処を整理
:white_check_mark: リソースを削除 Profile、View、RDBMS表を依存関係の逆順で削除
:white_check_mark: まとめ 第4回で構築・確認したLakehouseとSelect AI/RAGの内容を整理
:white_check_mark: 次回以降 AIDP Master Catalog、Private Agent Factory、APEXへの発展を整理
:white_check_mark: 参考資料 今回参照したOracle公式ドキュメント

■ 今回のゴール

今回のゴールを一言で表すと、次のとおりです。

Object Storageにある文書台帳、ADB内部の文書ガバナンス情報、PDF本文のVector Storeを、文書単位とチャンク単位の2段階で関連付け、構造化データ検索とRAG検索を用途に応じて使い分けられるLakehouseを作成します。

初見ではObject名が多く見えるため、最初に「どこに実データがあり、どのObjectがViewで、どのProfileが何を検索するのか」を整理します。

● 第4回で新しく作るものと再利用するもの

第4回では、1つのRDBMS表、3つのView、1つのSelect AI Profileを新しく作成します。

第3回で作成したVector TableとRAG Profileは、そのまま再利用します。

区分 Object 種類 作成元/用途
自動生成 DCAT$...DOCUMENT_INVENTORY External Table OCI Data CatalogのLogical EntityをADBへ同期すると作成されるData Lake参照用Table
新規作成 DOCUMENT_INVENTORY_EXT_V View 長いDCAT$...Schema名を隠し、文書インベントリを安定した名前で参照
新規作成 DOCUMENT_GOVERNANCE RDBMS Table AI利用承認、機密区分、レビュー担当、備考などを管理
新規作成 V_DOCUMENT_LAKEHOUSE View 文書インベントリとガバナンス表をdocument_idで統合
再利用 OCI_DB_MANUAL_IDX$VECTAB Vector Table 第3回で作成したPDF本文のチャンク、属性、Embeddingを保持
新規作成 V_DOCUMENT_VECTOR_CHUNKS View 文書単位のLakehouse情報とVector Storeの各チャンクを完全Object名で統合
新規作成 OCI_DB_LAKEHOUSE_SQL Select AI Profile V_DOCUMENT_LAKEHOUSEをNL2SQLで検索
再利用 OCI_DB_MANUAL_RAG Select AI RAG Profile OCI_DB_MANUAL_IDXを使用してPDF本文をSemantic Search

DOCUMENT_INVENTORY_EXT_VV_DOCUMENT_LAKEHOUSEV_DOCUMENT_VECTOR_CHUNKSはViewです。

Viewはデータを複製して保存するObjectではなく、参照時に元データを組み合わせて見せる論理レイヤーです。

● 各Objectが属するデータレイヤー

Object レイヤー データの粒度 主な内容 主な利用先
DOCUMENT_INVENTORY_EXT_V Data Lakeアクセスレイヤー 1行=1文書 文書ID、製品バージョン、文書名、カテゴリ、公式URL、Object名、RAG対象フラグ V_DOCUMENT_LAKEHOUSEの入力
DOCUMENT_GOVERNANCE ADB RDBMS/業務ガバナンスレイヤー 1行=1文書の審査状態 承認状態、AI利用可否、機密区分、レビュー担当、備考 V_DOCUMENT_LAKEHOUSEの入力
V_DOCUMENT_LAKEHOUSE 構造化Lakehouse統合/提供レイヤー 1行=1文書 Data Lakeの文書Metadata+ADBのガバナンス情報 OCI_DB_LAKEHOUSE_SQLによるNL2SQL
OCI_DB_MANUAL_IDX$VECTAB Vector Storeレイヤー 1行=1チャンク PDF本文チャンク、ATTRIBUTES JSON、Embedding OCI_DB_MANUAL_RAGによるSemantic Search
V_DOCUMENT_VECTOR_CHUNKS 文書+Vector統合/検証レイヤー 1行=1チャンク 文書Metadata+ガバナンス情報+PDF本文チャンク+Embedding+Source URL JOIN検証、監査、Custom SQL RAG、将来のAgent Tool

この構成では、データの粒度が途中で変わります。

DOCUMENT_INVENTORY_EXT_V
  1行 = 1文書
        │
        │ document_idでJOIN
        ▼
V_DOCUMENT_LAKEHOUSE
  1行 = 1文書
        │
        │ 完全Object名でVector StoreとJOIN
        ▼
V_DOCUMENT_VECTOR_CHUNKS
  1行 = 1チャンク

今回の検証では、文書インベントリは10文書です。そのうち第3回でVector化した26aiの4文書が、合計9,590チャンクとしてV_DOCUMENT_VECTOR_CHUNKSへ結び付きます。

● Object間の関係

次はER図に近い関係図です。

ただし、Vector Storeとの関係はDatabaseのForeign Keyではなく、Object Storage上の完全Object名を使用した論理JOINです。

JOIN Keyは2種類あります。

JOIN対象 JOIN Key 理由
DOCUMENT_INVENTORY_EXT_VDOCUMENT_GOVERNANCE document_id 文書単位の一意な業務キーとして使用
V_DOCUMENT_LAKEHOUSEOCI_DB_MANUAL_IDX$VECTAB 文書インベントリのobject_name=Vector Storeのlocation_uriobject_name Vector Storeには文書インベントリのdocument_idが自動保存されないため、PDF実体の完全Object名で対応付け

V_DOCUMENT_LAKEHOUSEは、文書一覧、承認状態、優先度などを検索するための文書単位のViewです。

V_DOCUMENT_VECTOR_CHUNKSは、文書情報と本文チャンクが正しく結び付いていることを確認するためのチャンク単位のViewです。

この2つは用途が異なります。

● Select AI Profileは「検索経路」を定義する

Select AI Profileはデータを保存するObjectではありません。

Select AIに対して、次の内容を定義する設定です。

どのProvider/Modelを使用するか
どのTable/ViewまたはVector Indexを検索対象にするか
NL2SQLとRAGのどちらの検索経路を使用するか
追加の指示や公開範囲をどうするか

今回は、質問の種類が異なるため、Profileを2つに分けます。

Profile 検索方式 検索対象 得意な質問
OCI_DB_LAKEHOUSE_SQL NL2SQL V_DOCUMENT_LAKEHOUSE 完全一致条件、一覧、集計、並べ替え、承認状態の確認 「26aiでAI利用が承認された文書を優先度順に表示」
OCI_DB_MANUAL_RAG Vector Search+RAG OCI_DB_MANUAL_IDXOCI_DB_MANUAL_IDX$VECTAB PDF本文の意味検索、要約、比較、手順や仕様の説明 「HNSW索引とIVF索引の違いを説明」

検索経路は次のようになります。

● Profileを1つにまとめない理由

Profileを分ける理由は、単に設定を整理するためではありません。

1) 検索方法が異なるため

構造化データは、APPROVAL_STATUS = 'APPROVED'のような正確な条件、集計、並べ替えをOracle SQLで処理するのが適しています。

PDF本文は、質問と意味が近いチャンクをEmbeddingで探すSemantic Searchが適しています。

2) Vector Tableを通常の業務表としてNL2SQLへ公開しないため

OCI_DB_MANUAL_IDX$VECTABには9,590件のチャンクとEmbeddingがあります。これをSQL用Profileのobject_listへ直接登録すると、Metadata量が増え、LLMが巨大なチャンク表やEmbedding列を通常の業務列として扱う可能性があります。

SQL用Profileには、文書単位に整理したV_DOCUMENT_LAKEHOUSEだけを公開します。

3) 公開範囲と責任範囲を明確にするため

OCI_DB_LAKEHOUSE_SQL
  → 文書Metadataとガバナンス情報だけを検索

OCI_DB_MANUAL_RAG
  → PDF本文だけをSemantic Search

どのProfileがどのデータへアクセスするかを限定することで、検索結果の意味と権限範囲を理解しやすくなります。

4) 標準のSelect AIでは1回の質問で2経路を自動統合しないため

SQL用ProfileのNARRATEはSQL結果を、RAG用ProfileのNARRATEはVector Searchで取得したチャンクをLLMへ渡します。

第4回では、人が次の順番でProfileを切り替えます。

1. OCI_DB_LAKEHOUSE_SQLで対象文書を特定
2. document_id、document_title、承認状態を確認
3. OCI_DB_MANUAL_RAGへ切り替え
4. 対象文書名を指定してPDF本文へ質問

この2つの検索経路を質問内容に応じて自動選択し、SQL結果とRAG結果をまとめる処理は、第5回以降のAI Agentで実装します。

V_DOCUMENT_VECTOR_CHUNKSはどのProfileで使うのか

V_DOCUMENT_VECTOR_CHUNKSは、今回の標準NL2SQL Profileや標準RAG Profileの直接の検索対象にはしません。

用途は次のとおりです。

Data Lake、RDBMS、Vector StoreのJOIN結果をSQLで検証
文書ごとのチャンク数やJOIN漏れを確認
承認状態と本文チャンクを同時に監査
Relational Filterを加えたCustom SQL RAG
Private Agent FactoryやSelect AI AgentのCustom Tool

標準RAGでは、OCI_DB_MANUAL_RAGがVector Indexを通じてOCI_DB_MANUAL_IDX$VECTABを検索します。

一方、V_DOCUMENT_VECTOR_CHUNKSは、将来のAgentやCustom SQL RAGから、ガバナンス条件を含めてチャンクを扱うための統合Viewとして残します。

● 第4回終了時の完成形

第4回の完了時点では、次の2種類の検索ができる状態になります。

構造化検索
  OCI_DB_LAKEHOUSE_SQL
    → V_DOCUMENT_LAKEHOUSE
    → 文書一覧、版、カテゴリ、承認状態、AI利用可否を検索

本文検索
  OCI_DB_MANUAL_RAG
    → OCI_DB_MANUAL_IDX$VECTAB
    → PDF本文をSemantic Searchし、Source付きで回答

さらに、V_DOCUMENT_VECTOR_CHUNKSを使用すると、Data Lake、RDBMS、Vector Storeが4文書、9,590チャンクで正しく結び付いていることをOracle SQLで確認できます。

SELECT AIは、現在のDatabase Sessionに設定されているProfileを使用します。

そのため、本稿ではProfileの取り違えを防ぐため、SELECT AI検索の直前にSET_PROFILEを実行し、GET_PROFILEで確認してから検索します。

DBMS_CLOUD_AI.GENERATEを使用する場合は、Sessionの状態へ依存しないように、毎回profile_nameを明示します。

■ 今回の重要な設計ポイント

● 標準のSELECT AI NARRATEはSQL結果かVector検索結果のどちらかを使用

Select AIのnarrateアクションは、自然言語の回答を生成するとき、LLMへ次のいずれかを渡します。

  • NL2SQLで実行したSQLの結果
  • Vector StoreからSemantic Searchで取得したチャンク

そのため、今回の第4回では、SQL検索とRAG検索のProfileを分け、順番に実行します。

1. Select AIで構造化データを検索
   ↓
2. 対象文書のdocument_id、document_titleを確認
   ↓
3. RAG Profileへ切り替え
   ↓
4. 対象文書の本文へ質問

1回の自然言語質問からSQL ToolとRAG Toolを自動選択し、両方の結果を統合する処理は、次回以降のAI Agentで実装します。

参考: About Select AI

● Data Lake、RDBMS、Vector StoreのJOIN自体はOracle SQLで実行できる

Select AIの標準RAGとは別に、Oracle SQLでは外部表、RDBMS表、Vector Tableを同じ問合せでJOINできます。

今回は、Vector StoreのATTRIBUTES.location_uriから製品バージョンを含むObject Prefixを取り出し、ATTRIBUTES.object_nameを連結して完全Object名を再構成します。その完全Object名を文書インベントリのobject_nameと結び付けます。

これにより、次の情報を1つのSQL結果として確認できます。

文書ID
製品バージョン
文書タイトル
カテゴリ
公式URL
AI利用承認状態
レビュー担当
PDF本文チャンク
Embedding
RAGのSource URL

Oracle AI Vector Searchでは、VectorデータとRelationalデータ、JSONなどを組み合わせたEnterprise RAGを構築できます。

参考: Use Retrieval Augmented Generation to Complement LLMs

■ 今回の構成

■ 使用するリソース

今回使用する主なリソースです。

項目 設定値
Object Storageリージョン ap-tokyo-1
Autonomous AI Databaseリージョン ap-tokyo-1
OCI Generative AIリージョン ap-osaka-1
Bucket oracle-database-doc-catalog
文書インベントリ catalog/document_inventory/current/document_inventory.parquet
PDF保存Prefix documents/oracle-database/26ai/
Database User RAG_USER
既存RAG Profile OCI_DB_MANUAL_RAG
既存Vector Index OCI_DB_MANUAL_IDX
既存Vector Table OCI_DB_MANUAL_IDX$VECTAB
新規RDBMS表 DOCUMENT_GOVERNANCE
Data Lake参照View DOCUMENT_INVENTORY_EXT_V
Lakehouse統合View V_DOCUMENT_LAKEHOUSE
Vector統合View V_DOCUMENT_VECTOR_CHUNKS
新規NL2SQL Profile OCI_DB_LAKEHOUSE_SQL
Chat Model cohere.command-a-03-2025
Embedding Model cohere.embed-v4.0
Embedding次元 1536

■ 事前準備

● 第2回の文書インベントリ

第2回で作成した文書インベントリには、Oracle Database 26ai、19c、12.2の合計10文書を登録しています。

Object Storage上の配置先です。

catalog/document_inventory/current/document_inventory.parquet

今回のVector Indexには、文書インベントリに登録した文書のうち、Oracle AI Database 26aiの次の4文書を登録しています。

document_id 文書
oracle_db_26ai_admin Database Administrator's Guide
oracle_db_26ai_ladbi Oracle AI Database Installation Guide for Linux
oracle_db_26ai_cncpt Database Concepts
oracle_db_26ai_vecse AI Vector Search User's Guide

● 第3回のVector Store

第3回で作成したVector Storeを残していることを確認します。

SQL01
SELECT
    index_name,
    status,
    description
FROM
    user_cloud_vector_indexes
WHERE
    index_name = 'OCI_DB_MANUAL_IDX';
SQL01:実行結果
INDEX_NAME           STATUS     DESCRIPTION
____________________ __________ __________________________________________________________
OCI_DB_MANUAL_IDX    ENABLED    Oracle Database 26ai manual PDF index for Select AI RAG
SQL
SELECT
    COUNT(*) AS chunk_count
FROM
    OCI_DB_MANUAL_IDX$VECTAB;
SQL02:実行結果
   CHUNK_COUNT
______________
          9590

第3回の検証では、4つのPDFから9,590件のチャンクが登録されました。

Vector Tableの構造です。

SQL
DESC OCI_DB_MANUAL_IDX$VECTAB
SQL実行結果
Name          Null?    Type
------------- -------- ----------------------
CONTENT                CLOB
ATTRIBUTES             JSON
EMBEDDING              VECTOR(1536,*,DENSE)

● 第3回のRAG Profileを確認

第4回では、第3回で作成したOCI_DB_MANUAL_RAGをそのまま再利用します。

SQL01
SELECT
    profile_name,
    status,
    description
FROM
    user_cloud_ai_profiles
WHERE
    profile_name = 'OCI_DB_MANUAL_RAG';
SQL01:実行結果
PROFILE_NAME         STATUS     DESCRIPTION
____________________ __________ ________________________________________________________________
OCI_DB_MANUAL_RAG    ENABLED    RAG profile for Oracle Database manuals in OCI Object Storage

RAGに関係する主なAttributeを確認します。

SQL
SELECT
    attribute_name,
    DBMS_LOB.SUBSTR(attribute_value, 500, 1) AS attribute_value
FROM
    user_cloud_ai_profile_attributes
WHERE
    profile_name = 'OCI_DB_MANUAL_RAG'
AND LOWER(attribute_name) IN (
    'model',
    'embedding_model',
    'vector_index_name',
    'enable_custom_source_uri'
)
ORDER BY
    attribute_name;
SQL2:実行結果
ATTRIBUTE_NAME              ATTRIBUTE_VALUE
___________________________ ___________________________
embedding_model             cohere.embed-v4.0
enable_custom_source_uri    true
model                       cohere.command-a-03-2025
vector_index_name           OCI_DB_MANUAL_IDX

確認する値です。

vector_index_name          = OCI_DB_MANUAL_IDX
enable_custom_source_uri   = true

enable_custom_source_uri = trueの場合は、第3回でObject Storage Metadataへ設定したOracle公式URLがRAG回答のSourcesへ表示されます。

■ 第2回で作成したLogical Entityを確認

第2回v1.3では、document_inventory.parquetをFilename Patternでグループ化し、document_inventoryというLogical Entityを作成しました。

第4回では同じ手順を繰り返さず、Autonomous AI Databaseとの同期に使用できる状態になっていることだけを確認します。

確認項目 確認結果
Logical Entity document_inventory
Status Active
Filename Pattern document-inventory-pattern
File Type PARQUET
Number of Attributes 20
Number of Files 1
対象Object catalog/document_inventory/current/document_inventory.parquet

Logical EntityのFilesタブに対象Parquetが表示され、20個のAttributesが確認できていれば、次のData Catalog同期へ進めます。

Filename Patternの作成、Data Assetへの割当て、Full Harvestの操作は第2回v1.3で実施しています。旧版の第2回を使用している場合は、先に第2回のLogical Entity作成手順を実施してください。

■ OCI Data CatalogとAutonomous AI Databaseを同期

OCI Data CatalogでハーベストしたLogical EntityをAutonomous AI Databaseと同期すると、Data Catalog管理のProtected Schema内にExternal Tableが作成されます。

Data CatalogのLogical EntityがExternal Tableへ、Logical EntityのAttributeがExternal Tableの列へマッピングされます。

参考: Query External Data with Data Catalog

第2回までの環境ですでにData Catalog同期を実施している場合、この節の接続・同期処理は省略し、生成済みExternal Tableの確認へ進みます。

● Resource Principal用Dynamic GroupとIAM Policyを確認

第3回で作成したAutonomous AI Database用Dynamic Groupを再利用できます。

Dynamic GroupのMatching Rule例です。

resource.id = '<Autonomous-AI-Database-OCID>'

DBMS_DCATからOCI Data Catalogへ接続するため、Autonomous AI DatabaseのResource Principalには次の権限が必要です。

allow dynamic-group <adb-dynamic-group-name> to manage data-catalog-family
in compartment <data-catalog-compartment-name>

allow dynamic-group <adb-dynamic-group-name> to read objects
in compartment <object-storage-compartment-name>

第3回でObject Storage読取りPolicyを設定済みの場合は、対象Bucketを読めることを確認します。今回追加になりやすいのは、manage data-catalog-familyです。

本番環境では、Data Catalog、Object Storage、Autonomous AI Databaseの配置Compartmentに合わせてPolicyのScopeを最小化します。

DCAT_SYNC Roleを確認

DBMS_DCATを使用するDatabase Userには、DCAT_SYNC Roleが必要です。

この記事ではADMINユーザーで同期処理を実行します。ADMIN以外のローカルユーザーで同期する場合は、ADMINからRoleを付与します。

SQL
GRANT DCAT_SYNC TO <data-catalog-sync-user>;

現在のユーザーへ付与されているか確認します。

SQL
SELECT
    granted_role
FROM
    user_role_privs
WHERE
    granted_role = 'DCAT_SYNC';
SQL実行結果
GRANTED_ROLE
_______________
DCAT_SYNC

● Data Catalog接続を確認

ADMINユーザーで実行します。

SQL
SELECT
    *
FROM
    all_dcat_connections;
SQL実行結果
no rows selected

no rows selectedと出力され、接続が未作成の場合は、Resource Principalを使用してOCI Data Catalog接続を作成します。

今回は、接続を識別しやすくするため、次のConnection IDを使用します。

OCI_DCAT_BLOG_01

dcat_con_idは複数のCatalogへ接続するときに必要です。1つだけ接続する場合は省略できますが、第5回以降のAIDPや外部Catalogとの比較を考慮し、第4回から明示します。

Connection IDには、次の条件があります。

Autonomous AI Database内で一意
英字から開始
英数字、_、$、#を使用可能
16文字以上

OCI_DCAT_BLOG_01は16文字で、この条件を満たしています。

・ Resource Principalを確認

最初に、ADMINユーザーでResource Principalが有効か確認します。

SQL
SELECT
    owner,
    credential_name
FROM
    dba_credentials
WHERE
    credential_name = 'OCI$RESOURCE_PRINCIPAL'
AND owner = 'ADMIN';

初回は、次の結果になりました。

SQL実行結果
no rows selected

Resource Principalを有効化します。

SQL
BEGIN
    DBMS_CLOUD_ADMIN.ENABLE_RESOURCE_PRINCIPAL();
END;
/
SQL実行結果
PL/SQL procedure successfully completed.

もう一度確認します。

SQL
SELECT
    owner,
    credential_name
FROM
    dba_credentials
WHERE
    credential_name = 'OCI$RESOURCE_PRINCIPAL'
AND owner = 'ADMIN';
SQL実行結果
OWNER    CREDENTIAL_NAME
________ _________________________
ADMIN    OCI$RESOURCE_PRINCIPAL

DBMS_DCATの引数定義を確認

Oracleのドキュメントでは、SET_DATA_CATALOG_CREDENTIALcredential_nameは省略可能で、省略時はResource Principalが使用されると説明されています。

ただし、今回のAutonomous AI Database環境では、dcat_con_idだけを指定した次の呼出しは、PLS-00306になりました。

今回の環境では使用しない省略形
BEGIN
    DBMS_DCAT.SET_DATA_CATALOG_CREDENTIAL(
        dcat_con_id => 'OCI_DCAT_BLOG_01'
    );
END;
/
SQL実行結果
PLS-00306: wrong number or types of arguments in call to
' SET_DATA_CATALOG_CREDENTIAL '

Databaseに実装されているPackageの定義を確認するため、次のSQLを実行します。

SQL
SELECT
    owner,
    overload,
    position,
    sequence,
    argument_name,
    data_type,
    in_out,
    defaulted
FROM
    all_arguments
WHERE
    package_name = 'DBMS_DCAT'
AND object_name = 'SET_DATA_CATALOG_CREDENTIAL'
ORDER BY
    owner,
    overload,
    sequence;
SQL実行結果
OWNER               OVERLOAD       POSITION    SEQUENCE ARGUMENT_NAME      DATA_TYPE    IN_OUT    DEFAULTED
___________________ ___________ ___________ ___________ __________________ ____________ _________ ____________
C##CLOUD$SERVICE                          1           1 CREDENTIAL_NAME    VARCHAR2     IN        N
C##CLOUD$SERVICE                          2           2 DCAT_CON_ID        VARCHAR2     IN        Y

今回の手順では、環境差によるデフォルト引数の解決へ依存しないように、credential_namedcat_con_idの両方を明示します。

・ Data Catalog用CredentialをConnection IDへ設定

Data CatalogのMetadataへアクセスするCredentialとして、ADMINユーザーのResource Principalを設定します。

SQL
BEGIN
    DBMS_DCAT.SET_DATA_CATALOG_CREDENTIAL(
        credential_name => 'OCI$RESOURCE_PRINCIPAL',
        dcat_con_id     => 'OCI_DCAT_BLOG_01'
    );
END;
/
SQL実行結果
PL/SQL procedure successfully completed.

・ Object Storage用CredentialをConnection IDへ設定

同期後に作成されるExternal TableからObject Storage上のParquetを読み取るため、Object Storage用Credentialも同じConnection IDへ設定します。

SQL
BEGIN
    DBMS_DCAT.SET_OBJECT_STORE_CREDENTIAL(
        credential_name => 'OCI$RESOURCE_PRINCIPAL',
        dcat_con_id     => 'OCI_DCAT_BLOG_01'
    );
END;
/
SQL実行結果
PL/SQL procedure successfully completed.

Data Catalog用とObject Storage用のCredentialは、役割が異なります。

Procedure 用途
SET_DATA_CATALOG_CREDENTIAL OCI Data CatalogのMetadataへアクセス
SET_OBJECT_STORE_CREDENTIAL External TableからObject Storage上の実データを読取り

・ OCI Data Catalog接続を登録

SET_DATA_CATALOG_CONNは、同じConnection IDについて1回だけ実行します。

冒頭の接続確認でOCI_DCAT_BLOG_01が表示されなかった場合だけ、2つのCredentialを設定した後にOCI Data Catalog接続を登録します。すでに接続が表示されている場合は、このProcedureを再実行せず「接続結果を確認」へ進みます。

SQL
BEGIN
    DBMS_DCAT.SET_DATA_CATALOG_CONN(
        region       => 'ap-tokyo-1',
        catalog_id   => '<OCI-Data-Catalog-OCID>',
        dcat_con_id  => 'OCI_DCAT_BLOG_01',
        catalog_type => 'OCI_DCAT'
    );
END;
/

catalog_idには、OCI Consoleで確認したData CatalogインスタンスのOCIDを指定します。

ocid1.datacatalog.oc1.ap-tokyo-1...

初回の登録が成功すると、次の結果になります。

SQL実行結果
PL/SQL procedure successfully completed.

すでにOCI_DCAT_BLOG_01が登録されている場合は、このSQLを再実行せず、次の「接続結果を確認」へ進みます。

ORA-20012: Connection identifier ... already existsが表示された場合

同じConnection IDでSET_DATA_CATALOG_CONNを再実行すると、次のエラーになります。

SQL実行結果
ORA-20012: Connection identifier OCI_DCAT_BLOG_01 already exists

これは新しい接続失敗ではなく、OCI_DCAT_BLOG_01がすでに登録されていることを示します。

SET_DATA_CATALOG_CONNは接続の新規作成用であり、既存Connection IDの上書きには使用しません。この場合は再登録せず、接続内容を確認してから同期へ進みます。

接続先のOCIDやRegionを誤って登録し、接続を作り直す必要がある場合だけ、次のProcedureで既存接続を削除します。

UNSET_DATA_CATALOG_CONNを実行すると、その接続の過去の同期で作成されたProtected SchemaとExternal Tableも削除されます。同期済み環境では、影響を確認してから実行します。

接続を作り直す場合のみ実行
BEGIN
    DBMS_DCAT.UNSET_DATA_CATALOG_CONN(
        dcat_con_id => 'OCI_DCAT_BLOG_01'
    );
END;
/

削除後は、Credentialの設定とSET_DATA_CATALOG_CONNをもう一度実行します。

・ 接続結果を確認

今回の環境では接続ID列がCONNECTION_IDだったため、次のSQLで確認します。

SQL
SELECT
    connection_id,
    name,
    catalog_type,
    region,
    instance_id,
    data_catalog_credential,
    object_store_credential,
    created,
    last_updated
FROM
    all_dcat_connections
WHERE
    connection_id = 'OCI_DCAT_BLOG_01';
SQL実行結果
CONNECTION_ID       NAME                 CATALOG_TYPE    REGION        INSTANCE_ID                                                                                      DATA_CATALOG_CREDENTIAL         OBJECT_STORE_CREDENTIAL         CREATED                            LAST_UPDATED
___________________ ____________________ _______________ _____________ ________________________________________________________________________________________________ _______________________________ _______________________________ __________________________________ __________________________________
OCI_DCAT_BLOG_01    Data-Catalog-Demo    OCI_DCAT        ap-tokyo-1    <data-catalog-ocid>    ADMIN.OCI$RESOURCE_PRINCIPAL    ADMIN.OCI$RESOURCE_PRINCIPAL    25-JUL-26 01.21.58.784000000 PM    10-AUG-26 04.09.31.139726000 PM
確認ポイント
CONNECTION_ID              = OCI_DCAT_BLOG_01
NAME                       = Data-Catalog-Demo
CATALOG_TYPE               = OCI_DCAT
REGION                     = ap-tokyo-1
DATA_CATALOG_CREDENTIAL    = ADMIN.OCI$RESOURCE_PRINCIPAL
OBJECT_STORE_CREDENTIAL    = ADMIN.OCI$RESOURCE_PRINCIPAL

今回の実行結果では、Data Catalog用Credentialと
Object Storage用Credentialの両方に、
ADMINユーザーのResource Principalが設定されていることを
確認できました。

参考:

● Data Catalogを同期

検証環境でData Catalog内の全Assetを同期する例です。

SQL
BEGIN
    DBMS_DCAT.RUN_SYNC(
        synced_objects  => q'~{"asset_list":["*"]}~',
        sync_option     => 'SYNC',
        error_semantics => 'STOP_ON_ERROR',
        log_level       => 'INFO',
        dcat_con_id     => 'OCI_DCAT_BLOG_01'
    );
END;
/
SQL実行結果
PL/SQL procedure successfully completed.

asset_list:["*"]は、対象が限定された検証用Data Catalogを想定しています。

複数システムのAssetが登録された環境では、AssetまたはLogical Entityを選択したSelective Syncを使用します。

同期状況を確認します。

SQL
SELECT
    id,
    type,
    start_time,
    update_time,
    status,
    logfile_table
FROM
    user_load_operations
WHERE
    type = 'DCAT_SYNC'
ORDER BY
    start_time DESC;
SQL実行結果
   ID TYPE         START_TIME                                    UPDATE_TIME                                   STATUS       LOGFILE_TABLE
_____ ____________ _____________________________________________ _____________________________________________ ____________ _____________________
   41 DCAT_SYNC    11-AUG-26 10.16.52.745653000 AM ASIA/TOKYO    11-AUG-26 10.17.05.287773000 AM ASIA/TOKYO    COMPLETED    "DBMS_DCAT$41_LOG"

STATUS = COMPLETEDになっていることを確認します。FAILEDの場合は、LOGFILE_TABLEまたは次のDBMS_DCAT$SYNC_LOGで原因を確認します。

直近の同期ログから、文書インベントリに関係する行だけを確認します。

SQL
SELECT
    log_timestamp,
    log_level,
    log_details
FROM
    DBMS_DCAT$SYNC_LOG
WHERE
       LOWER(log_details) LIKE '%catalog/document_inventory%'
    OR LOWER(log_details) LIKE '%entity document_inventory mapped to table%'
ORDER BY
    log_timestamp;
SQL実行結果(抜粋)
LOG_LEVEL  LOG_DETAILS
---------  ------------------------------------------------------------------------------
INFO       Translating regex: catalog/document_inventory/current/.*\.parquet$
INFO       Entity document_inventory mapped to table DCAT$OCI_DCAT_BLOG_01_...DOCUMENT_INVENTORY

● 同期されたLogical Entityを確認

SQL
SELECT
    dcat_con_id,
    oracle_schema_name,
    oracle_table_name
FROM
    dcat_entities
WHERE
    dcat_con_id = 'OCI_DCAT_BLOG_01'
AND oracle_table_name = 'DOCUMENT_INVENTORY';
SQL実行結果
DCAT_CON_ID       ORACLE_SCHEMA_NAME                                                                   ORACLE_TABLE_NAME
----------------  -----------------------------------------------------------------------------------  --------------------
OCI_DCAT_BLOG_01  DCAT$OCI_DCAT_BLOG_01_OBJECT_STORAGE_CSV_PARQUET_DEMO_ORACLE_DATABASE_DOC_CATALOG   DOCUMENT_INVENTORY

同期された文書インベントリのAttribute数も確認します。

SQL
SELECT
    COUNT(*) AS attribute_count
FROM
    dcat_attributes a
    INNER JOIN dcat_entities e
        ON  e.dcat_con_id = a.dcat_con_id
        AND e.asset_key   = a.asset_key
        AND e.entity_key  = a.entity_key
WHERE
    e.dcat_con_id = 'OCI_DCAT_BLOG_01'
AND e.oracle_table_name = 'DOCUMENT_INVENTORY';
SQL実行結果
ATTRIBUTE_COUNT
---------------
20

■ Data LakeのExternal Tableを確認

● DCAT Schemaを確認

Data Catalog同期で作成されたSchemaを確認します。

SQL
SELECT
    username
FROM
    all_users
WHERE
    username LIKE 'DCAT$%'
ORDER BY
    username;
SQL実行結果
USERNAME
______________________________________________________________________________________
DCAT$OCI_DCAT_BLOG_01_OBJECT_STORAGE_CSV_PARQUET_DEMO_DATA_CATALOG_CSV_PARQUET_DEMO
DCAT$OCI_DCAT_BLOG_01_OBJECT_STORAGE_CSV_PARQUET_DEMO_ORACLE_DATABASE_DOC_CATALOG

Data Catalog同期で生成されるSchema名は、環境のData Catalog接続、Data Asset、Bucketなどから決まります。

DCAT$<dcat-con-id>_<data-asset-name>_<folder-name>

● External Tableを確認

Data CatalogのLogical Entityと、同期で生成されたExternal TableのMappingを確認します。

SQL
SELECT
    e.display_name AS logical_entity_name,
    m.oracle_schema_name,
    m.oracle_table_name
FROM
    all_dcat_entities e
    INNER JOIN dcat_entities m
        ON m.dcat_con_id = e.dcat_con_id
       AND m.entity_key  = e.key
WHERE
    e.dcat_con_id = 'OCI_DCAT_BLOG_01'
AND UPPER(e.display_name) = 'DOCUMENT_INVENTORY';
SQL実行結果
LOGICAL_ENTITY_NAME    ORACLE_SCHEMA_NAME                                                                   ORACLE_TABLE_NAME
______________________ ____________________________________________________________________________________ _____________________
document_inventory     DCAT$OCI_DCAT_BLOG_01_OBJECT_STORAGE_CSV_PARQUET_DEMO_ORACLE_DATABASE_DOC_CATALOG    DOCUMENT_INVENTORY

ORACLE_SCHEMA_NAMEORACLE_TABLE_NAMEが、後続のSQLで使用する実Object名です。

External Table一覧からも確認できます。

SQL
SELECT
    owner,
    table_name,
    default_directory_name
FROM
    all_external_tables
WHERE
    owner LIKE 'DCAT$%'
ORDER BY
    owner,
    table_name;
SQL実行結果
OWNER                                                                                  TABLE_NAME              DEFAULT_DIRECTORY_NAME
______________________________________________________________________________________ _______________________ _________________________
DCAT$OCI_DCAT_BLOG_01_OBJECT_STORAGE_CSV_PARQUET_DEMO_DATA_CATALOG_CSV_PARQUET_DEMO    SALES_ORDERS_CSV
DCAT$OCI_DCAT_BLOG_01_OBJECT_STORAGE_CSV_PARQUET_DEMO_DATA_CATALOG_CSV_PARQUET_DEMO    SALES_ORDERS_PARQUET
DCAT$OCI_DCAT_BLOG_01_OBJECT_STORAGE_CSV_PARQUET_DEMO_ORACLE_DATABASE_DOC_CATALOG      DOCUMENT_INVENTORY

document_inventory.parquetに対応するExternal Tableを確認します。

以降の例では、次のPlaceholderを使用します。

Schema     : <DCAT-schema-name>
Table      : <document-inventory-external-table-name>

実際のSchema名とTable名へ置き換えます。

● External Tableの列を確認

SQL
SELECT
    column_id,
    column_name,
    data_type,
    data_length,
    data_precision,
    data_scale
FROM
    all_tab_columns
WHERE
    owner = 'DCAT$OCI_DCAT_BLOG_01_OBJECT_STORAGE_CSV_PARQUET_DEMO_ORACLE_DATABASE_DOC_CATALOG'
AND table_name = 'DOCUMENT_INVENTORY'
ORDER BY
    column_id;
SQL実行結果
   COLUMN_ID COLUMN_NAME           DATA_TYPE       DATA_LENGTH    DATA_PRECISION    DATA_SCALE
____________ _____________________ ____________ ______________ _________________ _____________
           1 DOCUMENT_ID           VARCHAR2               4000
           2 DOCUMENT_FAMILY_ID    VARCHAR2               4000
           3 PRODUCT_NAME          VARCHAR2               4000
           4 PRODUCT_VERSION       VARCHAR2               4000
           5 DOCUMENT_TITLE        VARCHAR2               4000
           6 DOCUMENT_TYPE         VARCHAR2               4000
           7 CATEGORY              VARCHAR2               4000
           8 SUBCATEGORY           VARCHAR2               4000
           9 LANGUAGE_CODE         VARCHAR2               4000
          10 DOCUMENT_NUMBER       VARCHAR2               4000
          11 PUBLICATION_YEAR      NUMBER                   22                 5             0
          12 PUBLICATION_MONTH     NUMBER                   22                 3             0
          13 OFFICIAL_URL          VARCHAR2               4000
          14 OBJECT_NAME           VARCHAR2               4000
          15 RAG_ENABLED           NUMBER                   22                 1             0
          16 DOCUMENT_PRIORITY     NUMBER                   22                 5             0
          17 DATA_OWNER            VARCHAR2               4000
          18 TAGS                  VARCHAR2               4000
          19 BUCKET_NAME           VARCHAR2               4000
          20 OBJECT_URI            VARCHAR2               4000

20 rows selected.

ParquetのBOOLはExternal TableではNUMBER(1)へマッピングされます。今回のrag_enabledは、1がtrue、0がfalseです。

参考: DBMS_CLOUD Package Parquet to Oracle Data Type Mapping

Data Lake上のデータを確認します。

SQL
SELECT
    document_id,
    product_version,
    document_title,
    category,
    official_url,
    object_name,
    rag_enabled,
    document_priority
FROM
    "DCAT$OCI_DCAT_BLOG_01_OBJECT_STORAGE_CSV_PARQUET_DEMO_ORACLE_DATABASE_DOC_CATALOG"."DOCUMENT_INVENTORY"
ORDER BY
    product_version,
    document_priority;
SQL実行結果
DOCUMENT_ID             PRODUCT_VERSION    DOCUMENT_TITLE                                     CATEGORY                   OFFICIAL_URL                                                                        OBJECT_NAME                                                                                   RAG_ENABLED    DOCUMENT_PRIORITY
_______________________ __________________ __________________________________________________ __________________________ ___________________________________________________________________________________ __________________________________________________________________________________________ ______________ ____________________
oracle_db_12_2_admin    12.2               Database Administrator's Guide                     administration             https://docs.oracle.com/en/database/oracle/oracle-database/12.2/admin/index.html    documents/oracle-database/12.2/admin/database-administrators-guide.pdf                                  1                   10
oracle_db_12_2_ladbi    12.2               Database Installation Guide for Linux              installation               https://docs.oracle.com/en/database/oracle/oracle-database/12.2/ladbi/index.html    documents/oracle-database/12.2/installation_linux/database-installation-guide-linux.pdf                 1                   20
oracle_db_12_2_cncpt    12.2               Database Concepts                                  architecture               https://docs.oracle.com/en/database/oracle/oracle-database/12.2/cncpt/index.html    documents/oracle-database/12.2/concepts/database-concepts.pdf                                           1                   30
oracle_db_19c_admin     19c                Database Administrator's Guide                     administration             https://docs.oracle.com/en/database/oracle/oracle-database/19/admin/index.html      documents/oracle-database/19c/admin/database-administrators-guide.pdf                                   1                   10
oracle_db_19c_ladbi     19c                Database Installation Guide for Linux              installation               https://docs.oracle.com/en/database/oracle/oracle-database/19/ladbi/index.html      documents/oracle-database/19c/installation_linux/database-installation-guide-linux.pdf                  1                   20
oracle_db_19c_cncpt     19c                Database Concepts                                  architecture               https://docs.oracle.com/en/database/oracle/oracle-database/19/cncpt/index.html      documents/oracle-database/19c/concepts/database-concepts.pdf                                            1                   30
oracle_db_26ai_vecse    26ai               AI Vector Search User's Guide                      ai_and_machine_learning    https://docs.oracle.com/en/database/oracle/oracle-database/26/vecse/index.html      documents/oracle-database/26ai/vector_search/ai-vector-search-users-guide.pdf                           1                    5
oracle_db_26ai_admin    26ai               Database Administrator's Guide                     administration             https://docs.oracle.com/en/database/oracle/oracle-database/26/admin/index.html      documents/oracle-database/26ai/admin/database-administrators-guide.pdf                                  1                   10
oracle_db_26ai_ladbi    26ai               Oracle AI Database Installation Guide for Linux    installation               https://docs.oracle.com/en/database/oracle/oracle-database/26/ladbi/index.html      documents/oracle-database/26ai/installation_linux/oracle-ai-database-installation-guide-linux.pdf                 1                   20
oracle_db_26ai_cncpt    26ai               Database Concepts                                  architecture               https://docs.oracle.com/en/database/oracle/oracle-database/26/cncpt/index.html      documents/oracle-database/26ai/concepts/database-concepts.pdf                                           1                   30

10 rows selected.

● 文書インベントリのURIとObject名を確認

第2回で修正したobject_uriが、全10件でHTTPS URIになっていることを確認します。

SQL
SELECT
    COUNT(*) AS invalid_object_uri_count
FROM
    "DCAT$OCI_DCAT_BLOG_01_OBJECT_STORAGE_CSV_PARQUET_DEMO_ORACLE_DATABASE_DOC_CATALOG"."DOCUMENT_INVENTORY"
WHERE
    object_uri LIKE '%<%'
OR  object_uri NOT LIKE 'https://%';
SQL実行結果
INVALID_OBJECT_URI_COUNT
------------------------
0

26ai Installation GuideのObject名も、実際のPDF名と一致していることを確認します。

SQL
SELECT
    document_id,
    object_name,
    object_uri
FROM
    "DCAT$OCI_DCAT_BLOG_01_OBJECT_STORAGE_CSV_PARQUET_DEMO_ORACLE_DATABASE_DOC_CATALOG"."DOCUMENT_INVENTORY"
WHERE
    document_id = 'oracle_db_26ai_ladbi';
SQL実行結果
DOCUMENT_ID           OBJECT_NAME                                                                                         OBJECT_URI
--------------------  --------------------------------------------------------------------------------------------------  -------------------------------------------------------------------------------
oracle_db_26ai_ladbi  documents/oracle-database/26ai/installation_linux/oracle-ai-database-installation-guide-linux.pdf  https://<namespace>.objectstorage.ap-tokyo-1.oci.customer-oci.com/...

今回はParquetのObject名、列名、データ型を変更せず、行値だけを更新したため、External Tableから修正後の値をそのまま参照できました。

● RAG_USERへREAD権限とCREATE VIEW権限を付与

Data Catalog同期Schemaは同期処理が管理するProtected Schemaです。

生成されたTableを直接変更せず、ADMINまたはDCAT_ADMINからRAG_USERREAD権限を付与します。DBMS_DCAT.RUN_SYNCgrant_read引数で自動付与する方法もありますが、今回は文書インベントリExternal Tableだけへ最小権限を付与します。

SQL構文
GRANT READ
ON "<DCAT-schema-name>"."<document-inventory-external-table-name>"
TO RAG_USER;

GRANT CREATE VIEW TO RAG_USER;
SQL実行結果
SQL> GRANT READ
    ON "DCAT$OCI_DCAT_BLOG_01_OBJECT_STORAGE_CSV_PARQUET_DEMO_ORACLE_DATABASE_DOC_CATALOG"."DOCUMENT_INVENTORY"
    TO RAG_USER;

Grant succeeded.

SQL> GRANT CREATE VIEW TO RAG_USER;

Grant succeeded.

Viewを作成するときは、Role経由ではなく、Objectに対する直接権限が必要です。

・ READ権限確認

SQL
SELECT
    grantee,
    owner,
    table_name,
    privilege,
    grantor
FROM
    dba_tab_privs
WHERE
    grantee = 'RAG_USER'
AND owner =
    'DCAT$OCI_DCAT_BLOG_01_OBJECT_STORAGE_CSV_PARQUET_DEMO_ORACLE_DATABASE_DOC_CATALOG'
AND table_name = 'DOCUMENT_INVENTORY'
ORDER BY
    privilege;
SQL実行結果
GRANTEE     OWNER                                                                                TABLE_NAME            PRIVILEGE    GRANTOR
___________ ____________________________________________________________________________________ _____________________ ____________ __________
RAG_USER    DCAT$OCI_DCAT_BLOG_01_OBJECT_STORAGE_CSV_PARQUET_DEMO_ORACLE_DATABASE_DOC_CATALOG    DOCUMENT_INVENTORY    READ         ADMIN

・ CREATE VIEW権限確認

SQL
SELECT
    grantee,
    privilege
FROM
    dba_sys_privs
WHERE
    grantee = 'RAG_USER'
AND privilege = 'CREATE VIEW';
SQL実行結果
GRANTEE     PRIVILEGE
___________ ______________
RAG_USER    CREATE VIEW

■ Data Lake参照用Viewを作成

以降はRAG_USERで実行します。

Data Catalog同期で生成されたSchema名やTable名を、Select AIへ直接公開することもできます。

ただし、生成名が長い場合や、将来AIDPなど別のCatalogへ移行する場合を考慮し、今回はローカルSchemaに安定したView名を作成します。

SQL
CREATE OR REPLACE VIEW DOCUMENT_INVENTORY_EXT_V AS
SELECT
    document_id,
    document_family_id,
    product_name,
    product_version,
    document_title,
    document_type,
    category,
    subcategory,
    language_code,
    document_number,
    publication_year,
    publication_month,
    official_url,
    object_name,
    rag_enabled,
    document_priority,
    data_owner,
    tags,
    bucket_name,
    object_uri
FROM
   "DCAT$OCI_DCAT_BLOG_01_OBJECT_STORAGE_CSV_PARQUET_DEMO_ORACLE_DATABASE_DOC_CATALOG"."DOCUMENT_INVENTORY";
SQL実行結果
View DOCUMENT_INVENTORY_EXT_V created.

件数を確認します。

SQL
SELECT
    COUNT(*) AS document_count
FROM
    DOCUMENT_INVENTORY_EXT_V;
SQL実行結果
   DOCUMENT_COUNT
_________________
               10

今回の文書インベントリでは、10件になる想定です。

SQL
SELECT
    product_version,
    COUNT(*) AS document_count
FROM
    DOCUMENT_INVENTORY_EXT_V
GROUP BY
    product_version
ORDER BY
    product_version;
SQL実行結果
PRODUCT_VERSION       DOCUMENT_COUNT
__________________ _________________
12.2                               3
19c                                3
26ai                               4

■ ADBのRDBMS表を作成

Data Lakeの文書インベントリは、文書そのものに関する比較的安定したMetadataを保持します。

一方、AIでの利用可否、レビュー状態、機密区分などは、運用中に更新される業務データです。

今回は、これらをAutonomous AI Database内のRDBMS表として管理します。

● 文書ガバナンス表を作成

SQL
CREATE TABLE DOCUMENT_GOVERNANCE (
    document_id                VARCHAR2(100)  NOT NULL,
    approval_status            VARCHAR2(20)   NOT NULL,
    ai_use_allowed             CHAR(1)        DEFAULT 'N' NOT NULL,
    security_classification    VARCHAR2(20)   NOT NULL,
    review_owner               VARCHAR2(100),
    reviewed_at                TIMESTAMP,
    notes                      VARCHAR2(1000),
    CONSTRAINT PK_DOCUMENT_GOVERNANCE
        PRIMARY KEY (document_id),
    CONSTRAINT CK_DOCUMENT_GOV_APPROVAL
        CHECK (approval_status IN ('APPROVED', 'REVIEW', 'BLOCKED')),
    CONSTRAINT CK_DOCUMENT_GOV_AI_USE
        CHECK (ai_use_allowed IN ('Y', 'N')),
    CONSTRAINT CK_DOCUMENT_GOV_SECURITY
        CHECK (security_classification IN ('PUBLIC', 'INTERNAL', 'CONFIDENTIAL'))
);
SQL実行結果
Table DOCUMENT_GOVERNANCE created.

ここで登録する承認状態や担当者は、第4回のLakehouse JOINを検証するためのサンプル値です。Oracle製品の正式なサポート状態や文書公開区分を表すものではありません。

● サンプルデータを登録

SQL
INSERT ALL
    INTO DOCUMENT_GOVERNANCE (
        document_id,
        approval_status,
        ai_use_allowed,
        security_classification,
        review_owner,
        reviewed_at,
        notes
    ) VALUES (
        'oracle_db_26ai_vecse',
        'APPROVED',
        'Y',
        'PUBLIC',
        'ai_platform_team',
        TIMESTAMP '2026-08-07 00:00:00',
        'Vector SearchとRAG検証で優先利用'
    )
    INTO DOCUMENT_GOVERNANCE (
        document_id,
        approval_status,
        ai_use_allowed,
        security_classification,
        review_owner,
        reviewed_at,
        notes
    ) VALUES (
        'oracle_db_26ai_admin',
        'APPROVED',
        'Y',
        'PUBLIC',
        'database_platform_team',
        TIMESTAMP '2026-08-07 00:00:00',
        'Database管理機能の確認に利用'
    )
    INTO DOCUMENT_GOVERNANCE (
        document_id,
        approval_status,
        ai_use_allowed,
        security_classification,
        review_owner,
        reviewed_at,
        notes
    ) VALUES (
        'oracle_db_26ai_cncpt',
        'APPROVED',
        'Y',
        'PUBLIC',
        'architecture_team',
        TIMESTAMP '2026-08-07 00:00:00',
        'Databaseアーキテクチャの確認に利用'
    )
    INTO DOCUMENT_GOVERNANCE (
        document_id,
        approval_status,
        ai_use_allowed,
        security_classification,
        review_owner,
        reviewed_at,
        notes
    ) VALUES (
        'oracle_db_26ai_ladbi',
        'REVIEW',
        'N',
        'PUBLIC',
        'infrastructure_team',
        TIMESTAMP '2026-08-07 00:00:00',
        'Agent利用前に内容と運用手順を再確認'
    )
SELECT 1 FROM dual;

COMMIT;
SQL実行結果
4 rows inserted.

Commit complete.

登録結果を確認します。

SQL
SELECT
    document_id,
    approval_status,
    ai_use_allowed,
    security_classification,
    review_owner,
    reviewed_at
FROM
    DOCUMENT_GOVERNANCE
ORDER BY
    document_id;
SQL実行結果
DOCUMENT_ID             APPROVAL_STATUS    AI_USE_ALLOWED    SECURITY_CLASSIFICATION    REVIEW_OWNER              REVIEWED_AT
_______________________ __________________ _________________ __________________________ _________________________ __________________________________
oracle_db_26ai_admin    APPROVED           Y                 PUBLIC                     database_platform_team    07-AUG-26 12.00.00.000000000 AM
oracle_db_26ai_cncpt    APPROVED           Y                 PUBLIC                     architecture_team         07-AUG-26 12.00.00.000000000 AM
oracle_db_26ai_ladbi    REVIEW             N                 PUBLIC                     infrastructure_team       07-AUG-26 12.00.00.000000000 AM
oracle_db_26ai_vecse    APPROVED           Y                 PUBLIC                     ai_platform_team          07-AUG-26 12.00.00.000000000 AM

■ Data Lake外部表とADB内部表をJOIN

● Lakehouse統合Viewを作成

Data Lakeの文書インベントリと、ADB内の文書ガバナンス表をdocument_idでJOINします。

同時に、Vector Storeで確認しやすい相対Object名を生成します。

文書インベントリのobject_nameです。

documents/oracle-database/26ai/vector_search/ai-vector-search-users-guide.pdf

Vector StoreのATTRIBUTES.object_nameです。

vector_search/ai-vector-search-users-guide.pdf

documents/oracle-database/<product_version>/を除外すると、Vector Store側と同じ相対Object名になります。

ただし、相対Object名だけをJOIN Keyにはしません。

admin/database-administrators-guide.pdfconcepts/database-concepts.pdfは、26ai、19c、12.2で同じ相対Object名になるためです。後続のVector StoreとのJOINでは、ATTRIBUTES.location_uriに含まれる製品バージョン付きPrefixとATTRIBUTES.object_nameを連結し、完全Object名を再構成します。

SQL
CREATE OR REPLACE VIEW V_DOCUMENT_LAKEHOUSE AS
SELECT
    i.document_id,
    i.document_family_id,
    i.product_name,
    i.product_version,
    i.document_title,
    i.document_type,
    i.category,
    i.subcategory,
    i.language_code,
    i.document_number,
    i.publication_year,
    i.publication_month,
    i.official_url,
    i.object_name,
    i.object_uri,
    i.bucket_name,
    i.rag_enabled,
    i.document_priority,
    i.data_owner,
    i.tags,
    NVL(g.approval_status, 'NOT_REVIEWED') AS approval_status,
    NVL(g.ai_use_allowed, 'N') AS ai_use_allowed,
    NVL(g.security_classification, 'UNCLASSIFIED') AS security_classification,
    g.review_owner,
    g.reviewed_at,
    g.notes,
    CASE
        WHEN i.object_name LIKE
             'documents/oracle-database/' || i.product_version || '/%'
        THEN SUBSTR(
                 i.object_name,
                 LENGTH(
                     'documents/oracle-database/' || i.product_version || '/'
                 ) + 1
             )
    END AS vector_object_name
FROM
    DOCUMENT_INVENTORY_EXT_V i
    LEFT JOIN DOCUMENT_GOVERNANCE g
        ON g.document_id = i.document_id;
SQL実行結果
View V_DOCUMENT_LAKEHOUSE created.

● JOIN結果を確認

SQL
SELECT
    document_id,
    product_version,
    document_title,
    rag_enabled,
    approval_status,
    ai_use_allowed,
    review_owner,
    vector_object_name
FROM
    V_DOCUMENT_LAKEHOUSE
ORDER BY
    product_version,
    document_priority;
SQL実行結果
DOCUMENT_ID             PRODUCT_VERSION    DOCUMENT_TITLE                                        RAG_ENABLED APPROVAL_STATUS    AI_USE_ALLOWED    REVIEW_OWNER              VECTOR_OBJECT_NAME
_______________________ __________________ __________________________________________________ ______________ __________________ _________________ _________________________ ___________________________________________________________
oracle_db_12_2_admin    12.2               Database Administrator's Guide                                  1 NOT_REVIEWED       N                                           admin/database-administrators-guide.pdf
oracle_db_12_2_ladbi    12.2               Database Installation Guide for Linux                           1 NOT_REVIEWED       N                                           installation_linux/database-installation-guide-linux.pdf
oracle_db_12_2_cncpt    12.2               Database Concepts                                               1 NOT_REVIEWED       N                                           concepts/database-concepts.pdf
oracle_db_19c_admin     19c                Database Administrator's Guide                                  1 NOT_REVIEWED       N                                           admin/database-administrators-guide.pdf
oracle_db_19c_ladbi     19c                Database Installation Guide for Linux                           1 NOT_REVIEWED       N                                           installation_linux/database-installation-guide-linux.pdf
oracle_db_19c_cncpt     19c                Database Concepts                                               1 NOT_REVIEWED       N                                           concepts/database-concepts.pdf
oracle_db_26ai_vecse    26ai               AI Vector Search User's Guide                                   1 APPROVED           Y                 ai_platform_team          vector_search/ai-vector-search-users-guide.pdf
oracle_db_26ai_admin    26ai               Database Administrator's Guide                                  1 APPROVED           Y                 database_platform_team    admin/database-administrators-guide.pdf
oracle_db_26ai_ladbi    26ai               Oracle AI Database Installation Guide for Linux                 1 REVIEW             N                 infrastructure_team       installation_linux/oracle-ai-database-installation-guide-linux.pdf
oracle_db_26ai_cncpt    26ai               Database Concepts                                               1 APPROVED           Y                 architecture_team         concepts/database-concepts.pdf

10 rows selected.

Oracle AI Database 26aiの4文書について、Data LakeのMetadataとADBのガバナンス情報が結合されます。

19cと12.2の文書は、今回DOCUMENT_GOVERNANCEへ登録していないため、次の値になります。

approval_status         = NOT_REVIEWED
ai_use_allowed          = N
security_classification = UNCLASSIFIED

■ Select AI向けにTableとColumnの意味を追加

Select AIのNL2SQL精度を上げるため、Viewと主要列へコメントを設定します。

SQL
COMMENT ON TABLE V_DOCUMENT_LAKEHOUSE IS
'Object Storage上の文書インベントリとADB内部の文書ガバナンス情報をdocument_idで統合したLakehouse View';
SQL実行結果
Comment created.
SQL
COMMENT ON COLUMN V_DOCUMENT_LAKEHOUSE.DOCUMENT_ID IS
'製品バージョンを含む文書単位の一意なID';

COMMENT ON COLUMN V_DOCUMENT_LAKEHOUSE.DOCUMENT_FAMILY_ID IS
'製品バージョンをまたいだ文書系列のID';

COMMENT ON COLUMN V_DOCUMENT_LAKEHOUSE.PRODUCT_VERSION IS
'Oracle Databaseの製品バージョン。26ai、19c、12.2など';

COMMENT ON COLUMN V_DOCUMENT_LAKEHOUSE.RAG_ENABLED IS
'文書インベントリでRAG対象として管理されているかを示す値。ParquetのBOOLはExternal TableでNUMBER(1)へマッピングされ、1がtrue、0がfalse';

COMMENT ON COLUMN V_DOCUMENT_LAKEHOUSE.APPROVAL_STATUS IS
'ADBの業務表で管理するAI利用レビュー状態。APPROVED、REVIEW、BLOCKED、NOT_REVIEWED';

COMMENT ON COLUMN V_DOCUMENT_LAKEHOUSE.AI_USE_ALLOWED IS
'AI AgentやRAGでの利用を業務上許可している場合はY、それ以外はN';

COMMENT ON COLUMN V_DOCUMENT_LAKEHOUSE.DOCUMENT_PRIORITY IS
'数値が小さいほど利用優先度が高い';

COMMENT ON COLUMN V_DOCUMENT_LAKEHOUSE.VECTOR_OBJECT_NAME IS
'Vector Storeとの対応確認に使用する正規化済み相対Object名。バージョン間で重複するため、単独ではJOIN Keyにしない';
SQL実行結果
Comment created.

■ Vector StoreとJOIN

● Vector TableのATTRIBUTES確認

第3回でDBMS_CLOUD_AI.CREATE_VECTOR_INDEXを実行したとき、object_namestart_offsetなどの項目はVector Indexの作成構文へ明示的に指定していません。

しかし、作成されたOCI_DB_MANUAL_IDX$VECTABを確認すると、ATTRIBUTES列のJSONにSource ObjectやChunkに関する情報が自動的に格納されています。

OCI_DB_MANUAL_IDX$VECTAB
├── CONTENT
│     └── PDFから抽出・分割された本文Chunk
│
├── ATTRIBUTES
│     ├── object_name
│     ├── object_size
│     ├── last_modified
│     ├── location_uri
│     ├── custom_uri
│     ├── start_offset
│     └── end_offset
│
└── EMBEDDING
      └── Chunk本文から生成されたEmbedding Vector

ATTRIBUTESは、CREATE_VECTOR_INDEXでユーザーが列定義したものではありません。

Vector Index作成時に自動作成されるData Load PipelineがObject Storage上のSource Objectを取得し、本文抽出、Chunk分割、Embedding生成を行う過程で、**「このChunkがどのSource Objectのどの位置から作成されたか」**を追跡するためのMetadataをJSONとして付加します。

今回のVector Indexでは、次のPipelineが自動作成されています。

OCI_DB_MANUAL_IDX$VECPIPELINE

また、CREATE_VECTOR_INDEXでは次のようにprofile_nameとObject Storageのlocationを指定しています。

profile_name = OCI_DB_MANUAL_RAG
location     = Object Storage上の26ai PDF

このため、Vector StoreにはPDF本文だけではなく、Source ObjectとChunkを追跡するためのMetadataも保存されます。

ATTRIBUTESへ格納される情報

今回の環境で確認した主なPropertyは次のとおりです。

Property 内容 主な生成元
object_name Vector Indexのlocationを基準としたSource Object名 Object StorageのSource Object情報
object_size Source Objectのファイルサイズ Object StorageのObject Metadata
last_modified Source Objectの最終更新日時 Object StorageのObject Metadata
location_uri Vector Indexが参照したObject StorageのLocation情報 CREATE_VECTOR_INDEXlocationと取込処理
custom_uri RAGのSourceとして使用するCustom URL。今回の環境で確認できたVector Store内部表現 Object StorageのCustom Metadataを使用した取込結果
start_offset Chunkの開始位置 Chunk分割処理
end_offset Chunkの終了位置 Chunk分割処理

Databaseや取込処理のバージョンによって、これ以外のPropertyが追加される可能性があります。そのため、固定のProperty一覧を前提にするのではなく、後述のSQLで実際のATTRIBUTESを確認します。

custom_uriはどこから来るのか

custom_uriは、OCI Object Storageにcustom_uriという名前のMetadataを作成したものではありません。

第3回では、PDFをObject StorageへPutするときに、次のUser-defined Metadataを設定しています。

customized_url_source
=
https://docs.oracle.com/...

OCI Object Storageでは、User-defined Metadataはopc-meta-というPrefix付きのMetadata Headerとして管理・返却されます。

そのため、OCI ConsoleのObject Detailsでは次の名前で確認できます。

opc-meta-customized_url_source

今回の流れを整理すると次のようになります。

作業者がPDFをObject StorageへPut
        │
        └─ customized_url_source
           = Oracle公式URL
                │
                ▼
OCI Object Storage
        │
        └─ opc-meta-customized_url_source
           = Oracle公式URL
                │
                │ Vector Index Data Load Pipeline
                ▼
OCI_DB_MANUAL_IDX$VECTAB
        │
        └─ ATTRIBUTES.custom_uri
           = Oracle公式URL
                │
                ▼
Select AI with RAG
        └─ SourcesでOracle公式URLを表示

Select AI Profileでは、次のAttributeをtrueに設定しています。

enable_custom_source_uri = true

この設定により、Select AIはRAGのSourcesを表示するときに、Object Storage Objectのopc-meta-customized_url_sourceをCustom Source URLとして使用します。

今回の検証では、このMetadataを設定してVector Indexを再作成した後、同じURLがOCI_DB_MANUAL_IDX$VECTAB.ATTRIBUTEScustom_uriとして格納されていることも確認できました。

opc-meta-customized_url_sourceをRAGのSourcesへ使用する動作はSelect AIの機能として定義されています。

一方、Vector Table内部でcustom_uriというJSON Property名へ格納されることについては、今回の環境で実際に確認できた内部表現として扱います。custom_uriというProperty名そのものを固定的な公開Schemaとして前提にせず、実データを確認して使用します。

・ Data Catalogのofficial_urlが自動コピーされたわけではない

第2回で作成した文書インベントリには、Oracle公式URLを保持するofficial_urlがあります。

ただし、次の2つは別のMetadataです。

Data Lake / document_inventory.parquet
  official_url
      → 文書インベントリとして管理するURL

OCI Object Storage
  customized_url_source
      → RAGのSourcesとして使用するURL

Data Catalogやdocument_inventory.parquetofficial_urlが、自動的にVector Storeへコピーされたわけではありません。

第3回では同じOracle公式URLをObject Storage Objectのcustomized_url_sourceへ別途設定し、それをVector Indexの取込処理とSelect AI with RAGから利用しています。

ATTRIBUTESのJSONをそのまま確認

まず、Vector Tableに実際に保存されているJSONをそのまま確認します。

SQL
SELECT
    JSON_SERIALIZE(
        attributes
        RETURNING VARCHAR2(4000)
        PRETTY
    ) AS attributes
FROM
    OCI_DB_MANUAL_IDX$VECTAB
WHERE
    JSON_VALUE(
        attributes,
        '$.object_name'
        RETURNING VARCHAR2(1000)
    ) = 'vector_search/ai-vector-search-users-guide.pdf'
FETCH FIRST 1 ROW ONLY;

今回の環境では、次のようなSource MetadataとChunk Metadataを確認できます。

{
  "object_name" : "vector_search/ai-vector-search-users-guide.pdf",
  "object_size" : 6013363,
  "last_modified" : "2026-08-06T13:32:21+00:00",
  "location_uri" : "https://objectstorage.ap-tokyo-1.oraclecloud.com/n/<namespace>/b/oracle-database-doc-catalog/o/documents/oracle-database/26ai/",
  "custom_uri" : "https://docs.oracle.com/en/database/oracle/oracle-database/26/vecse/ai-vector-search-users-guide.pdf",
  "start_offset" : 1001729,
  "end_offset" : 1002752
}

・ Propertyを列として確認

JOINで利用するPropertyを列として取り出して確認します。

SQL
SELECT DISTINCT
    JSON_VALUE(
        attributes,
        '$.object_name'
        RETURNING VARCHAR2(1000)
    ) AS object_name,
    JSON_VALUE(
        attributes,
        '$.object_size'
        RETURNING NUMBER
    ) AS object_size,
    JSON_VALUE(
        attributes,
        '$.last_modified'
        RETURNING VARCHAR2(100)
    ) AS last_modified,
    JSON_VALUE(
        attributes,
        '$.location_uri'
        RETURNING VARCHAR2(2000)
    ) AS location_uri,
    JSON_VALUE(
        attributes,
        '$.custom_uri'
        RETURNING VARCHAR2(2000)
    ) AS custom_uri
FROM
    OCI_DB_MANUAL_IDX$VECTAB
ORDER BY
    object_name;
SQL実行かくにん
OBJECT_NAME                                                              OBJECT_SIZE LAST_MODIFIED                LOCATION_URI                                                                                                                       CUSTOM_URI
_____________________________________________________________________ ______________ ____________________________ __________________________________________________________________________________________________________________________________ ________________________________________________________________________________________________________
admin/database-administrators-guide.pdf                                      9975856 2026-08-06T15:36:45+00:00    https://objectstorage.ap-tokyo-1.oraclecloud.com/n/idqcucnenh88/b/oracle-database-doc-catalog/o/documents/oracle-database/26ai/    https://docs.oracle.com/en/database/oracle/oracle-database/26/admin/database-administrators-guide.pdf
concepts/database-concepts.pdf                                              13348414 2026-08-06T13:32:04+00:00    https://objectstorage.ap-tokyo-1.oraclecloud.com/n/idqcucnenh88/b/oracle-database-doc-catalog/o/documents/oracle-database/26ai/    https://docs.oracle.com/cd/G47991_01/cncpt/database-concepts.pdf
installation_linux/oracle-ai-database-installation-guide-linux.pdf           1138151 2026-08-06T13:32:12+00:00    https://objectstorage.ap-tokyo-1.oraclecloud.com/n/idqcucnenh88/b/oracle-database-doc-catalog/o/documents/oracle-database/26ai/    https://docs.oracle.com/cd/G47991_01/ladbi/oracle-ai-database-installation-guide-linux.pdf
vector_search/ai-vector-search-users-guide.pdf                               6013363 2026-08-06T13:32:21+00:00    https://objectstorage.ap-tokyo-1.oraclecloud.com/n/idqcucnenh88/b/oracle-database-doc-catalog/o/documents/oracle-database/26ai/    https://docs.oracle.com/en/database/oracle/oracle-database/26/vecse/ai-vector-search-users-guide.pdf

Chunk単位の位置情報も確認できます。

SQL
SELECT
    JSON_VALUE(
        attributes,
        '$.object_name'
        RETURNING VARCHAR2(1000)
    ) AS object_name,
    JSON_VALUE(
        attributes,
        '$.start_offset'
        RETURNING NUMBER
    ) AS start_offset,
    JSON_VALUE(
        attributes,
        '$.end_offset'
        RETURNING NUMBER
    ) AS end_offset,
    DBMS_LOB.SUBSTR(content, 200, 1) AS chunk_content
FROM
    OCI_DB_MANUAL_IDX$VECTAB
WHERE
    JSON_VALUE(
        attributes,
        '$.object_name'
        RETURNING VARCHAR2(1000)
    ) = 'vector_search/ai-vector-search-users-guide.pdf'
FETCH FIRST 5 ROWS ONLY;
SQL実行確認
OBJECT_NAME                                          START_OFFSET    END_OFFSET CHUNK_CONTENT
_________________________________________________ _______________ _____________ _____________________________________________________________________________________
vector_search/ai-vector-search-users-guide.pdf             542081        543104 se, the text may lose semantic context and may not be useful for queries



                                                                                that target specific information.



                                                                                Syntax:



                                                                                SELECT C.*



                                                                                FROM documentation_tab D, VECTOR_CHUNKS(D.text BY words MAX 4
vector_search/ai-vector-search-users-guide.pdf             528641        529664 ation of specialized indexes that



                                                                                are designed for Artificial Intelligence (AI) workloads that allow you to



                                                                                query data based on semantics



                                                                                314 150 , rather than keywords.



                                                                                Why Use Oracle A
vector_search/ai-vector-search-users-guide.pdf             570753        571776


                                                                                columns stored in external



                                                                                tables.



                                                                                



                                                                                IVF indexes are supported only for external Iceberg tables. For more information,



                                                                                see



                                                                                IVF Indexing on External Iceberg Tables



                                                                                .



                                                                                Vector
vector_search/ai-vector-search-users-guide.pdf             606593        607616 87654E-002,3.45828459E-002,-3.45360823E-002,-4.4002533E-003,1.77463



                                                                                517'||



                                                                                'E-002,6.68234832E-004,6.14458732E-002,-5.07084019E-002,-1.21073434E-002,4.195



                                                                                981'||



                                                                                '85E-002,3.69152687E-002,1.
vector_search/ai-vector-search-users-guide.pdf             613761        614784


                                                                                M77



                                                                                0



                                                                                1



                                                                                1



                                                                                0



                                                                                0



                                                                                M91



                                                                                0



                                                                                1



                                                                                1



                                                                                0



                                                                                0



                                                                                M49



                                                                                0



                                                                                0



                                                                                0



                                                                                1



                                                                                1



                                                                                M60



                                                                                0



                                                                                0



                                                                                0



                                                                                0



                                                                                1



                                                                                NGC1073



                                                                                0



                                                                                1



                                                                                1



                                                                                0



                                                                                0



                                                                                This nat

SQL>

・ どのJSON Propertyが存在するかを確認

ATTRIBUTESに格納されているJSON Propertyをまとめて確認したい場合は、JSON_DATAGUIDEを使用できます。

SQLclでは出力が長くなる場合があるため、最初に表示サイズを広げます。

SQL
SET LONG 100000
SET LONGCHUNKSIZE 100000
SQL
SELECT
    JSON_DATAGUIDE(attributes) AS attributes_data_guide
FROM
    OCI_DB_MANUAL_IDX$VECTAB;
SQL実行確認
ATTRIBUTES_DATA_GUIDE
_________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
[{"o:path":"$","type":"object","o:length":1},{"o:path":"$.custom_uri","type":"string","o:length":128},{"o:path":"$.end_offset","type":"number","o:length":8},{"o:path":"$.object_name","type":"string","o:length":128},{"o:path":"$.object_size","type":"number","o:length":8},{"o:path":"$.location_uri","type":"string","o:length":128},{"o:path":"$.start_offset","type":"number","o:length":8},{"o:path":"$.last_modified","type":"string","o:length":32}]

これにより、ATTRIBUTES内に実際に存在するJSON PathとDatatypeを確認できます。

● Vector TableのObject名を確認

ATTRIBUTES.location_uriはVector Index作成時に指定したObject StorageのPrefix、ATTRIBUTES.object_nameはそのPrefixからの相対Object名です。

SQL
SELECT DISTINCT
    JSON_VALUE(
        attributes,
        '$.location_uri'
        RETURNING VARCHAR2(2000)
    ) AS vector_location_uri,
    JSON_VALUE(
        attributes,
        '$.object_name'
        RETURNING VARCHAR2(1000)
    ) AS vector_object_name,
    JSON_VALUE(
        attributes,
        '$.custom_uri'
        RETURNING VARCHAR2(2000)
    ) AS source_uri
FROM
    OCI_DB_MANUAL_IDX$VECTAB
ORDER BY
    vector_object_name;
SQL実行結果
VECTOR_LOCATION_URI                                                                                                                VECTOR_OBJECT_NAME                                                    SOURCE_URI
__________________________________________________________________________________________________________________________________ _____________________________________________________________________ ________________________________________________________________________________________________________
https://objectstorage.ap-tokyo-1.oraclecloud.com/n/<namespace>/b/oracle-database-doc-catalog/o/documents/oracle-database/26ai/    admin/database-administrators-guide.pdf                               https://docs.oracle.com/en/database/oracle/oracle-database/26/admin/database-administrators-guide.pdf
https://objectstorage.ap-tokyo-1.oraclecloud.com/n/<namespace>/b/oracle-database-doc-catalog/o/documents/oracle-database/26ai/    concepts/database-concepts.pdf                                        https://docs.oracle.com/cd/G47991_01/cncpt/database-concepts.pdf
https://objectstorage.ap-tokyo-1.oraclecloud.com/n/<namespace>/b/oracle-database-doc-catalog/o/documents/oracle-database/26ai/    installation_linux/oracle-ai-database-installation-guide-linux.pdf    https://docs.oracle.com/cd/G47991_01/ladbi/oracle-ai-database-installation-guide-linux.pdf
https://objectstorage.ap-tokyo-1.oraclecloud.com/n/<namespace>/b/oracle-database-doc-catalog/o/documents/oracle-database/26ai/    vector_search/ai-vector-search-users-guide.pdf                        https://docs.oracle.com/en/database/oracle/oracle-database/26/vecse/ai-vector-search-users-guide.pdf

4つのPDFについて、26aiを含むPrefix、相対Object名、Oracle公式URLが表示されます。

● 相対Object名の重複を確認

文書インベントリでは、同じ種類のマニュアルが複数の製品バージョンに存在します。

SQL
SELECT
    vector_object_name,
    COUNT(DISTINCT product_version) AS version_count
FROM
    V_DOCUMENT_LAKEHOUSE
GROUP BY
    vector_object_name
HAVING
    COUNT(DISTINCT product_version) > 1
ORDER BY
    vector_object_name;
SQL実行結果
VECTOR_OBJECT_NAME                                             VERSION_COUNT
___________________________________________________________ ________________
admin/database-administrators-guide.pdf                                    3
concepts/database-concepts.pdf                                             3
installation_linux/database-installation-guide-linux.pdf                   2

例えば、次の相対Object名は製品バージョン間で重複します。adminconceptsは26ai、19c、12.2で重複し、installation_linux/database-installation-guide-linux.pdfは19cと12.2で重複します。

admin/database-administrators-guide.pdf
concepts/database-concepts.pdf
installation_linux/database-installation-guide-linux.pdf

このため、ATTRIBUTES.object_nameだけでJOINすると、26aiのVectorチャンクが19cや12.2の文書Metadataへ誤って結び付く可能性があります。

● Data Lake、RDBMS、Vector Storeの統合Viewを作成

Vector Storeのlocation_uriから/o/より後ろのPrefixを取り出し、末尾と先頭の/を正規化して相対Object名を連結します。

location_uriのObject Prefix
  documents/oracle-database/26ai/

+ attributes.object_name
  vector_search/ai-vector-search-users-guide.pdf

= 完全Object名
  documents/oracle-database/26ai/vector_search/ai-vector-search-users-guide.pdf

この完全Object名を、文書インベントリのobject_nameとJOINします。

SQL
CREATE OR REPLACE VIEW V_DOCUMENT_VECTOR_CHUNKS AS
WITH VECTOR_SOURCE AS (
    SELECT
        content,
        attributes,
        embedding,
        JSON_VALUE(
            attributes,
            '$.location_uri'
            RETURNING VARCHAR2(2000)
        ) AS vector_location_uri,
        JSON_VALUE(
            attributes,
            '$.object_name'
            RETURNING VARCHAR2(1000)
        ) AS vector_object_name,
        RTRIM(
            REGEXP_SUBSTR(
                JSON_VALUE(
                    attributes,
                    '$.location_uri'
                    RETURNING VARCHAR2(2000)
                ),
                '/o/(.*)$',
                1,
                1,
                NULL,
                1
            ),
            '/'
        ) || '/' ||
        LTRIM(
            JSON_VALUE(
                attributes,
                '$.object_name'
                RETURNING VARCHAR2(1000)
            ),
            '/'
        ) AS vector_full_object_name,
        JSON_VALUE(
            attributes,
            '$.custom_uri'
            RETURNING VARCHAR2(2000)
        ) AS source_uri,
        JSON_VALUE(
            attributes,
            '$.start_offset'
            RETURNING NUMBER
        ) AS start_offset,
        JSON_VALUE(
            attributes,
            '$.end_offset'
            RETURNING NUMBER
        ) AS end_offset
    FROM
        OCI_DB_MANUAL_IDX$VECTAB
)
SELECT
    l.document_id,
    l.document_family_id,
    l.product_name,
    l.product_version,
    l.document_title,
    l.document_type,
    l.category,
    l.subcategory,
    l.official_url,
    l.object_name AS inventory_object_name,
    l.object_uri,
    l.rag_enabled,
    l.document_priority,
    l.approval_status,
    l.ai_use_allowed,
    l.security_classification,
    l.review_owner,
    l.reviewed_at,
    v.vector_location_uri,
    v.vector_object_name,
    v.vector_full_object_name,
    v.source_uri,
    v.start_offset,
    v.end_offset,
    v.content AS chunk_content,
    v.embedding AS chunk_embedding
FROM
    V_DOCUMENT_LAKEHOUSE l
    INNER JOIN VECTOR_SOURCE v
        ON v.vector_full_object_name = l.object_name;
SQL実行結果
View V_DOCUMENT_VECTOR_CHUNKS created.

このViewでは、次の3種類のデータが1行へ結び付きます。

Data Lake
  document_title、product_version、category、official_url

RDBMS
  approval_status、ai_use_allowed、review_owner

Vector Store
  chunk_content、chunk_embedding、source_uri

● 文書ごとのチャンク数を確認

最初に、統合Viewへ結び付いた文書数とチャンク総数を確認します。

SQL
SELECT
    COUNT(DISTINCT document_id) AS document_count,
    COUNT(*) AS joined_chunk_count
FROM
    V_DOCUMENT_VECTOR_CHUNKS;
SQL実行結果

   DOCUMENT_COUNT    JOINED_CHUNK_COUNT
_________________ _____________________
                4                  9590

第3回のVector Storeがそのまま残っており、4文書すべてのObject名が一致していれば、次の値になる想定です。

想定結果
DOCUMENT_COUNT      = 4
JOINED_CHUNK_COUNT  = 9590

続いて、文書ごとのチャンク数を確認します。

SQL
SELECT
    document_id,
    document_title,
    approval_status,
    ai_use_allowed,
    COUNT(*) AS chunk_count
FROM
    V_DOCUMENT_VECTOR_CHUNKS
GROUP BY
    document_id,
    document_title,
    approval_status,
    ai_use_allowed
ORDER BY
    document_id;
SQL実行結果

DOCUMENT_ID             DOCUMENT_TITLE                                     APPROVAL_STATUS    AI_USE_ALLOWED       CHUNK_COUNT
_______________________ __________________________________________________ __________________ _________________ ______________
oracle_db_26ai_admin    Database Administrator's Guide                     APPROVED           Y                           4586
oracle_db_26ai_cncpt    Database Concepts                                  APPROVED           Y                           2386
oracle_db_26ai_ladbi    Oracle AI Database Installation Guide for Linux    REVIEW             N                            733
oracle_db_26ai_vecse    AI Vector Search User's Guide                      APPROVED           Y                           1885

● Vector StoreとのJOIN漏れを確認

文書インベントリ側に存在する26ai文書のうち、Vector Storeへ結び付かなかった文書を確認します。

SQL
WITH VECTOR_OBJECTS AS (
    SELECT DISTINCT
        RTRIM(
            REGEXP_SUBSTR(
                JSON_VALUE(
                    attributes,
                    '$.location_uri'
                    RETURNING VARCHAR2(2000)
                ),
                '/o/(.*)$',
                1,
                1,
                NULL,
                1
            ),
            '/'
        ) || '/' ||
        LTRIM(
            JSON_VALUE(
                attributes,
                '$.object_name'
                RETURNING VARCHAR2(1000)
            ),
            '/'
        ) AS vector_full_object_name
    FROM
        OCI_DB_MANUAL_IDX$VECTAB
)
SELECT
    l.document_id,
    l.document_title,
    l.object_name,
    l.vector_object_name
FROM
    V_DOCUMENT_LAKEHOUSE l
WHERE
    l.product_version = '26ai'
AND l.rag_enabled = 1
AND NOT EXISTS (
    SELECT
        1
    FROM
        VECTOR_OBJECTS v
    WHERE
        v.vector_full_object_name = l.object_name
);
SQL実行結果
no rows selected

0件であれば、4文書すべてのObject名を正しく結び付けられています。

● 3レイヤーを1つのSQLで確認

SQL
SELECT
    document_id,
    product_version,
    document_title,
    category,
    approval_status,
    ai_use_allowed,
    review_owner,
    source_uri,
    DBMS_LOB.SUBSTR(chunk_content, 300, 1) AS chunk_content
FROM
    V_DOCUMENT_VECTOR_CHUNKS
WHERE
    document_id = 'oracle_db_26ai_vecse'
FETCH FIRST 1 ROW ONLY;
SQL実行結果(抜粋)
DOCUMENT_ID           PRODUCT_VERSION  DOCUMENT_TITLE                   APPROVAL_STATUS  AI_USE_ALLOWED  REVIEW_OWNER       SOURCE_URI                                      CHUNK_CONTENT
--------------------  ---------------  -------------------------------  ---------------  --------------  -----------------  ----------------------------------------------  ----------------------------------------
oracle_db_26ai_vecse  26ai             AI Vector Search User's Guide   APPROVED         Y               ai_platform_team   https://docs.oracle.com/.../vecse/...pdf    Syntax: SELECT C.* FROM ... VECTOR_CHUNKS(...)

これで、Data Lakeの文書Metadata、ADBのガバナンス情報、Vector StoreのPDF本文チャンクを同じSQLで参照できました。

V_DOCUMENT_VECTOR_CHUNKSは、Vector Storeの内容をガバナンス情報と一緒に監査・確認したり、今後Custom SQL RAGやAI AgentのToolから利用したりするためのRelational Viewです。標準のSelect AI with RAGは、引き続きOCI_DB_MANUAL_IDXをVector Indexとして使用します。

■ Lakehouse検索用Select AI Profileを作成

Data Lake外部表とADB内部表をJOINしたV_DOCUMENT_LAKEHOUSEを、NL2SQLの対象にします。

Vectorの生チャンクやEmbeddingは、NL2SQLで自由に参照させる必要がありません。

そのため、SQL用Profileのobject_listには、安定したLakehouse Viewだけを登録します。

● 実行ユーザーを確認

ここからのProfile作成とSelect AIの実行は、RAG_USERで行います。

SQL
SHOW USER
SQL実行結果
USER is "RAG_USER"

● Profile属性JSONを事前検証

Profileを削除・作成する前に、最小構成の属性がStrict JSONとして有効であることを確認します。

<OCI-Generative-AI-Compartment-OCID>は、OCI Generative AIを利用するCompartmentのOCIDへ置き換えます。

SQL
SELECT
    CASE
        WHEN q'~{
            "provider": "oci",
            "credential_name": "OCI$RESOURCE_PRINCIPAL",
            "region": "ap-osaka-1",
            "oci_compartment_id": "<OCI-Generative-AI-Compartment-OCID>",
            "model": "cohere.command-a-03-2025",
            "object_list": [
                {
                    "owner": "RAG_USER",
                    "name": "V_DOCUMENT_LAKEHOUSE"
                }
            ]
        }~' IS JSON STRICT
        THEN 'VALID JSON'
        ELSE 'INVALID JSON'
    END AS json_status
FROM
    dual;
SQL実行結果
JSON_STATUS
______________
VALID JSON

JSON文字列では、Property名と文字列値をダブルクォーテーションで囲みます。

次のようなJSON_OBJECT用構文を、q'~{...}~'のJSON文字列内へ混在させないようにします。

使用しない形式
'oci_compartment_id' VALUE 'ocid1.compartment...'

● 同名Profileを削除

JSONがVALID JSONになったことを確認してから、同名Profileを削除します。

force = TRUEを指定すると、Profileが存在しない場合もエラーを無視できます。

SQL
BEGIN
    DBMS_CLOUD_AI.DROP_PROFILE(
        profile_name => 'OCI_DB_LAKEHOUSE_SQL',
        force        => TRUE
    );
END;
/
SQL実行結果
PL/SQL procedure successfully completed.

● 最小構成でProfileを作成

最初からすべてのAttributeを指定せず、まず接続とObject Listに必要な最小構成で作成します。

SQL
BEGIN
    DBMS_CLOUD_AI.CREATE_PROFILE(
        profile_name => 'OCI_DB_LAKEHOUSE_SQL',
        attributes   => q'~{
            "provider": "oci",
            "credential_name": "OCI$RESOURCE_PRINCIPAL",
            "region": "ap-osaka-1",
            "oci_compartment_id": "<OCI-Generative-AI-Compartment-OCID>",
            "model": "cohere.command-a-03-2025",
            "object_list": [
                {
                    "owner": "RAG_USER",
                    "name": "V_DOCUMENT_LAKEHOUSE"
                }
            ]
        }~',
        status       => 'ENABLED',
        description  => 'NL2SQL profile for Data Catalog external data joined with ADB document governance data'
    );
END;
/
SQL実行結果
PL/SQL procedure successfully completed.

● Profileと基本Attributeを確認

SQL
SELECT
    profile_name,
    status,
    description
FROM
    user_cloud_ai_profiles
WHERE
    profile_name = 'OCI_DB_LAKEHOUSE_SQL';
SQL実行結果
PROFILE_NAME            STATUS     DESCRIPTION
_______________________ __________ ___________________________________________________________________________________
OCI_DB_LAKEHOUSE_SQL    ENABLED    NL2SQL profile for Data Catalog external data joined with ADB document governanc

基本Attributeを確認します。

SQL
SELECT
    attribute_name,
    DBMS_LOB.SUBSTR(
        attribute_value,
        1000,
        1
    ) AS attribute_value
FROM
    user_cloud_ai_profile_attributes
WHERE
    profile_name = 'OCI_DB_LAKEHOUSE_SQL'
ORDER BY
    attribute_name;
SQL実行結果
ATTRIBUTE_NAME        ATTRIBUTE_VALUE
_____________________ ______________________________________________________________________________________
credential_name       OCI$RESOURCE_PRINCIPAL
model                 cohere.command-a-03-2025
object_list           [{"owner":"RAG_USER","name":"V_DOCUMENT_LAKEHOUSE"}]
oci_compartment_id    <OCI-Generative-AI-Compartment-OCID>
provider              oci
region                ap-osaka-1

6 rows selected.

● オプションAttributeを追加

最小構成のProfile作成が成功した後、オプションAttributeをSET_ATTRIBUTEで段階的に追加します。

この順序にすると、エラーが発生した場合に、どのAttributeが原因かを切り分けやすくなります。

・ Object Listの動作を設定

enforce_object_list = trueにすると、SQL生成でProfileのObject Listに登録したObjectだけを使用するよう制限できます。

SQL
BEGIN
    DBMS_CLOUD_AI.SET_ATTRIBUTE(
        profile_name    => 'OCI_DB_LAKEHOUSE_SQL',
        attribute_name  => 'object_list_mode',
        attribute_value => 'all'
    );

    DBMS_CLOUD_AI.SET_ATTRIBUTE(
        profile_name    => 'OCI_DB_LAKEHOUSE_SQL',
        attribute_name  => 'enforce_object_list',
        attribute_value => 'true'
    );
END;
/
SQL実行結果
PL/SQL procedure successfully completed.

・ コメントと制約を有効化

SQL
BEGIN
    DBMS_CLOUD_AI.SET_ATTRIBUTE(
        profile_name    => 'OCI_DB_LAKEHOUSE_SQL',
        attribute_name  => 'comments',
        attribute_value => 'true'
    );

    DBMS_CLOUD_AI.SET_ATTRIBUTE(
        profile_name    => 'OCI_DB_LAKEHOUSE_SQL',
        attribute_name  => 'constraints',
        attribute_value => 'true'
    );
END;
/
SQL実行結果
PL/SQL procedure successfully completed.

・ Modelパラメータを設定

SQL
BEGIN
    DBMS_CLOUD_AI.SET_ATTRIBUTE(
        profile_name    => 'OCI_DB_LAKEHOUSE_SQL',
        attribute_name  => 'temperature',
        attribute_value => '0.1'
    );

    DBMS_CLOUD_AI.SET_ATTRIBUTE(
        profile_name    => 'OCI_DB_LAKEHOUSE_SQL',
        attribute_name  => 'max_tokens',
        attribute_value => '2000'
    );
END;
/
SQL実行結果
PL/SQL procedure successfully completed.

・ 追加指示を設定

SQL
BEGIN
    DBMS_CLOUD_AI.SET_ATTRIBUTE(
        profile_name    => 'OCI_DB_LAKEHOUSE_SQL',
        attribute_name  => 'additional_instructions',
        attribute_value =>
            '回答は日本語で行ってください。文書の利用可否を判断するときは、RAG_ENABLEDだけでなくAPPROVAL_STATUSとAI_USE_ALLOWEDも確認してください。RAG_ENABLEDは1がtrue、0がfalseです。DOCUMENT_PRIORITYは数値が小さいほど優先度が高いものとして扱ってください。存在しない列や値を推測しないでください。'
    );
END;
/
SQL実行結果
PL/SQL procedure successfully completed.

● 最終的なAttributeを確認

SQL
SELECT
    attribute_name,
    DBMS_LOB.SUBSTR(
        attribute_value,
        2000,
        1
    ) AS attribute_value
FROM
    user_cloud_ai_profile_attributes
WHERE
    profile_name = 'OCI_DB_LAKEHOUSE_SQL'
ORDER BY
    attribute_name;
SQL実行結果
ATTRIBUTE_NAME             ATTRIBUTE_VALUE
__________________________ ________________________________________________________________________________________________________________________________________________________________________________________
additional_instructions    回答は日本語で行ってください。文書の利用可否を判断するときは、RAG_ENABLEDだけでなくAPPROVAL_STATUSとAI_USE_ALLOWEDも確認してください。RAG_ENABLEDは1がtrue、0がfalseです。DOCUMENT_PRIORITYは数値が小さいほど優先度が高いものとして扱ってください。存在しない列や値を推測しないでください。
comments                   true
constraints                true
credential_name            OCI$RESOURCE_PRINCIPAL
enforce_object_list        true
max_tokens                 2000
model                      cohere.command-a-03-2025
object_list                [{"owner":"RAG_USER","name":"V_DOCUMENT_LAKEHOUSE"}]
object_list_mode           all
oci_compartment_id         <OCI-Generative-AI-Compartment-OCID>
provider                   oci
region                     ap-osaka-1
temperature                0.1

13 rows selected.

ここまでで、Lakehouseの構造化データを検索するSQL用Profileの作成は完了です。

ProfileのSession設定は、次の検索節で各検索の直前に実行します。

● 追加したオプションAttributeの役割

ここでは、OCI_DB_LAKEHOUSE_SQL Profileへ設定したAttribute全体を整理したうえで、今回追加したオプションAttributeの役割を確認します。

今回のOCI_DB_LAKEHOUSE_SQLでは、最終的に13個のAttributeを設定しました。

これらは、役割ごとに次の5グループへ整理できます。

分類 Attribute 今回の値 役割
OCI Generative AI接続 provider oci 使用するAI Providerを指定
OCI Generative AI接続 credential_name OCI$RESOURCE_PRINCIPAL OCI Generative AIへ接続するときの認証情報を指定
OCI Generative AI接続 region ap-osaka-1 OCI Generative AIを利用するRegionを指定
OCI Generative AI接続 oci_compartment_id <OCI-Generative-AI-Compartment-OCID> OCI Generative AIを利用するCompartmentを指定
OCI Generative AI接続 model cohere.command-a-03-2025 NL2SQLや回答生成に使用するLLMを指定
NL2SQL対象 object_list RAG_USER.V_DOCUMENT_LAKEHOUSE NL2SQLの対象とするDatabase Objectを指定
NL2SQL対象 object_list_mode all object_list内のObject MetadataをすべてLLMへ渡す
NL2SQL対象 enforce_object_list true SQL生成で使用するObjectをobject_list内へ制限
Metadata拡張 comments true Table/View、Columnに設定したCommentをLLMへ渡す
Metadata拡張 constraints true Primary Key、Foreign KeyなどのConstraint情報をLLMへ渡す
LLM生成設定 temperature 0.1 LLMの出力のランダム性を低くし、SQL生成を安定させる
LLM生成設定 max_tokens 2000 1回の生成で出力できる最大Token数を指定
業務ルール additional_instructions 日本語の追加指示 文書利用可否、優先度、回答言語などの判断ルールを追加

このうち、Profile作成時に設定した基本Attributeは次の6個です。

provider
credential_name
region
oci_compartment_id
model
object_list

その後、NL2SQLの精度、検索範囲、安全性、業務ルールを補強するため、次の7個のオプションAttributeを追加しました。

object_list_mode
enforce_object_list
comments
constraints
temperature
max_tokens
additional_instructions

Profile全体を役割で見ると、次の構成になります。

OCI_DB_LAKEHOUSE_SQL
│
├─ OCI Generative AI接続
│   ├─ provider
│   ├─ credential_name
│   ├─ region
│   ├─ oci_compartment_id
│   └─ model
│
├─ NL2SQL対象
│   ├─ object_list
│   ├─ object_list_mode
│   └─ enforce_object_list
│
├─ Metadata拡張
│   ├─ comments
│   └─ constraints
│
├─ LLM生成設定
│   ├─ temperature
│   └─ max_tokens
│
└─ 業務ルール
    └─ additional_instructions

以降では、今回追加した7個のオプションAttributeについて詳しく確認します。

object_list_mode = all

object_list_modeは、object_listに登録したDatabase ObjectのMetadataをLLMへどのように渡すかを指定します。

今回のProfileでは、次のViewだけをNL2SQL対象として登録しています。

[
    {
        "owner": "RAG_USER",
        "name": "V_DOCUMENT_LAKEHOUSE"
    }
]

今回は対象Objectが1つだけなので、allを指定し、このViewのMetadataをすべてLLMへ渡す構成にしています。

object_list
  └─ RAG_USER.V_DOCUMENT_LAKEHOUSE
              │
              │ object_list_mode = all
              ▼
   ViewのMetadataをLLMへ渡す

TableやViewが多数存在する環境では、質問に関連するObjectを絞り込む構成も考えられますが、今回のように公開するViewを1つへ限定した構成では、allが分かりやすくなります。

enforce_object_list = true

enforce_object_listは、Select AIがSQLを生成するときに、object_listへ登録したObjectだけを使用させるための設定です。

今回のProfileでは、次のように設定しています。

object_list
  └─ V_DOCUMENT_LAKEHOUSE

enforce_object_list = true

このため、Select AIにはLakehouse統合ViewだけをNL2SQL対象として公開します。

V_DOCUMENT_LAKEHOUSE
        │
        ├─ 使用可能
        │
        ▼
      Select AI

DOCUMENT_GOVERNANCE
DCAT$...DOCUMENT_INVENTORY
OCI_DB_MANUAL_IDX$VECTAB
        │
        └─ SQL用Profileから直接使用させない

Data Catalog同期で作成されたProtected SchemaやVector Tableを直接NL2SQL対象へ含めず、業務的に利用しやすいViewだけを公開することで、検索対象を分かりやすく限定できます。

comments = true

commentstrueにすると、Table/ViewやColumnへ設定したCommentをNL2SQL用MetadataとしてLLMへ渡せます。

今回、V_DOCUMENT_LAKEHOUSEには次のようなCommentを設定しました。

COMMENT ON COLUMN V_DOCUMENT_LAKEHOUSE.RAG_ENABLED IS
'文書インベントリでRAG対象として管理されているかを示す値。ParquetのBOOLはExternal TableでNUMBER(1)へマッピングされ、1がtrue、0がfalse';

COMMENT ON COLUMN V_DOCUMENT_LAKEHOUSE.APPROVAL_STATUS IS
'ADBの業務表で管理するAI利用レビュー状態。APPROVED、REVIEW、BLOCKED、NOT_REVIEWED';

COMMENT ON COLUMN V_DOCUMENT_LAKEHOUSE.DOCUMENT_PRIORITY IS
'数値が小さいほど利用優先度が高い';

Column名だけでは分かりにくい業務的な意味を、Commentを使ってLLMへ補足できます。

DOCUMENT_PRIORITY
        │
        │ comments = true
        ▼
「数値が小さいほど利用優先度が高い」
        │
        ▼
      LLM

今回のように、Data LakeのMetadataとADBの業務データを統合したViewを自然言語から検索する場合、Columnの意味を明示することはNL2SQLの精度向上に役立ちます。

constraints = true

constraintstrueにすると、Primary KeyやForeign KeyなどのConstraint情報をLLMへ渡せます。

例えば複数Tableを直接object_listへ登録する場合は、Foreign Key情報からTable間の関係を理解し、JOIN条件を生成する助けになります。

TABLE_A
  PK: document_id
        │
        │ Foreign Key
        ▼
TABLE_B
  FK: document_id

ただし、今回のobject_listには完成済みのV_DOCUMENT_LAKEHOUSEだけを登録しています。

Data LakeとRDBMSのJOINはView内部ですでに実装されているため、今回の構成ではconstraintsよりも、commentsadditional_instructionsの方がNL2SQLへ与える影響は大きくなります。

temperature = 0.1

temperatureは、LLMが回答やSQLを生成するときのランダム性を調整します。

一般的には、値を低くすると出力が安定し、高くすると回答のバリエーションが大きくなります。

今回の用途はCreativeな文章生成ではなく、自然言語から安定してSQLを生成するNL2SQLです。

そのため、低めの値として0.1を設定しました。

temperature 高め
  → 出力のバリエーションが大きい

temperature 低め
  → 出力が安定しやすい
  → NL2SQL向き

今回
  temperature = 0.1

max_tokens = 2000

max_tokensは、1回のLLM呼出しで生成できる最大Token数を指定します。

今回のProfileでは次の値を設定しました。

max_tokens = 2000

これは「必ず2000 Token生成する」という意味ではなく、生成可能な上限値です。

SHOWSQLで生成するSQLや、NARRATEで生成する説明が途中で切れにくいように、ある程度余裕を持たせています。

additional_instructions

additional_instructionsは、このProfileを使用するときに毎回LLMへ追加する指示です。

今回、次の内容を設定しました。

回答は日本語で行ってください。
文書の利用可否を判断するときは、RAG_ENABLEDだけでなく
APPROVAL_STATUSとAI_USE_ALLOWEDも確認してください。
RAG_ENABLEDは1がtrue、0がfalseです。
DOCUMENT_PRIORITYは数値が小さいほど優先度が高いものとして扱ってください。
存在しない列や値を推測しないでください。

この内容は、主に次の5つのルールをLLMへ伝えています。

指示 目的
回答は日本語 回答言語を固定
RAG_ENABLEDだけで利用可否を判断しない Data Lake側のRAG対象設定だけでAI利用可能と判断することを防ぐ
APPROVAL_STATUSAI_USE_ALLOWEDも確認 ADB側のガバナンス情報を利用可否の判断へ含める
DOCUMENT_PRIORITYは小さいほど優先 数値の業務的な意味を伝える
存在しない列や値を推測しない Metadataに存在しない情報を補完しないよう指示

今回のLakehouseでは、同じ文書に対して次の3種類の状態を持ちます。

RAG_ENABLED
  → Data Lakeの文書インベントリ上でRAG対象か

APPROVAL_STATUS
  → ADBのガバナンス表で承認済みか

AI_USE_ALLOWED
  → AIから利用してよいか

例えば、Oracle AI Database Installation Guide for Linuxは次の状態です。

RAG_ENABLED      = 1
APPROVAL_STATUS  = REVIEW
AI_USE_ALLOWED   = N

この文書は文書インベントリ上ではRAG対象ですが、業務上はまだAI利用が承認されていません。

そのため、

RAG_ENABLED = 1

だけを見て「AI利用可能」と判断しないように、additional_instructionsへ業務ルールを設定しています。

commentsadditional_instructionsの違い

今回のProfileでは、commentsadditional_instructionsの両方を使用しています。

役割は次のように分けられます。

comments
  → Table/Columnそのものの意味をLLMへ伝える

additional_instructions
  → そのMetadataを使って、
     LLMがどのように判断すべきかを伝える

例えば、DOCUMENT_PRIORITYについては、Column Commentで次の意味を伝えます。

数値が小さいほど利用優先度が高い

一方、additional_instructionsでは、文書利用可否の判断方法として、

RAG_ENABLEDだけで判断せず、
APPROVAL_STATUSとAI_USE_ALLOWEDも確認する

という業務ルールを設定します。

object_list_modeenforce_object_listの違い

この2つも似ていますが、役割が異なります。

object_list_mode = all
  → object_list内のObject Metadataを
     どのようにLLMへ渡すか

enforce_object_list = true
  → 生成するSQLで
     object_list外のObjectを使用させるか

今回の設定を図にすると、次のようになります。

object_list
  └─ V_DOCUMENT_LAKEHOUSE
            │
            ├─ object_list_mode = all
            │       │
            │       └─ ViewのMetadataをすべてLLMへ渡す
            │
            └─ enforce_object_list = true
                    │
                    └─ SQLもこのViewだけを対象にする

これにより、単にV_DOCUMENT_LAKEHOUSEをLLMへ公開するだけではなく、

どのObjectを検索してよいか
        +
各Columnが何を意味するか
        +
どのような業務ルールで判断するか

までProfile側で明示したうえで、Select AIのNL2SQLを実行できるようにしています。

■ Select AIでLakehouseを検索

以降のSELECT AIはSQLclから実行します。

NARRATEなどのCLOB結果が途中で切れないように、最初に表示設定を行います。

SQLcl
SET LONG 100000
SET LONGCHUNKSIZE 100000
SET LINESIZE 32767
SET PAGESIZE 50000

今回使用するProfileと検索先を整理します。

検索 直前に設定するProfile 主な検索先
構造化データのSHOWSQLSELECT AINARRATE OCI_DB_LAKEHOUSE_SQL V_DOCUMENT_LAKEHOUSE
PDF本文のSELECT AI NARRATE OCI_DB_MANUAL_RAG OCI_DB_MANUAL_IDX$VECTAB
DBMS_CLOUD_AI.GENERATE profile_name引数で明示 指定したProfileの検索先

SELECT AIはSessionに設定されているProfileを使用します。

本稿では迷わないように、各検索の直前にSET_PROFILEGET_PROFILEを実行します。

● 構造化検索1:承認済み文書の生成SQLを確認

・ 直前にSQL用Profileを設定

SQL
BEGIN
    DBMS_CLOUD_AI.SET_PROFILE(
        profile_name => 'OCI_DB_LAKEHOUSE_SQL'
    );
END;
/
SQL実行結果
PL/SQL procedure successfully completed.
SQL
SELECT
    DBMS_CLOUD_AI.GET_PROFILE AS current_profile
FROM
    dual;
SQL実行結果
CURRENT_PROFILE
____________________________________
"RAG_USER"."OCI_DB_LAKEHOUSE_SQL"

・ 生成SQLを確認

Data Lakeのrag_enabledと、ADB内部表のapproval_statusai_use_allowedを組み合わせて質問します。

SQL
SELECT AI SHOWSQL
Oracle AI Database 26aiの文書のうち、
文書インベントリでRAG対象になっていて、
ADBのガバナンス表でAI利用が承認されている文書を、
優先度の高い順に表示してください。
文書ID、文書タイトル、カテゴリ、公式URL、レビュー担当を含めてください;
SQL実行結果
RESPONSE
___________________________________________________
SELECT
    dl."DOCUMENT_ID" AS "文書ID",
    dl."DOCUMENT_TITLE" AS "文書タイトル",
    dl."CATEGORY" AS "カテゴリ",
    dl."OFFICIAL_URL" AS "公式URL",
    dl."REVIEW_OWNER" AS "レビュー担当"
FROM
    "RAG_USER"."V_DOCUMENT_LAKEHOUSE" dl
WHERE
    UPPER(dl."PRODUCT_VERSION") = '26AI'
    AND dl."RAG_ENABLED" = 1
    AND UPPER(dl."APPROVAL_STATUS") = 'APPROVED'
    AND UPPER(dl."AI_USE_ALLOWED") = 'Y'
ORDER BY
    dl."DOCUMENT_PRIORITY" ASC

生成SQLで、次を確認します。

検索先             = V_DOCUMENT_LAKEHOUSE
PRODUCT_VERSION    = 26ai
RAG_ENABLED        = 1
APPROVAL_STATUS    = APPROVED
AI_USE_ALLOWED     = Y
並び順             = DOCUMENT_PRIORITYの昇順

・ 比較用の基準SQL

SQL
SELECT
    document_id,
    document_title,
    category,
    official_url,
    review_owner,
    document_priority
FROM
    V_DOCUMENT_LAKEHOUSE
WHERE
    product_version = '26ai'
AND rag_enabled = 1
AND approval_status = 'APPROVED'
AND ai_use_allowed = 'Y'
ORDER BY
    document_priority;
SQL実行結果
DOCUMENT_ID             DOCUMENT_TITLE                    CATEGORY                   OFFICIAL_URL                                                                      REVIEW_OWNER                 DOCUMENT_PRIORITY
_______________________ _________________________________ __________________________ _________________________________________________________________________________ _________________________ ____________________
oracle_db_26ai_vecse    AI Vector Search User's Guide     ai_and_machine_learning    https://docs.oracle.com/en/database/oracle/oracle-database/26/vecse/index.html    ai_platform_team                             5
oracle_db_26ai_admin    Database Administrator's Guide    administration             https://docs.oracle.com/en/database/oracle/oracle-database/26/admin/index.html    database_platform_team                      10
oracle_db_26ai_cncpt    Database Concepts                 architecture               https://docs.oracle.com/en/database/oracle/oracle-database/26/cncpt/index.html    architecture_team                           30

● 構造化検索2:承認済み文書をSelect AIで取得

・ 直前にSQL用Profileを設定

SQL
BEGIN
    DBMS_CLOUD_AI.SET_PROFILE(
        profile_name => 'OCI_DB_LAKEHOUSE_SQL'
    );
END;
/
SQL
SELECT
    DBMS_CLOUD_AI.GET_PROFILE AS current_profile
FROM
    dual;
確認結果
"RAG_USER"."OCI_DB_LAKEHOUSE_SQL"

・ SQLを実行

SQL
SELECT AI
Oracle AI Database 26aiの文書のうち、
文書インベントリでRAG対象になっていて、
ADBのガバナンス表でAI利用が承認されている文書を、
優先度の高い順に表示してください。
文書ID、文書タイトル、カテゴリ、公式URL、レビュー担当を含めてください;
SQL実行結果
文書ID                    文書タイトル                            カテゴリ                       公式URL                                                                             レビュー担当
_______________________ _________________________________ __________________________ _________________________________________________________________________________ _________________________
oracle_db_26ai_vecse    AI Vector Search User's Guide     ai_and_machine_learning    https://docs.oracle.com/en/database/oracle/oracle-database/26/vecse/index.html    ai_platform_team
oracle_db_26ai_admin    Database Administrator's Guide    administration             https://docs.oracle.com/en/database/oracle/oracle-database/26/admin/index.html    database_platform_team
oracle_db_26ai_cncpt    Database Concepts                 architecture               https://docs.oracle.com/en/database/oracle/oracle-database/26/cncpt/index.html    architecture_team

● 構造化検索3:SQL結果を自然言語で説明

・ 直前にSQL用Profileを設定

SQL
BEGIN
    DBMS_CLOUD_AI.SET_PROFILE(
        profile_name => 'OCI_DB_LAKEHOUSE_SQL'
    );
END;
/
SQL
SELECT
    DBMS_CLOUD_AI.GET_PROFILE AS current_profile
FROM
    dual;
確認結果
"RAG_USER"."OCI_DB_LAKEHOUSE_SQL"

・ NARRATEを実行

SQL
SELECT AI NARRATE
Oracle AI Database 26aiの文書について、
RAG対象かつAI利用が承認されている文書を整理し、
どの文書から検証を開始すべきかを優先度とともに日本語で説明してください;
SQL実行結果(冒頭を抜粋)
Oracle AI Database 26aiの文書のうち、RAG対象でAI利用が承認されているものを優先度順に整理しました。
...

ここでは、Data Lake外部表とADB内部表をJOINしたSQL結果がLLMへ送られ、自然言語の回答が生成されます。

● 構造化検索4:レビュー中またはAI利用不可の文書を確認

最初に基準SQLで、対象データが1件存在することを確認します。

SQL
SELECT
    document_id,
    document_title,
    approval_status,
    ai_use_allowed,
    review_owner,
    notes
FROM
    V_DOCUMENT_LAKEHOUSE
WHERE
    product_version = '26ai'
AND (
       approval_status IN ('REVIEW', 'BLOCKED')
    OR ai_use_allowed = 'N'
)
ORDER BY
    document_priority;
SQL実行結果
DOCUMENT_ID           DOCUMENT_TITLE                                      APPROVAL_STATUS  AI_USE_ALLOWED  REVIEW_OWNER         NOTES
--------------------  --------------------------------------------------  ---------------  --------------  -------------------  ----------------------------------------
oracle_db_26ai_ladbi  Oracle AI Database Installation Guide for Linux    REVIEW           N               infrastructure_team  Agent利用前に内容と運用手順を再確認

・ SHOWSQLの直前にSQL用Profileを設定

SQL
BEGIN
    DBMS_CLOUD_AI.SET_PROFILE(
        profile_name => 'OCI_DB_LAKEHOUSE_SQL'
    );
END;
/
SQL
SELECT
    DBMS_CLOUD_AI.GET_PROFILE AS current_profile
FROM
    dual;
SQL実行結果
CURRENT_PROFILE
____________________________________
"RAG_USER"."OCI_DB_LAKEHOUSE_SQL"

・ 生成SQLを確認

SQL
SELECT AI SHOWSQL
Oracle AI Database 26aiの文書のうち、
APPROVAL_STATUSREVIEWまたはBLOCKED
もしくはAI_USE_ALLOWEDNの文書を表示してください。
文書ID、文書タイトル、承認状態、AI利用可否、
レビュー担当、備考を含めてください;
SQL実行結果
RESPONSE
_________________________________________________________________________________________________________
SELECT
    dl."DOCUMENT_ID" AS "文書ID",
    dl."DOCUMENT_TITLE" AS "文書タイトル",
    dl."APPROVAL_STATUS" AS "承認状態",
    dl."AI_USE_ALLOWED" AS "AI利用可否",
    dl."REVIEW_OWNER" AS "レビュー担当",
    dl."NOTES" AS "備考"
FROM
    "RAG_USER"."V_DOCUMENT_LAKEHOUSE" dl
WHERE
    (dl."APPROVAL_STATUS" = 'REVIEW' OR dl."APPROVAL_STATUS" = 'BLOCKED' OR dl."AI_USE_ALLOWED" = 'N')
    AND dl."PRODUCT_VERSION" = '26ai'

OR条件が括弧でまとめられ、その後にPRODUCT_VERSION = '26ai'が適用されていることを確認します。

また、検索先が次のViewであることを確認します。

RAG_USER.V_DOCUMENT_LAKEHOUSE

生成SQLがOCI_DB_MANUAL_IDX$VECTABを参照している場合は、RAG用Profileが有効です。検索を実行せず、SQL用Profileへ設定し直します。

・ SELECT AIの直前にSQL用Profileをもう一度設定

SHOWSQLの後に別のProfileへ切り替わっていないことを確実にするため、実行直前にも設定します。

SQL
BEGIN
    DBMS_CLOUD_AI.SET_PROFILE(
        profile_name => 'OCI_DB_LAKEHOUSE_SQL'
    );
END;
/
SQL
SELECT
    DBMS_CLOUD_AI.GET_PROFILE AS current_profile
FROM
    dual;
確認結果
"RAG_USER"."OCI_DB_LAKEHOUSE_SQL"

・ Select AIから実行

SQL
SELECT AI
Oracle AI Database 26aiの文書のうち、
APPROVAL_STATUSREVIEWまたはBLOCKED
もしくはAI_USE_ALLOWEDNの文書を表示してください。
文書ID、文書タイトル、承認状態、AI利用可否、
レビュー担当、備考を含めてください;
SQL実行結果
文書ID                    文書タイトル                                             承認状態      AI利用可否    レビュー担当                 備考
_______________________ __________________________________________________ _________ _________ ______________________ _______________________
oracle_db_26ai_ladbi    Oracle AI Database Installation Guide for Linux    REVIEW    N         infrastructure_team    Agent利用前に内容と運用手順を再確認

これにより、SQL用Profileを明示的に設定した状態で、レビュー中またはAI利用不可の文書を1件取得できました。

■ Database Actionsから実行する場合

SELECT AIAI Keywordは、Database ActionsおよびAPEX Serviceでは使用できません。

Database ActionsのSQL Worksheetから実行する場合は、DBMS_CLOUD_AI.GENERATEを使用します。

DBMS_CLOUD_AI.GENERATEでは、各呼出しのprofile_nameへ使用するProfileを明示します。そのため、Sessionに設定されたProfileへ依存しません。

● SHOWSQL相当

SQL
SELECT
    DBMS_LOB.SUBSTR(
        DBMS_CLOUD_AI.GENERATE(
            prompt       => q'[
Oracle AI Database 26aiの文書のうち、
RAG対象かつAI利用が承認されている文書を、
優先度の高い順に表示してください。
文書ID、文書タイトル、カテゴリ、公式URL、
レビュー担当を含めてください。
]',
            profile_name => 'OCI_DB_LAKEHOUSE_SQL',
            action       => 'showsql'
        ),
        32767,
        1
    ) AS response
FROM
    dual;
SQL実行結果
RESPONSE
___________________________________________________
SELECT
    dl."DOCUMENT_ID" AS "文書ID",
    dl."DOCUMENT_TITLE" AS "文書タイトル",
    dl."CATEGORY" AS "カテゴリ",
    dl."OFFICIAL_URL" AS "公式URL",
    dl."REVIEW_OWNER" AS "レビュー担当"
FROM
    "RAG_USER"."V_DOCUMENT_LAKEHOUSE" dl
WHERE
    UPPER(dl."PRODUCT_VERSION") = '26AI'
    AND dl."RAG_ENABLED" = 1
    AND UPPER(dl."APPROVAL_STATUS") = 'APPROVED'
    AND UPPER(dl."AI_USE_ALLOWED") = 'Y'
ORDER BY
    dl."DOCUMENT_PRIORITY" ASC

● NARRATE相当

SQL
SELECT
    DBMS_LOB.SUBSTR(
        DBMS_CLOUD_AI.GENERATE(
            prompt       => q'[
Oracle AI Database 26aiの文書について、
RAG対象かつAI利用が承認されている文書を整理し、
どの文書から検証を開始すべきかを日本語で説明してください。
]',
            profile_name => 'OCI_DB_LAKEHOUSE_SQL',
            action       => 'narrate'
        ),
        32767,
        1
    ) AS response
FROM
    dual;
SQL実行結果(冒頭を抜粋)
Oracle AI Database 26aiの文書のうち、RAG対象でAI利用が承認されているものは、以下の3つです。
...

参考: Use AI Keyword to Enter Prompts

■ Select AI with RAGへ切り替える

構造化データの検索によって、AI利用が承認され、優先度が最も高い文書としてAI Vector Search User's Guideを確認できました。

次に、第3回で作成したRAG Profileへ切り替え、PDF本文へ質問します。

● RAG検索の直前にRAG Profileを設定

SQL
BEGIN
    DBMS_CLOUD_AI.SET_PROFILE(
        profile_name => 'OCI_DB_MANUAL_RAG'
    );
END;
/
SQL実行結果
PL/SQL procedure successfully completed.
SQL
SELECT
    DBMS_CLOUD_AI.GET_PROFILE AS current_profile
FROM
    dual;
SQL実行結果
CURRENT_PROFILE
_________________________________
"RAG_USER"."OCI_DB_MANUAL_RAG"

● 選択した文書の本文へ質問

SQL
SELECT AI NARRATE
AI Vector Searchユーザーズ・ガイドの記載に基づき、
HNSW索引とIVF索引の違いを、
索引構造、検索特性、更新時の考慮点が分かるように日本語で説明してください。
取得した資料に記載されていないことは推測しないでください;

回答本文に加えて、AI Vector Search User's GuideのOracle公式URLがSourcesへ表示されることを確認します。

SQL実行結果(抜粋)
HNSW索引とIVF索引の違いは以下の通りです。

索引構造
- HNSW索引:階層的なナビゲーション可能な小世界グラフを使用します。
- IVF索引:インバーテッドファイル構造を使用し、ベクトルをクラスタリングして索引を作成します。

Sources:
- vector_search/ai-vector-search-users-guide.pdf
  https://docs.oracle.com/en/database/oracle/oracle-database/26/vecse/ai-vector-search-users-guide.pdf

● Database ActionsからRAGを実行

profile_nameへRAG用Profileを明示するため、SessionのProfileには依存しません。

SQL
SELECT
    DBMS_LOB.SUBSTR(
        DBMS_CLOUD_AI.GENERATE(
            prompt       => q'[
AI Vector Search User's Guideの記載に基づき、
HNSW索引とIVF索引の違いを日本語で説明してください。
資料に記載されていないことは推測しないでください。
]',
            profile_name => 'OCI_DB_MANUAL_RAG',
            action       => 'narrate'
        ),
        32767,
        1
    ) AS response
FROM
    dual;

● RAG検索後にSQL用Profileへ戻す

後続の構造化検索を誤ってVector Storeへ実行しないように、検証の最後にSQL用Profileへ戻します。

SQL
BEGIN
    DBMS_CLOUD_AI.SET_PROFILE(
        profile_name => 'OCI_DB_LAKEHOUSE_SQL'
    );
END;
/
SQL
SELECT
    DBMS_CLOUD_AI.GET_PROFILE AS current_profile
FROM
    dual;
確認結果
"RAG_USER"."OCI_DB_LAKEHOUSE_SQL"

■ 第4回で実現できた検索フロー

今回の検索フローを整理します。

ユーザーの質問
  「AI利用が承認されている26ai文書はどれか」
        ↓
OCI_DB_LAKEHOUSE_SQL
        ↓
V_DOCUMENT_LAKEHOUSE
        ↓
Data Lake外部表+ADB内部表をJOIN
        ↓
AI Vector Search User's Guideを選択
        ↓
OCI_DB_MANUAL_RAGへ切替
        ↓
OCI_DB_MANUAL_IDX$VECTABをSemantic Search
        ↓
PDF本文を根拠に回答

第4回では、人がProfileを切り替え、構造化検索の結果を次のRAG質問へ引き継いでいます。

■ なぜ1つのProfileへすべて登録しないのか

narrateは、SQL生成用ProfileではSQL実行結果を、Vector Indexを設定したRAG用ProfileではSemantic Searchの取得結果をLLMへ渡します。SQL用ProfileへVector Indexも設定しても、Data Lake+RDBMSのSQL結果とPDFの検索結果が自動的に1つへ統合されるわけではありません。

また、Vector TableのCONTENTEMBEDDINGをNL2SQLのobject_listへ直接登録すると、次の問題が発生します。

  • Metadata量が増える
  • LLMが巨大なチャンク表を通常表として選択する可能性がある
  • Embedding列を通常の業務列として扱う可能性がある
  • Select AIへ公開するObject範囲が広くなる
  • SQL検索とRAG検索の責任範囲が不明確になる

そのため、今回は次のように責任を分離しました。

OCI_DB_LAKEHOUSE_SQL
  object_list = V_DOCUMENT_LAKEHOUSE
  用途        = 構造化データの検索、JOIN、集計

OCI_DB_MANUAL_RAG
  vector_index_name = OCI_DB_MANUAL_IDX
  用途              = PDF本文のSemantic Search、回答生成

この2つを自動的に選択して連携する処理が、次回以降のAI Agentの役割になります。

■ 第4回で構築したLakehouse

今回の構成は、単にData Lake上のParquetをSQLで参照するだけではありません。

Data Lake
  Object Storage上のParquet
        +
RDBMS
  ADB内部の業務・ガバナンス表
        +
Vector Store
  PDF本文のチャンクとEmbedding
        +
Generative AI
  NL2SQL、RAG、自然言語回答

これらをAutonomous AI Database上で統合したことで、構造化データと非構造化データをAIから利用するためのLakehouse基盤を作成できました。

■ 運用上の考慮点

● Data Catalog同期Schemaを直接変更しない

Data Catalog同期で生成されたDCAT$...Schemaは、同期処理によって管理されます。

列名や型などを変更する場合はData Catalog側のMetadataやCustom Propertiesを更新し、再同期します。

ローカルで利用しやすい名前や業務ルールは、今回のようにViewで吸収します。

● Select AIへ公開するObjectを限定

object_listには、利用者へ公開するViewだけを登録します。

今回はenforce_object_list = trueを設定し、Select AIがProfile外のObjectを使用しないようにしています。

NARRATEで外部AI Providerへ送られるデータを確認

NL2SQLのMetadata拡張では、Table名、Column名、型、コメントなどがAI Providerへ送信されます。

narrateでは、SQL実行結果またはVector Storeから取得したチャンクもLLMへ送信されます。

機密データを扱う場合は、次を検討します。

  • Public文書とInternal文書のVector Index分離
  • Database UserとProfileの分離
  • Object Storage Bucket/Prefixの分離
  • object_listの最小化
  • 機密列を含まないViewの作成
  • AI Provider、Model、Region、データ保持条件の確認

● 大規模なExternal TableではLake Cacheを検討

今回の文書インベントリは10行のため、Performance対策は不要です。

将来、Data Lake上の大規模なParquetやIceberg表を繰り返し検索する場合は、Lake Cache、Data Lake Accelerator、Implicit Partitioningなどを検討できます。

参考: Use Lakehouse with Autonomous AI Database

■ トラブルシューティング

PLS-00684: invalid data type for the JSON return value

CREATE_PROFILEattributesJSON_OBJECT(... RETURNING CLOB)を直接指定したところ、今回の環境ではPL/SQLコンパイル時にPLS-00684になりました。

今回のProfile属性は小さいため、RETURNING CLOBへ依存せず、q'~{...}~'形式のJSON文字列を使用します。

ORA-20046: Profile attributes are not in valid JSON format

q'~{...}~'の中へ次のようなJSON_OBJECT用構文を混在させると、JSONとして無効になります。

誤り:  'oci_compartment_id' VALUE 'ocid1.compartment...'
正しい: "oci_compartment_id": "ocid1.compartment..."

CREATE_PROFILEの前にIS JSON STRICTVALID JSONになることを確認します。

ORA-01031: insufficient privilegesでViewを作成できない

RAG_USERにはCREATE VIEWシステム権限と、同期External Tableに対する直接のREAD権限が必要です。Role経由ではなく、Object権限をユーザー本人へ付与します。

SQL
GRANT CREATE VIEW TO RAG_USER;

GRANT READ
ON "<DCAT-schema-name>"."DOCUMENT_INVENTORY"
TO RAG_USER;

ORA-20012: Connection identifier ... already exists

同じConnection IDでSET_DATA_CATALOG_CONNを再実行した場合に発生します。接続確認SQLで既存行が表示される場合は、接続を作り直さず、そのまま同期へ進みます。

● Select AIでレビュー中の文書が0件になる

自然言語の「未承認」が、実データに存在しない状態値へ変換される場合があります。まず基準SQLで対象行を確認し、SELECT AI SHOWSQLで生成条件を確認します。必要に応じてAPPROVAL_STATUS IN ('REVIEW','BLOCKED')AI_USE_ALLOWED = 'N'をプロンプトへ明示します。

PLS-00306SET_DATA_CATALOG_CREDENTIALを呼び出せない

今回の環境では、次のようにdcat_con_idだけを指定すると、PLS-00306が発生しました。

BEGIN
    DBMS_DCAT.SET_DATA_CATALOG_CREDENTIAL(
        dcat_con_id => 'OCI_DCAT_BLOG_01'
    );
END;
/

この場合は、Resource PrincipalのCredential名も明示します。

SQL
BEGIN
    DBMS_DCAT.SET_DATA_CATALOG_CREDENTIAL(
        credential_name => 'OCI$RESOURCE_PRINCIPAL',
        dcat_con_id     => 'OCI_DCAT_BLOG_01'
    );
END;
/

Databaseに実装されている引数定義は、ALL_ARGUMENTSから確認できます。

SQL
SELECT
    owner,
    overload,
    position,
    sequence,
    argument_name,
    data_type,
    in_out,
    defaulted
FROM
    all_arguments
WHERE
    package_name = 'DBMS_DCAT'
AND object_name = 'SET_DATA_CATALOG_CREDENTIAL'
ORDER BY
    owner,
    overload,
    sequence;

OracleのドキュメントとDatabaseに実装されているPackage Signatureに差がある場合は、実際のDatabaseで確認した引数定義を優先します。

ORA-20000:Data catalog credential not set

SET_DATA_CATALOG_CONNを先に実行すると、次のエラーになる場合があります。

ORA-20000: Data catalog credential not set for connection with id
OCI_DCAT_BLOG_01

次の順序で実行します。

1. ENABLE_RESOURCE_PRINCIPAL
2. SET_DATA_CATALOG_CREDENTIAL
3. SET_OBJECT_STORE_CREDENTIAL
4. SET_DATA_CATALOG_CONN
5. ALL_DCAT_CONNECTIONSで確認

SET_DATA_CATALOG_CREDENTIALSET_OBJECT_STORE_CREDENTIALには、同じdcat_con_idを指定します。

ORA-00904: "DCAT_CON_ID": invalid identifier

今回の環境では、次のSQLでORA-00904が発生しました。

SELECT
    *
FROM
    all_dcat_connections
WHERE
    dcat_con_id = 'OCI_DCAT_BLOG_01';

Oracleの現行ドキュメントではALL_DCAT_CONNECTIONS.DCAT_CON_IDが定義されていますが、今回の接続先で実際に解決されたViewでは、この列名を参照できませんでした。原因を推測せず、DESCまたはALL_TAB_COLUMNSで実環境の定義を確認します。

実環境の列定義を確認します。

SQL
DESC ALL_DCAT_CONNECTIONS

または、次を実行します。

SQL
SELECT
    owner,
    column_id,
    column_name,
    data_type
FROM
    all_tab_columns
WHERE
    table_name = 'ALL_DCAT_CONNECTIONS'
ORDER BY
    owner,
    column_id;

接続が1件の場合は、列名で絞り込まず、次のSQLで確認できます。

SQL
SELECT
    *
FROM
    all_dcat_connections;

SET_DATA_CATALOG_CONNPL/SQL procedure successfully completed.で終了し、このSQLで接続行が表示されれば、接続登録は完了しています。Credentialや接続処理を作り直す必要はありません。

DCAT$...Schemaが作成されない

確認する項目です。

Data Catalog Connection
Resource Principal
OCI IAM Policy
Object Storage読取り権限
Data Catalog AssetのHarvest完了
Logical Entityの作成
DBMS_DCAT.RUN_SYNCのStatus
USER_LOAD_OPERATIONSのLog

ORA-00942: table or view does not exist

RAG_USERへExternal Tableの直接権限が付与されているか確認します。

SQL
SELECT
    owner,
    table_name,
    privilege,
    grantor
FROM
    user_tab_privs_recd
WHERE
    owner LIKE 'DCAT$%';

Role経由の権限だけでは、View作成時に参照できない場合があります。

● Vector StoreとのJOIN結果が0件

Data Lake側の完全Object名と、Vector Store側で再構成した完全Object名を比較します。

SQL
SELECT
    document_id,
    object_name,
    vector_object_name
FROM
    V_DOCUMENT_LAKEHOUSE
WHERE
    product_version = '26ai';
SQL
SELECT DISTINCT
    JSON_VALUE(
        attributes,
        '$.location_uri'
        RETURNING VARCHAR2(2000)
    ) AS vector_location_uri,
    JSON_VALUE(
        attributes,
        '$.object_name'
        RETURNING VARCHAR2(1000)
    ) AS vector_object_name,
    RTRIM(
        REGEXP_SUBSTR(
            JSON_VALUE(
                attributes,
                '$.location_uri'
                RETURNING VARCHAR2(2000)
            ),
            '/o/(.*)$',
            1,
            1,
            NULL,
            1
        ),
        '/'
    ) || '/' ||
    LTRIM(
        JSON_VALUE(
            attributes,
            '$.object_name'
            RETURNING VARCHAR2(1000)
        ),
        '/'
    ) AS vector_full_object_name
FROM
    OCI_DB_MANUAL_IDX$VECTAB
ORDER BY
    vector_object_name;

次の点を確認します。

  • Prefixの有無
  • 製品バージョンの表記
  • Directory名
  • PDFファイル名
  • ハイフンとアンダースコア
  • 大文字と小文字

特にObject Storage上の実ファイル名と、文書インベントリのobject_nameを一致させます。

今回の検証では、26ai Installation Guideだけ文書インベントリが旧ファイル名になっていたため、最初は3文書、8,857チャンクしかJOINできませんでした。

修正前: documents/oracle-database/26ai/installation_linux/database-installation-guide-linux.pdf
修正後: documents/oracle-database/26ai/installation_linux/oracle-ai-database-installation-guide-linux.pdf

Parquetを修正して同じObject名へ上書きした後、4文書、9,590チャンク、JOIN漏れ0件になりました。

object_uri<your-namespace>またはoci://が残る

第2回の生成スクリプトが旧版の場合、HTTPS URIではなくPlaceholderを含む値が生成されることがあります。Object Storageへアップロードする前にローカルParquetを検査し、ADB側でも次が0件になることを確認します。

SQL
SELECT COUNT(*) AS invalid_object_uri_count
FROM DOCUMENT_INVENTORY_EXT_V
WHERE object_uri LIKE '%<%'
   OR object_uri NOT LIKE 'https://%';

● Database ActionsでSELECT AIがエラーになる

Database ActionsではSELECT AI Keywordを使用せず、DBMS_CLOUD_AI.GENERATEを実行します。

また、Database ActionsではSET_PROFILEへ依存せず、profile_name引数を明示します。

● 構造化データの質問でVector Tableが検索される

構造化データの質問をSELECT AI SHOWSQLで確認したとき、生成SQLが次のVector Tableを参照する場合があります。

OCI_DB_MANUAL_IDX$VECTAB

また、生成SQL内のEmbedding作成で次のProfileが使用されている場合は、RAG用Profileが現在のSessionへ設定されています。

OCI_DB_MANUAL_RAG

構造化検索の直前に、SQL用Profileを明示的に設定します。

SQL
BEGIN
    DBMS_CLOUD_AI.SET_PROFILE(
        profile_name => 'OCI_DB_LAKEHOUSE_SQL'
    );
END;
/
SQL
SELECT
    DBMS_CLOUD_AI.GET_PROFILE AS current_profile
FROM
    dual;

次の結果を確認してから、SELECT AIを実行します。

"RAG_USER"."OCI_DB_LAKEHOUSE_SQL"

SQL用ProfileのSHOWSQLでは、検索先が次のViewになります。

RAG_USER.V_DOCUMENT_LAKEHOUSE

● RAGが意図しない文書を参照する

標準のSelect AI with RAGは、SQL用Viewのapproval_statusdocument_idを自動的にVector検索条件へ適用しません。

次の対策があります。

文書種別ごとにVector Indexを分ける
公開区分ごとにVector Indexを分ける
質問へ対象文書名を明示する
Custom SQL RAGでRelational Filterを適用する
Select AI AgentまたはPrivate Agent FactoryでToolを制御する

第4回では、構造化検索で対象文書を確認した後、文書名を明示してRAGを実行します。

■ リソースを削除

第5回以降で今回のLakehouseを再利用するため、基本的には削除せずに残します。

検証環境を削除する場合は、依存関係の逆順で削除します。

● SQL用Profileを削除

SQL
BEGIN
    DBMS_CLOUD_AI.DROP_PROFILE(
        profile_name => 'OCI_DB_LAKEHOUSE_SQL',
        force        => TRUE
    );
END;
/

● Vector統合Viewを削除

SQL
DROP VIEW V_DOCUMENT_VECTOR_CHUNKS;

● Lakehouse統合Viewを削除

SQL
DROP VIEW V_DOCUMENT_LAKEHOUSE;

● Data Lake参照Viewを削除

SQL
DROP VIEW DOCUMENT_INVENTORY_EXT_V;

● RDBMS表を削除

SQL
DROP TABLE DOCUMENT_GOVERNANCE PURGE;

Data Catalog接続、同期External Table、既存RAG Profile、Vector Indexは、第5回以降で再利用する場合は削除しません。

■ まとめ

今回は、第1回から第3回までに作成したデータ資産を再利用し、Autonomous AI Database上でLakehouseとして統合しました。

主な検証結果です。

確認項目 結果
Data Catalog同期 Logical EntityをExternal Tableとして参照
Data Lake+RDBMS 文書Metadataとガバナンス情報をdocument_idでJOIN
Vector Storeとの統合 4文書、9,590チャンクを完全Object名でJOIN
JOIN漏れ 0件
Select AI AI利用が承認された3文書をNL2SQLで検索
Select AI with RAG 選択したPDF本文を検索し、Oracle公式URLをSourceとして表示
Profile設計 SQL検索用とRAG検索用を分離

今回一番面白かったのは、Data CatalogのMetadataが、単なる「ファイルの一覧」ではなく、RDBMSの業務データとVector StoreのPDF本文を結び付ける設計情報になったことです。

Data Catalogは、Object Storageへファイルを入れるだけで、すべてを自動的に仕分けしてくれる魔法の箱ではありません。

document_idobject_name、製品バージョン、カテゴリ、RAG対象フラグなどを先に設計しておくことで、初めてRDBMSの承認情報やVector Storeのチャンクと正しく結び付けられます。

第1回  Data Lakeへデータを配置
   ↓
第2回  Metadataを設計してData Catalogで管理
   ↓
第3回  PDF本文をVector化してRAGへ対応
   ↓
第4回  Data Lake+RDBMS+Vector StoreをLakehouseとして統合

Object StorageにはParquetやPDFを置き、RDBMSには更新される業務ルールを持たせ、Vector Storeには本文のチャンクとEmbeddingを格納する。それぞれが得意な役割を残しながら、Oracle AI Databaseから同じSQLでつなげて利用できるところが、今回とても面白いと感じました。

Oracle Databaseを長く触ってきた人ほど、これまでのTableやView、JOINという考え方の先に、Data Lakeと非構造化データ、Vector Search、生成AIまでつながっていく構成には、グッとくるものがあると思います。

一方で、標準のSelect AIだけでは、構造化検索の結果とRAG検索の結果を1回の質問から自動的に統合できません。今回は人がProfileを切り替え、対象文書を次のRAG質問へ引き継ぎました。

この制約を確認できたことで、次にAI Agentへ任せる処理も明確になりました。

この時点で、AI Agentへ渡すための「データ」と「道具」は揃いました。

次回は、今回作成したLakehouseをAIDP Master Catalogへ登録し、より広いデータ基盤から発見、管理、利用できる形へ発展させてみてみたいです。

これで、AI Agentへ渡すための「道具」と「データ」が揃いました。

■ 次回以降

今後は、今回作成したLakehouseとデータ群をそのまま再利用し、AI Agent系の検証へ進みます。

予定
第5回 AIDP Master Catalogへ既存Lakehouseを登録し、AI-readyなデータ基盤へ発展
第6回 Private Agent FactoryからLakehouseのSQL検索とRAG検索を使い分け
第7回 Oracle APEX 26.1、APEX AI Agent、APEX Workflowから業務アプリ化
以降 Oracle AI Data CatalogとApache IcebergによるOpen Lakehouseへ発展

■ 解説

■ おまけ

おまけ2.jpg

■ 参考資料

■ 参考資料詳細

今回の第4回では、OCI Data CatalogのLogical EntityとAutonomous AI DatabaseのExternal Table連携、Resource Principal、DBMS_DCAT、Select AIのNL2SQL、AI Profile、Vector Index、Select AI with RAGまで複数の機能を組み合わせています。

実装内容と対応付けて確認しやすいように、Oracle公式ドキュメントを分野ごとに整理します。

● OCI Data Catalog/Data Lake

  • OCI Data Catalog

    • OCI Data Catalog全体のドキュメントです。
  • Harvesting Object Storage Files as Logical Data Entities

    • Object Storage上のファイルをFilename PatternでLogical EntityとしてまとめてHarvestする仕組みを確認できます。
    • 今回のdocument_inventory.parquetをLogical Entityとして扱う部分の参考資料です。
  • Query External Data with Data Catalog

    • OCI Data CatalogのMetadataをAutonomous AI Databaseから利用し、External TableとしてObject Storage上のデータを参照する構成を確認できます。
  • DBMS_DCAT Package

    • SET_DATA_CATALOG_CONNSET_DATA_CATALOG_CREDENTIALSET_OBJECT_STORE_CREDENTIALRUN_SYNCなど、Data CatalogとAutonomous AI Databaseを同期するためのDBMS_DCAT Packageを確認できます。
    • Data Catalog同期によってProtected SchemaとExternal Tableが作成される仕組みや、grant_read、同期用Dictionary Viewについても確認できます。
  • Use Lakehouse with Autonomous AI Database

    • Object Storage上のData LakeデータをAutonomous AI DatabaseからSQLで利用するLakehouse機能の概要を確認できます。
  • Parquet to Oracle Data Type Mapping

    • Parquetの型がAutonomous AI DatabaseのExternal TableでどのOracle Data Typeへマッピングされるかを確認できます。
    • 今回のrag_enabledで、ParquetのBoolean値をExternal Table側から確認する部分の参考資料です。

● Resource Principal/Object Storage

  • Use Resource Principal to Access Oracle Cloud Infrastructure Resources

    • Autonomous AI DatabaseからOCI Resource Principalを使用してOCI Serviceへアクセスする仕組みを確認できます。
    • 今回使用しているOCI$RESOURCE_PRINCIPALの参考資料です。
  • DBMS_CLOUD URI Formats

    • Autonomous AI DatabaseからObject Storageを参照するときに使用できるURI形式を確認できます。
    • 今回の文書インベントリで保持しているobject_uriの形式を確認するときの参考資料です。
  • Uploading an Object Storage Object to a Bucket

    • Object StorageへのObject UploadとUser-defined Metadataの設定方法を確認できます。
    • OCI CLIのoci os object put --metadataについても説明されています。

● Select AI/NL2SQL/AI Profile

  • About Select AI

    • Select AIの概要と、自然言語からSQLを生成・実行するNL2SQLの位置付けを確認できます。
  • Manage AI Profiles

    • DBMS_CLOUD_AI.CREATE_PROFILESET_PROFILEを使用したAI Profileの作成・管理方法を確認できます。
    • SELECT AIを実行するStateful Sessionでは、SessionごとにProfileを設定する必要があることも確認できます。
  • DBMS_CLOUD_AI Package

    • Select AIで使用するDBMS_CLOUD_AI Packageの詳細です。
    • 今回のOCI_DB_LAKEHOUSE_SQLで設定した次のProfile Attributeを確認できます。
provider
credential_name
region
oci_compartment_id
model
object_list
object_list_mode
enforce_object_list
comments
constraints
temperature
max_tokens
additional_instructions
  • CREATE_PROFILESET_ATTRIBUTESET_PROFILEGET_PROFILEGENERATEなど、今回使用したProcedure/Functionも確認できます。

  • RAG Profileで使用したenable_custom_source_uriについても説明されており、trueの場合はObject Storageのopc-meta-customized_url_source Metadata HeaderをSource URLとして使用する動作を確認できます。

  • Use AI Keyword to Enter Prompts

    • SELECT AI SHOWSQLSELECT AI NARRATEなど、AI Keywordを使用した自然言語Promptの実行方法を確認できます。
  • Examples of Using Select AI

    • Select AIによるNL2SQL、SHOWSQLNARRATEなどの実行例を確認できます。
  • Select your AI Provider and LLMs

    • Select AIで利用できるAI Provider、Chat Model、Embedding Modelを確認できます。
    • 今回使用しているcohere.command-a-03-2025cohere.embed-v4.0を確認する際の参考資料です。
  • Regional availability for Generative AI models

    • OCI Generative AI ModelのRegion別Availabilityを確認できます。
    • Modelの利用可能Regionは変更される可能性があるため、再検証時にはこのページで確認します。

● Vector Store/Select AI with RAG

  • Select AI with Retrieval Augmented Generation

    • Object Storage上のPDFなどを取得し、文書をText化、Chunk化、Embedding化してVector Storeへ格納し、Semantic SearchからRAG回答を生成するSelect AI with RAGの処理全体を確認できます。
    • 今回参照しているVector TableのCONTENTATTRIBUTESEMBEDDINGを理解するための中心的な参考資料です。
  • DBMS_CLOUD_AI Package - Vector Index

    • DBMS_CLOUD_AI.CREATE_VECTOR_INDEXとVector Index Attributeを確認できます。
    • locationchunk_sizechunk_overlapvector_dimensionrefresh_rateなど、Vector Store作成時の設定を確認できます。
  • Use Retrieval Augmented Generation to Complement LLMs

    • Oracle AI Vector Searchを利用したRAGの基本構成と、Relational DataとVector Dataを組み合わせる考え方を確認できます。
  • SQL RAG Example

    • Oracle AI Vector SearchをSQLから利用してRAGを構成する例を確認できます。
    • 今回のV_DOCUMENT_VECTOR_CHUNKSのように、Relational MetadataとVector StoreをSQLで関連付ける場合の参考になります。

● Object StorageのCustom Source URL

今回の第3回/第4回では、PDF Upload時に次のUser-defined Metadataを設定しています。

customized_url_source

Object Storage側では、Metadata Headerとして次の名前で確認できます。

opc-meta-customized_url_source

Select AIのRAG Profileで、

enable_custom_source_uri = true

を設定すると、このMetadata Headerに設定したURLをRAG回答のSourcesとして利用できます。

この動作は次のOracle公式ドキュメントで確認できます。

今回の環境では、Vector TableのATTRIBUTES JSON内にcustom_uriとして同じSource URLが保持されていることを確認しました。

ただし、ATTRIBUTES.custom_uriというJSON Property名そのものを公開仕様として保証するOracle公式ドキュメントは確認できていないため、本稿では「今回の環境で確認できたVector Store内部のMetadata表現」として扱っています。

● 次回以降の発展

  • Oracle AI Data Platform
    • 今回作成したData Lake、RDBMS、Vector Storeを、次回以降AIDPのCatalog/AI-ready Dataへ発展させる際の参考資料です。
6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?