2010年12月17日金曜日

Oracle Text でハマッタ...

Oracle Text を利用して中間一致検索の高速化をはかろうしてハマッてしまった。
ます、DBのバージョンが 9i であったためデータを追加・更新・削除しても Oracle Text で作成した索引に即反映させることができない。(10g以降ならデータの追加・変更時に同期可能なのだが...)
↓↓↓↓↓
よって、DBMS_JOB で定期的に更新を行うことになる。
そこでハマッタ。(T_T)

Oracle Textの利用方法(手順)の説明も兼ねて設定方法から説明します。
  1. OracleTextを利用するユーザーを作成します。
  2. ユーザー作成方法はみなさんご存知のとおりです。
    CREATE USER myuser IDENTIFIED BY myuser_password;
  3. 利用するユーザーに権限を与えます。
    (ユーザーにロールを付与します。)
    GRANT RESOURCE, CONNECT, CTXAPP TO MYUSER;
    (CTX PL/SQLパッケージでのEXECUTE権限の付与)
    すべてのOracle Textパッケージの実行権限を付与する場合。
    GRANT EXECUTE ON CTXSYS.CTX_CLS TO myuser;
    GRANT EXECUTE ON CTXSYS.CTX_DDL TO myuser;
    GRANT EXECUTE ON CTXSYS.CTX_DOC TO myuser;
    GRANT EXECUTE ON CTXSYS.CTX_OUTPUT TO myuser;
    GRANT EXECUTE ON CTXSYS.CTX_QUERY TO myuser;
    GRANT EXECUTE ON CTXSYS.CTX_REPORT TO myuser;
    GRANT EXECUTE ON CTXSYS.CTX_THES TO myuser;
    GRANT EXECUTE ON CTXSYS.CTX_ULEXER TO myuser;
  4. プリファレンス(全文検索対象のデータがどんなものかを示す指定)を作成します。
  5. connect <ユーザ名>/<パスワード>

    begin
    ctx_ddl.create_preference('<プリファレンス名>',
                                     'JAPANESE_VGRAM_LEXER');
    end;
    /
  6. 全文検索用の索引を作成します。
  7. CREATE INDEX <索引名> ON <表名> ( <項目名> )
          INDEXTYPE IS CTXSYS.CONTEXT PARAMETERS ('LEXER <プリファレンス名>')
    /
  8. 索引の手動更新
  9. Oracle Text索引は、情報が挿入または更新されるたびに動的に更新されません。  Oracle Textのストアド・プロシージャであるctx_ddl.sync_indexを使用して、索引を定期的にリフレッシュ(同期化)する必要があります。

    BEGIN
    -- 引数にINDEX名を指定
    CTX_DDL.SYNC_INDEX('<索引名>');
    END;
    /

    しかし、上記だといちいち自分で実行して更新しなければならない。
  10. そこでDBMS_JOBで定期実行して索引をリフレッシュ(同期化)する。・・・ここでハマる。
  11. //■DBM_JOB
    VARIABLE jobno NUMBER;
    BEGIN
    DBMS_JOB.SUBMIT(:jobno
         , 'BEGIN CTX_DDL.SYNC_INDEX(''<索引名>''); END;'
         , SYSDATE, 'SYSDATE+10/1440');
         COMMIT;
    END;
    /

    上記で問題(エラー発生)もなく DBMS_JOB に登録できた。
    しかし、ジョブの実行時間後に内容を確認しても追加・変更されたデータが反映されていない。

    下記のように索引で保留中の内容を確認すると更新されてないことを確認。
    SELECT pnd_index_name,
     pnd_rowid,
     to_char(pnd_timestamp, 'dd-mon-yyyy hh24:mi:ss') timestamp  FROM ctx_user_pending;


    更新されないので、手動でジョブを実行するとエラーになる。
    begin    dbms_job.run(<ジョブ番号>);    end;
    *
    行1でエラーが発生しまた.
    ORA-12011:1ジョブの実行に失敗しました
    ORA-06512:"SYS.DBMS_IJOB" . 行406
    ORA-06512:"SYS.DBMS_JOB" . 行272
    ORA-06512:行1

    アラートを調べ、トレースファイルを参照してググッてみたがなかなか解決策が見つからなかった、
  12. 解決策を見つけてみると...
  13. なんと、何度か試行錯誤した中にあったのは?と思う内容であった。わずかにどこか違っていたようだ。

    解答はこれダ!

    define idxname = "<索引名>"
    define interval = "10"

    set serveroutput on
    declare
        job number;
    begin
        dbms_job.submit(job, 'ctx_ddl.sync_index(''&idxname'');',
        interval=>'SYSDATE+&interval/1440');

        dbms_output.put_line('job '||job||' has been submitted.');
    end;
    /
毎度のことながら、些細な事でかなりの時間(今回は丸一日)を費やしてしまうものだ。 やはり、知識は正確により多く貯える必要がある。(泣)

0 件のコメント:

コメントを投稿