2022年7月13日水曜日

APEX 22.1で追加された行検索のトークン化の効果

 Oracle APEX 22.1よりアプリケーション定義プロパティに、行検索のトークン化が追加されています。


オンライン・ヘルプには、以下のように説明されています。

コンポーネントで行検索が行われた場合に、検索語がどのように適用されるかを指定します。

「オン」を選択すると、検索語のそれぞれの単語が別々に処理されます。全体であれ個別であれ、列に検索語が含まれていればレコードが一致します。フレーズ全体を検索するには、検索語を二重引用符(")で囲み、"ui developer"のようにします。検索語の中の二重引用符をエスケープするには、二重引用符("")を使用します。
例1- redおよびshoesという語を含む任意のレコード検索: red shoes2- developerという語とui designerという表現全体を含む任意のレコード検索: developer "ui designer"3- authorという語と、the sky is "blue" and niceという表現全体を含む任意のレコード検索語: author "the sky is ""blue"" and nice"

「オフ」を選択すると、検索語全体が完全一致として扱われます。

Oracle APEX 22.1で新規に作成したアプリケーションでは、デフォルトでONになっています。

こちらの記事で作成した簡易ファイル管理アプリケーションを使って、行検索のトークン化の効果を確認します。


今回の動作確認では、対話モード・レポートを使用します。これ以外にスマート・フィルタファセット検索対話グリッドポップアップLOVなど、行検索がサポートされているすべてのコンポーネントで機能します。

テストに使用するデータとして、Oracle APEX情報サイトよりPDFで提供されているファイルをいくつかアップロードしています。



Oracle Textによる全文検索との関係



レポートにOracle Text索引列が設定されている場合は、Oracle Textによる検索が優先されます。この場合、行検索のトークン化の設定は意味を持ちません。

対話モード・レポートでは、属性詳細Oracle Text索引列に、Oracle Text索引が作成されている列を指定します。今回のサンプル・アプリケーションでは、表SIMPLE_CONTENTSの列TITLEを指定します。


Oracle and Daysを検索語として行検索を行います。OracleDaysを含む文書が3件検索されました。


列Abstractを非表示にしても、検索結果は変わりません。これは全文検索索引を作成する元データとして、列TITLE、ABSTRACT、そしてBLOBから自動フィルタを適用して取り出した文字列を使用しているためです。逆に列TITLE、ABSTRACT、アップロードしたファイルの内容以外はレポートに表示されていても、検索対象にはなりません。

デバッグ・ログより実際に実行されているSELECT文を確認してみます。


もっとも内側で実行されているSELECT文の、WHERE句として与えられている条件は以下になります。

contains("TITLE",:apex$f1,1)>0

バインド変数の:apex$f1に、検索語のOracle and Daysが渡されています。


行検索のトークン化がOFFの場合



Oracle Daysを検索語として行検索を行います。結果は0件になります。行検索のトークン化OFFの場合、検索語Oracle Daysと完全一致する単語を含む行のみが検索結果となります。


同様にデバッグ・ログよりWHERE句の条件を確認します。
(
    instr( upper("TITLE"),upper(:apex$f1)) > 0 
    or 
    instr( upper("ABSTRACT"),upper(:apex$f1)) > 0
)

バインド変数の:apex$f1に、検索語のOracle Daysが渡されています。

この条件であれば、検索結果は0件になります。


行検索のトークン化がONの場合



APEX 22.1で追加されたプロパティ行検索のトークン化ONにしたときの結果です。OFFの場合と同様に検索語としてOracle Daysを与えて行検索を行います。

行検索のトークン化がONの場合、検索結果が3件になりました。


デバッグ・ログよりWHERE句の条件を確認します。

(
    instr( upper("TITLE"),upper(:apex$f1)) > 0
    or
    instr( upper("ABSTRACT"),upper(:apex$f1)) > 0
)
and
(
    instr( upper("TITLE"),upper(:apex$f2)) > 0 
    or
    instr( upper("ABSTRACT"),upper(:apex$f2)) > 0
)

行検索に与えられた検索語Oracle Daysは空白で区切られ、Oracle:apex$f1Days:apex$f2に割り当てられます。結果としてOracleとDaysが含まれている表示列があれば、検索結果に含まれます。

今回は列ABSTRACTにOracleとDaysの両方が含まれているデータが3件ありました。


Oracle Text関数



本題から外れますが、近いトピックなのでOracle Text関数も使ってみます。

ファンクションconvert_end_user_searchを作成します。
create or replace function convert_end_user_search (
    p_search in varchar2 )
    return varchar2 
is
begin
    return 'FUZZY({' || replace( p_search, '}', '\}' ) || '}, 30, 2000)';
end;
これはOracle Text関数のオンライン・ヘルプに記載のある、Oracle Text CONTAINS問合わせ演算子のFUZZY関数を使った例です。

アプリケーション定義プロパティOracle Text関数として、convert_end_user_searchを設定します。


対話モード・レポート属性Oracle Text索引列TITLEを指定し、Oracle Textによる全文検索を有効にします。

検索語としてOlacle Daysを与えて、行検索を行ってみます。Oracleではなくスペルが間違っているOlacleです

FUZZY検索が行われるため、スペルが間違っていても、検索結果として3件返されます。


これも条件句を確認してみます。

contains("TITLE",convert_end_user_search(:apex$f1),1)>0

convert_end_user_searchが返す文字列は、:apex$f1がOlacle Daysであれば以下になります。

FUZZY({Olacle Days}, 30, 2000)

結果として、上記の条件句は以下になります。

contains("TITLE",'FUZZY({Olacle Days}, 30, 2000)',1)>0

この他にも多数の演算子があります。しかし、Oracle Textの日本語対応は充実しているとは言い難いため、ほとんど期待できないです。

Oracle APEX 22.1で追加された、行検索のトークン化についての説明は以上になります。

Oracle APEXのアプリケーション作成の参考になれば幸いです。