題材の相談を受けたので、ちょっとアプリを作ってみました。作り方は以前に記事に書いてはいるので、あまり細かい実装はせず、ブロックチェーン表で可能かどうかの確認を目的とします。
結論としてはAlways Freeの21cでは、Oracle Textのauto filterに何か問題があるようで、うまく動きませんでした。ブロックチェーン表だからできない、ということではなく、ブロックチェーン表でも全文検索索引は機能するはずですが、現状ではAlways Free以外に利用可能な21cのインスタンスは無いので確認できません。
以下より作業ログです。
最初にPDFを保存するブロックチェーン表を定義します。構造はクイックSQLの以下のモデルを使います。
# prefix: trm
# semantics: default
documents
title vc400
document file
DDLを生成し、スクリプトを保存してから、レビューと実行を行うと、DDLの編集画面になります。DDLをブロックチェーン表となるように書き換えます。
-- create tables
create blockchain table trm_documents (
id number generated by default on null as identity
constraint trm_documents_id_pk primary key,
title varchar2(400),
document blob,
document_filename varchar2(512),
document_mimetype varchar2(512),
document_charset varchar2(512),
document_lastupd date
)
no drop until 31 days idle no delete locked HASHING USING "SHA2_512" version "v1"
;
DDLを実行し表を作成した後、アプリケーションの作成を行い、アプリケーション作成ウィザードを起動します。作成するアプリケーションの名前を指定し(ここではPDF保存)、アプリケーションの作成をクリックします。
これで、PDF(に限らず、あらゆるファイル)のアップロードと保存、ダウンロードを行うアプリケーションが作成されました。
次に全文検索索引をブロックチェーン表に付加します。
最初に日本語レクサーを登録します。
begin
ctx_ddl.create_preference('ja_lexer', 'JAPANESE_LEXER');
end;
/
Autonomous Databaseの場合は、ワークスペース・スキーマにCTX_DDLパッケージの実行権限が割り当たっていません。SQL Developer WebなどからADMINでサインインして実行権限を割り与えます。
grant execute on ctx_ddl to スキーマ名;
BLOB(バイナリ・データ)として登録されたファイルより、文字情報を抽出するフィルタを設定します。
begin
ctx_ddl.create_preference('auto_filter', 'AUTO_FILTER');
ctx_ddl.create_policy('auto_policy', 'auto_filter');
end
/
ユーザー・データストアに利用されるファイルよりテキストを抽出するプロシージャを作成します。
create or replace procedure pdf_to_text(
rid in rowid,
tlob in out nocopy clob
)
is
l_title trm_documents.title%type;
l_document trm_documents.document%type;
l_clob clob;
begin
for c in (select title, document from trm_documents where rowid = rid)
loop
if c.title is not null then
dbms_lob.writeappend(tlob, length(c.title), c.title);
end if;
if dbms_lob.getlength(c.document) > 0 then
begin
ctx_doc.policy_filter('auto_policy', c.document, l_clob, true);
dbms_lob.copy(tlob, l_clob, length(l_clob), length(tlob)+1, 1);
exception
when others then
null;
end;
end if;
end loop;
end pdf_to_text;
ユーザー・データストアtrm_documents_storeを登録します。APEXDEVとなっている部分は、作成したプロシージャpdf_to_textのオーナーに置き換えます。
begin
ctx_ddl.create_preference('trm_documents_store', 'user_datastore');
ctx_ddl.set_attribute('trm_documents_store', 'procedure', 'APEXDEV.pdf_to_text');
ctx_ddl.set_attribute('trm_documents_store', 'output_type', 'CLOB');
end;
作成したユーザー・データストアを使って、全文検索索引を作成します。
create index trm_documents_sidx on trm_documents(title)
indextype is ctxsys.context
parameters('filter ctxsys.null_filter lexer ja_lexer datastore trm_documents_store sync(on commit)');
以上で、全文検索索引の作成は完了です。
アプリケーションにすでに含まれている対話モード・レポートが全文検索索引を使用するように属性の設定を行います。
対話モード・レポートのリージョンを開き、右ペインでAttributesを開きます。詳細にOracle Text索引列の設定があるので、それに列TITLEが設定されていることを確認します。
以上で、一応動くはずなんですが、試すと検索にヒットしません。確認のため以下のコードを実行しました。
以下のエラーが発生します。
ORA-20000: Oracle Textエラー: DRG-11207: ユーザー・フィルタ・コマンドが状態1で終了しました。 DRG-11221: サードパーティのフィルタが、このドキュメントの破損を示しています。 ORA-06512: "CTXSYS.DRUE", 行186 ORA-06512: "CTXSYS.CTX_DOC", 行1682 ORA-06512: 行6 ORA-06512: 行6 ORA-06512: "SYS.DBMS_SQL", 行1766
このインスタンスでは普通の表でも同じエラーが発生することも確認できました。東京リージョンの19cで普通の表を対象に、同じ手順でアプリケーションを作成すると、問題なく全文検索ができるので、おそらくAlways Freeの21c固有の事象ではないかと思われます。