6.1 問合せの概要

Oracle Textの基本的な問合せでは、問合せ式を入力します。式は、通常はワードで、演算子を併用する場合と併用しない場合があります。式を満たすすべてのドキュメント(事前に索引付け済)が、各ドキュメントの関連性スコアとともに戻ります。スコアを使用して、結果セット内のドキュメントを順序付けできます。

Oracle Textの問合せを入力するには、SQLのSELECT文を使用します。索引のタイプに応じて、WHERE句にCONTAINS演算子またはCATSEARCH演算子のいずれかを使用します。これらの演算子は、PL/SQLカーソル内など、SELECT文を使用できる状況であれば、いつでもプログラムで使用できます。

CTXRULE索引を使用してドキュメントを分類するには、MATCHES演算子を使用します。

6.1.1 CONTAINSによる問合せ

CONTEXT索引タイプを作成する場合は、CONTAINS演算子を使用して問合せを入力する必要があります。この索引は、大量のまとまったドキュメントのコレクションを索引付けする場合に適しています。

CONTAINS演算子では、複数の演算子を使用して検索条件を定義できます。これらの演算子によって、論理、近接、ファジー、ステミング、シソーラスおよびワイルドカードの各検索を入力できます。また、適切に構成された索引を使用すると、HTMLやXMLのような内部構造を持つドキュメントに対してセクション検索を入力することもできます。

CONTAINSでは、ABOUT演算子を使用して、ドキュメント・テーマを検索できます。

6.1.1.1 CONTAINS SQL例

SELECT文では、CONTAINS演算子を使用してWHERE句で問合せを指定します。また、ヒットリストのヒットごとにスコアを戻すには、SCORE演算子を指定します。次の例では、問合せの入力方法を示します。

SELECT SCORE(1), title from news WHERE CONTAINS(text, 'oracle', 1) > 0;

次のように、ORDER BY句を使用して、結果を最も高いスコアのドキュメントから最も低いスコアのドキュメントに順序付けることができます。

SELECT SCORE(1), title from news 
           WHERE CONTAINS(text, 'oracle', 1) > 0
           ORDER BY SCORE(1) DESC;

CONTAINS演算子の後には、> 0構文が必要です。この構文は、CONTAINS演算子によって戻されるスコアの値が、戻される行に対してゼロより大きい必要があることを指定します。

SELECT文でSCORE演算子がコールされた場合、CONTAINS演算子は、前述の例に示すように、3番目のパラメータでスコア・ラベルの値を参照する必要があります。

6.1.1.2 CONTAINS PL/SQL例

PL/SQLアプリケーションでは、カーソルを使用して問合せ結果をフェッチできます。

次の例では、CONTAINS問合せをNEWS表に対して入力し、ワードoracleを含むすべての記事を検索します。ヒットしたもののうち上位10個のタイトルとスコアが出力されます。

declare 
  rowno number := 0; 
begin 
  for c1 in (SELECT SCORE(1) score, title FROM news 
              WHERE CONTAINS(text, 'oracle', 1) > 0
              ORDER BY SCORE(1) DESC) 
  loop 
    rowno := rowno + 1; 
    dbms_output.put_line(c1.title||': '||c1.score); 
    exit when rowno = 10; 
  end loop; 
end; 

この例では、カーソルFORループを使用して、ヒットしたもののうち上位10個を取り出します。SCORE演算子の戻り値に対して、別名scoreが宣言されています。スコアとタイトルがカーソル・ドット表記法を使用して出力として表示されます。

6.1.1.3 CONTAINSによる構造化問合せの例

構造化問合せは複合問合せとも呼ばれ、テキスト列を問い合せる1つのCONTAINS述語と、構造化データ列を問い合せる別の述語を持つ問合せです。

構造化問合せを入力するには、SELECT文のWHERE条件に構造化句を指定します。

たとえば、次のSELECT文は、1997年10月1日以降に書かれた、ワードoracleを含む記事をすべて検索します。

SELECT SCORE(1), title, issue_date from news 
           WHERE CONTAINS(text, 'oracle', 1) > 0
           AND issue_date >= ('01-OCT-97') 
           ORDER BY SCORE(1) DESC;

6.1.2 CATSEARCHによる問合せ

CTXCAT索引タイプを作成する場合は、CATSEARCH演算子を使用して問合せを入力する必要があります。

この索引は、使用しているアプリケーションで、テキスト列に短いテキスト断片を格納し、関連列に関連情報を格納する場合に適しています。

たとえば、オンライン・オークション・サイトを提供しているアプリケーションの場合、表のテキスト列に品目の説明を格納し、その他の列に日付と価格情報を格納するという具合です。CTXCAT索引を使用すると、1つ以上の列にBツリー索引を作成できるため、複雑な問合せに対する問合せのパフォーマンスが通常高速になります。

CATSEARCHによる問合せに使用できる演算子は、ANDORなどの論理操作に制限されています。構造化基準を定義するには、>、<、=、BETWEENおよびIN演算子を使用します。

ノート:

Oracle Textの索引タイプCTXCATは、Oracle Database 23aiでは非推奨です。索引タイプ自体とその演算子CTXCATは、将来のリリースで削除される可能性があります。

CONTEXT問合せの代替文法としてCTXCATおよびCTXCAT文法の使用はどちらも非推奨です。かわりに、Oracleでは、CONTEXT索引タイプを使用することをお薦めします。索引タイプは、トランザクション以外のすべての同じ機能を提供できます。CONTEXTでのトランザクションに近い動作は、SYNC(ON COMMIT)または短い期間(できればSYNC(EVERY [time-period]))を使用して実現できます。

CTXCATは、通常、索引のサイズが数メガバイトのときに導入されました。最近の大規模な索引は、CTXCATで管理が困難な場合があります。CTXCATへの索引セットの追加は、CONTEXT索引タイプでFILTER BY列とORDER BY列、またはSDATA列(あるいはその両方)を使用することで、より効率的に実行できます。したがって、CTXCATが適切な選択になることはほとんどありません。Oracleでは、より効率的なCONTEXT索引タイプを選択することをお薦めします。

6.1.2.1 CATSEARCH SQL問合せの例

CATSEARCHによる一般的な問合せの例として、ワードcameraを含むすべての行を検索してbid_closeの日付順にソートする次の構造化句などがあります。

SELECT FROM auction WHERE CATSEARCH(title, 'camera', 'order by bid_close desc')> 0;

入力できる構造化問合せのタイプは、サブ索引の作成方法によって異なります。

関連項目:

CTXCAT索引の作成

前述の例のように、CATSEARCH問合せの構造化部分を指定するには、3番目のstructured_queryパラメータを使用します。構造化式の列には、対応するサブ索引が必要です。

たとえば、category_idbid_closeには、AUCTION表のctxcat索引内にサブ索引があるとします。この場合は、次のような構造化問合せを入力します。

SELECT FROM auction WHERE CATSEARCH(title, 'camera', 'category_id=99 order by bid_close desc')> 0;

6.1.2.2 CATSEARCH例

次の例は、CTXCAT索引に対するフィールド・セクション検索を示しています。これは、CATSEARCH問合せの問合せテンプレートでCONTEXT構文を使用します。

-- Create and populate table
create table BOOKS (ID number, INFO varchar2(200), PUBDATE DATE);
 
insert into BOOKS values(1, '<author>NOAM CHOMSKY</author><subject>CIVIL
   RIGHTS</subject><language>ENGLISH</language><publisher>MIT
   PRESS</publisher>', '01-NOV-2003');
 
insert into BOOKS values(2, '<author>NICANOR PARRA</author><subject>POEMS 
  AND ANTIPOEMS</subject><language>SPANISH</language>
  <publisher>VASQUEZ</publisher>', '01-JAN-2001');
 
insert into BOOKS values(1, '<author>LUC SANTE</author><subject>XML
  DATABASE</subject><language>FRENCH</language><publisher>FREE
  PRESS</publisher>', '15-MAY-2002');
 
commit;
 
-- Create index set and section group
exec ctx_ddl.create_index_set('BOOK_INDEX_SET');
exec ctx_ddl.add_index('BOOK_INDEX_SET','PUBDATE');
 
exec ctx_ddl.create_section_group('BOOK_SECTION_GROUP',
      'BASIC_SECTION_GROUP');
exec ctx_ddl.add_field_section('BOOK_SECTION_GROUP','AUTHOR','AUTHOR');
exec ctx_ddl.add_field_section('BOOK_SECTION_GROUP','SUBJECT','SUBJECT');
exec ctx_ddl.add_field_section('BOOK_SECTION_GROUP','LANGUAGE','LANGUAGE');
exec ctx_ddl.add_field_section('BOOK_SECTION_GROUP','PUBLISHER','PUBLISHER'); 
 
-- Create index
create index books_index on books(info) indextype is ctxsys.ctxcat
  parameters('index set book_index_set section group book_section_group');
 
-- Use the index
-- Note that: even though CTXCAT index can be created with field sections, it
-- cannot be accessed using CTXCAT grammar (default for CATSEARCH).
-- We need to use query template with CONTEXT grammar to access field 
-- sections with CATSEARCH
 
select  id, info from books
where catsearch(info,
'<query>
      <textquery grammar="context">
              NOAM within author and english within language
      </textquery>
 </query>',
'order by pubdate')>0; 

6.1.3 MATCHESによる問合せ

CTXRULE索引タイプを作成する場合は、MATCHES演算子を使用してドキュメントを分類する必要があります。CTXRULE索引は、本来は分類を定義する問合せのセットに作成される索引です。

たとえば、ドキュメントの着信ストリームをドキュメントの内容に基づいて分類する必要がある場合は、カテゴリを定義する問合せのセットを作成できます。この問合せは、テキスト列の行として作成します。このタイプの表を作成するには、CTX_CLS.TRAINプロシージャを使用します。

次に、CTXRULE索引を作成するために表を索引付けします。ドキュメントの着信時に、MATCHES演算子を使用して各ドキュメントを分類します。

6.1.3.1 MATCHES SQL問合せ

MATCHES問合せでは、指定したドキュメントに一致する問合せ表内のすべての行を検索します。querytable表がCTXRULE索引に関連付けられている場合、次の問合せを入力します。

SELECT classification FROM querytable WHERE MATCHES(query_string,:doc_text) > 0;

:doc_textバインド変数には、分類されるCLOBドキュメントが含まれています。

次に、その単純な例を示します。

   create table queries (
      query_id      number,
      query_string  varchar2(80)
    );

    insert into queries values (1, 'oracle');
    insert into queries values (2, 'larry or ellison');
    insert into queries values (3, 'oracle and text');
    insert into queries values (4, 'market share');

    create index queryx on queries(query_string)
      indextype is ctxsys.ctxrule;

    select query_id from queries
     where matches(query_string, 
                   'Oracle announced that its market share in databases 
                    increased over the last year.')>0

この問合せでは、問合せ1 (ドキュメントにoracleというワードが出現)および4 (ドキュメントにmarket shareという句が出現)が返され、問合せ2 (larryおよびellisonというワードは出現しない)および3 (ドキュメント内にテキストがないため問合せに一致しない)は返されません。

この例では、簡略化するために、ドキュメントを文字列として渡しています。通常、ドキュメントはバインド変数で渡されます。

MATCHES問合せでは、VARCHAR2またはCLOBのドキュメント・テキストを使用できます。BLOB入力は使用できないため、フィルタ処理済のドキュメントに直接一致させることはできません。かわりに、AUTO_FILTERフィルタを使用してバイナリ・コンテンツをCLOBにフィルタ処理する必要があります。この例では、2つのことを想定しています。

  • ドキュメント・データは、:doc_blobバインド変数にあります。

  • CTX_DOC.POLICY_FILTERで使用できるmy_policyをすでに定義しています。

たとえば:

  declare
    doc_text clob;
  begin
    -- create a temporary CLOB to hold the document text
    doc_text := dbms_lob.createtemporary(doc_text, TRUE, DBMS_LOB.SESSION);
 
    -- create a simple policy for this example
    ctx_ddl.create_preference(preference_name => 'fast_filter',
                        object_name       => 'AUTO_FILTER');
    ctx_ddl.set_attribute(preference_name => 'fast_filter',
                        attribute_name    => 'OUTPUT_FORMATTING',
                        attribute_value   => 'FALSE');
    ctx_ddl.create_policy(policy_name     => 'my_policy',
                        filter            => 'fast_filter);

    -- call ctx_doc.policy_filter to filter the BLOB to CLOB data
    ctx_doc.policy_filter('my_policy', :doc_blob, doc_text, FALSE);

    -- now do the matches query using the CLOB version
    for c1 in (select * from queries where matches(query_string, doc_text)>0)
    loop
      -- do what you need to do here
    end loop;

    dbms_lob.freetemporary(doc_text);
  end;

テキストをCLOBに取り込んでMATCHES問合せを入力する必要があるため、CTX_DOC.POLICY_FILTERプロシージャによりBLOBCLOBデータにフィルタ処理します。これは、CTX_DDL.CREATE_POLICYを使用してすでに作成されたポリシーの名前を1つの引数として受け取ります。

関連項目:

CTX_DOC.POLICY_FILTERの詳細は、『Oracle Textリファレンス』を参照してください

ファイルがデータベース文字セット内のテキストである場合、BFILEを作成し、DBMS_LOB.LOADFROMFILEファンクションを使用してCLOBにロードするか、UTL_FILEを使用して、ファイルを一時的なCLOBロケータに読み込むことができます。

ファイルがAUTO_FILTERフィルタ処理を必要とする場合は、ファイルをBLOBにロードして、前述のように、CTX_DOC.POLICY_FILTERをコールします。

関連項目:

拡張された分類の例は、「Oracle Textでのドキュメントの分類」を参照してください

6.1.3.2 MATCHES PL/SQL例

次の例では、問合せのプロファイル表がCTXRULE索引に関連付けられていることを前提としています。また、newsfeed表に分類対象の記事のセットが含まれていることも前提となります。

この例では、newsfeed表内をループし、MATCHES演算子を使用して各記事を分類します。結果は、results表に格納されます。

PROMPT  Populate the category table based on newsfeed articles
PROMPT
set serveroutput on;
declare
  mypk   number;
  mytitle varchar2(1000);
  myarticles clob;
  mycategory varchar2(100);
  cursor doccur is select pk,title,articles from newsfeed;
  cursor mycur is  select category from profiles where matches(rule, myarticles)>0;  
  cursor rescur is select category, pk, title from results order by category,pk;

begin
  dbms_output.enable(1000000);
  open doccur;
  loop
    fetch doccur into mypk, mytitle, myarticles;
    exit when doccur%notfound;
    open mycur;
    loop
      fetch mycur into mycategory;
      exit when mycur%notfound;
      insert into results values(mycategory, mypk, mytitle);
    end loop;
    close mycur;
    commit;
  end loop;
  close doccur;
  commit;

end;

次の例では、分類された記事をカテゴリ別に表示します。

PROMPT  display the list of articles for every category
PROMPT
set serveroutput on;

declare
  mypk   number;
  mytitle varchar2(1000);
  mycategory varchar2(100);
  cursor catcur is select category from profiles order by category;
  cursor rescur is select pk, title from results where category=mycategory order by pk;

begin
  dbms_output.enable(1000000);
  open catcur;
  loop
    fetch catcur into mycategory;
    exit when catcur%notfound;
    dbms_output.put_line('********** CATEGORY: '||mycategory||' *************');
open rescur;
    loop
      fetch rescur into mypk, mytitle;
      exit when rescur%notfound;
dbms_output.put_line('**  ('||mypk||'). '||mytitle);
    end loop;
    close rescur;
    dbms_output.put_line('**');
dbms_output.put_line('*******************************************************');
  end loop;
  close catcur; 
end;

関連項目:

拡張された分類の例は、「Oracle Textでのドキュメントの分類」を参照してください

6.1.4 ワード問合せと句問合せ

ワード問合せは、ワードまたは句に対する問合せです。たとえば、テキスト表でワードdogを含むすべての行を検索するには、問合せ語句として、dogを指定して問合せを入力します。

ワード問合せは、SQL演算子のCONTAINSCATSEARCHの両方で入力できます。ただし、句問合せは、異なる方法で解釈されます。

  • CONTAINS句問合せ: 問合せ式に複数のワードが空白のみ(演算子なし)で区切られて含まれている場合、そのワードの文字列は句とみなされます。Oracle Textでは、問合せ中に文字列全体が検索されます。たとえば、句international lawを含むすべてのドキュメントを検索するには、句international lawを指定して問合せを入力します。

  • CATSEARCH句問合せ: CATSEARCH演算子では、句のワード間にAND演算子を挿入します。たとえば、international lawの問合せでは、international AND lawとして解釈されます。

6.1.5 ストップワードの問合せ

ストップワードは、索引エントリが作成されないワードです。これは、通常、検索の対象とならない、その言語の一般的なワードです。

Oracle Textには、使用言語のデフォルトのストップワード・リストが組み込まれています。このリストは、ストップリストと呼ばれます。たとえば、英語では、ワードthisおよびthatは、デフォルトのストップリストでストップワードとして定義されています。このデフォルトのストップリストを変更したり、CTX_DDLパッケージを使用して新しいストップリストを作成できます。また、索引を作成した後で、ALTER INDEX文でストップワードを追加することもできます。

ストップワードまたはストップワードのみで構成されている句に対する問合せは発行できません。たとえば、thisがストップワードとして定義されている場合は、ワードthisを問い合せても、ヒットは戻りません。

Oracle Textの索引では、ストップワードの索引エントリは作成しませんが、ストップワードの位置は記録しているため、this boy talks to that girlといった索引付け可能なワードに加えてストップワードを含む句を問い合せることができます。

問合せ句内にストップワードが含まれている場合、このストップワードは任意のワードに一致します。たとえば、次の問合せではwasがストップワードであると想定しています。この場合、Jack is bigJack grew bigなどの句が一致します。また、ストップワードではありませんが、grewにも一致します。

'Jack was big'

Oracle Database 12cリリース2 (12.2)以降、ストップワードとストップワードの単項演算子が問合せ結果の初期段階で無視されるため、前のリリースと異なる問合せ結果になります。たとえば、次の問合せでは、theがストップワードで、問合せ処理中に$演算子とストップワードが無視されるため、ドキュメントは返されません。

SQL> select count(1) from tabx where contains(text,'$the')>0; 
 . 
  COUNT(1) 
 ---------- 
        0

次の問合せでは、theストップワードと$演算子が無視されるため、firstが含まれているドキュメントは返されます。

SQL> select count(1) from tabx where contains(text,'first and $the')>0; 
 . 
  COUNT(1) 
 ---------- 
        2

6.1.6 ABOUT問合せおよびテーマ

ABOUT問合せは、ドキュメント・テーマに対する問合せです。ドキュメント・テーマは、テキスト内で詳しく展開されている概念のことです。たとえば、US politicsABOUT問合せでは、アメリカの大統領選挙や外交政策に関する情報を含むドキュメントが戻る可能性があります。戻るドキュメントには、US politicsと正確に一致する句が含まれている必要はありません。

索引付け時に、ドキュメント・テーマはナレッジ・ベースから導出され、このナレッジ・ベースには、一般的な知識を表すカテゴリと概念が階層式にリストされています。たとえば、ナレッジ・カタログのテーマには、jazz musicfootballNelson Mandelaなどの具体的な概念もあります。また、テーマには、happinesshonestyなどの抽象的な概念もあります。

索引付け中に、システムでは、ドキュメント内で詳しく展開されているが、ナレッジ・ベースには存在しないドキュメント・テーマも識別し、索引付けすることができます。

ナレッジ・ベースは、業界または問合せアプリケーション固有の概念や用語を定義して補強できます。補強した場合は、追加した概念に対するABOUT問合せの精度が向上します。

索引内にテーマ・コンポーネントを作成すると、ABOUT問合せのパフォーマンスが最も向上します。テーマ・コンポーネントは、英語とフランス語ではデフォルトで作成されます。

ストップテーマの問合せ

ABOUT演算子を使用すると、テーマを問い合せることができます。ストップテーマは、索引付けされていないテーマです。ストップテーマは、CTX_DDLパッケージを使用して追加および削除できます。また、索引を作成した後で、ALTER INDEX文でストップテーマを追加することもできます。