15 結果セット・インタフェースの使用

XML問合せおよびJSON問合せの結果セット・インタフェースについて詳しく説明します。

この章のトピックは、次のとおりです:

15.1 XML問合せの結果セット・インタフェースの概要

XML問合せの結果セット・インタフェース(RSI)は、XMLの問合せを実行し、XMLとして結果を戻すことができるため、SELECTセマンティクス内で有効なSQL層および要件が回避されます。RSIは、単純なOracle Text問合せとXML結果セット記述子を使用し、その結果セット記述子に応じてXMLでヒットリストが戻されます。XML問合せのRSIは、グループ化およびカウントにSDATAセクションを使用します。

アプリケーションでは、検索結果ページは最初の数ドキュメントのメタデータ、合計ヒット数、ワードごとのヒット数など、多くの個別の要素で構成されます。追加のコールのたびに、問合せを再解析して索引メタデータを検索するための時間がかかります。また、SQLでは、反復問合せ絞込みといった一部の検索操作が難しくなります。SQL文を構成して目的の結果を達成することが可能であっても、通常はこのようなSQLは次善の選択となります。

XML問合せRSIは、検索結果のページに必要な様々な種類のデータを同時に作成でき、オーバーヘッドを共有することでパフォーマンスを向上させます。RSIは、SQLでは表現しにくいデータ・ビューも返すことができます。

15.2 XML問合せの結果セット・インタフェースの使用

CTX_QUERY.RESULT_SET()およびCTX_QUERY.RESULT_SET_CLOB_QUERY() APIを使用すると、CONTAINS()問合せを何度も実行して同じ結果を得るのではなく、単一の問合せで問合せ結果を取得できます。2つのAPIは、一方がVARCHAR2問合せパラメータを使用し、もう一方がCLOB問合せを使用してより長い問合せに対応できる点を除き同じです。

たとえば、検索結果ページを表示するには、まず次の情報を取得する必要があります。

  • 日時および関連性でソートされた上位20個のヒット・リスト

  • 指定されたOracle Text問合せのヒットの総数

  • 公開日でグループ化した件数

  • 作成者でグループ化した件数

検索するドキュメントを格納する次の表定義を前提とします。

create table docs (
  docid    number,
  author   varchar2(30),
  pubdate  date,
  title    varchar2(60),  doc      clob);

次のOracle Text索引の定義を前提とします。

create index docidx on docs(doc) indextype is ctxsys.context
filter by author, pubdate, title
order by pubdate;

これらの定義を使用する場合、4つのSQL文を発行して、検索結果ページの表示に必要な4つの情報を取得できます。

-- Get top 20 hits sorted by date and relevancy
select * from
  (select /*+ first_rows */ rowid, title, author, pubdate
   from docs where contains(doc, 'oracle',1)>0
   order by pubdate desc, score(1) desc)
where rownum < 21;
 
-- Get total number of hits for the given Oracle Text query
select count(*) from docs where contains(doc, 'oracle',1)>0;
 
-- Get counts group by publication date
select pubdate, count(*) from docs where contains(doc, 'oracle',1)>0 
group by pubdate;
 
-- Get counts group by author
select author, count(*) from docs where contains(doc, 'oracle',1)>0 group by author;

表示されているとおり、同じ問合せを4回実行しているため、別々のSQL文を使用するとリソース集中型の問合せになります。ただし、CTX_QUERY.RESULT_SET()を使用すると、単一のOracle Textの問合せにこのすべての情報を入力できます。

declare
   rs clob;
begin
   dbms_lob.createtemporary(rs, true, dbms_lob.session);
   ctx_query.result_set('docidx', 'oracle text performance tuning', '
   <ctx_result_set_descriptor>  
    <count/>
    <hitlist start_hit_num="1" end_hit_num="20" order="pubDate desc, 
        score desc">
      <score/>
      <rowid/>
         <sdata name="title"/>
      <sdata name="author"/>
      <sdata name="pubDate"/>
    </hitlist>
    <group sdata="pubDate">
      <count/>
    </group>
   <group sdata="author">
     <count/>
   </group>
  </ctx_result_set_descriptor>
 ', rs);
 
-- Put in your code here to process the Output Result Set XML
   dbms_lob.freetemporary(rs);
exception
   when others then
    dbms_lob.freetemporary(rs);
    raise;
end;
/

結果セットの出力は、検索結果ページの作成に必要な情報が含まれているXMLです。

<ctx_result_set>
  <hitlist>
    <hit>
      <score>90</score>
      <rowid>AAAPoEAABAAAMWsAAC</rowid>
      <sdata name="TITLE"> Article 8 </sdata>
      <sdata name="AUTHOR">John</sdata>
      <sdata name="PUBDATE">2001-01-03 00:00:00</sdata>
    </hit>
    <hit>
      <score>86</score>
      <rowid>AAAPoEAABAAAMWsAAG</rowid>
      <sdata name="TITLE"> Article 20 </sdata>
      <sdata name="AUTHOR">John</sdata>
      <sdata name="PUBDATE">2001-01-03 00:00:00</sdata>
    </hit>
    <hit>
      <score>78</score>
      <rowid>AAAPoEAABAAAMWsAAK</rowid>
      <sdata name="TITLE"> Article 17 </sdata>
      <sdata name="AUTHOR">John</sdata>
      <sdata name="PUBDATE">2001-01-03 00:00:00</sdata>
    </hit>
    <hit>
      <score>77</score>
      <rowid>AAAPoEAABAAAMWsAAO</rowid>
      <sdata name="TITLE"> Article 37 </sdata>
      <sdata name="AUTHOR">John</sdata>
      <sdata name="PUBDATE">2001-01-03 00:00:00</sdata>
    </hit>
...
    <hit>
      <score>72</score>
      <rowid>AAAPoEAABAAAMWsAAS</rowid>
      <sdata name="TITLE"> Article 56 </sdata>
      <sdata name="AUTHOR">John</sdata>
      <sdata name="PUBDATE">2001-01-03 00:00:00</sdata>
    </hit>
  </hitlist>
 
  <count>100</count>
 
  <groups sdata="PUBDATE">
    <group value="2001-01-01 00:00:00"><count>25</count></group>
    <group value="2001-01-02 00:00:00"><count>50</count></group>
    <group value="2001-01-03 00:00:00"><count>25</count></group>
  </groups>
 
  <groups sdata="AUTHOR">
    <group value="John"><count>50</count></group>
    <group value="Mike"><count>25</count></group>
    <group value="Steve"><count>25</count></group>
  </groups>
 
</ctx_result_set>

関連項目:

構文の詳細とCTX_QUERY.RESULT_SETの詳細は、『Oracle Textリファレンス』を参照してください。

15.3 Oracle TextによるXMLのみのアプリケーションの作成

CONTAINS句を含むSQL SELECT文を使用してアプリケーションを作成することが一般的ですが、これは必ずしも最も効率的な方法ではありません。代替方法は、XMLベースのRSIを使用することです。このメリットは、問合せのすべての結果をフェッチしなくても、サマリー情報(ヒットの総数など)を簡単に取得できることです。

RSIを使用するには、結果セット記述子(RSD)を指定します。RSDは、戻される情報を宣言します。これは次のもので構成できます。

  • 問合せ結果の合計数

  • ヒットリスト

  • SDATAフィールドのサマリー情報

次に、ヒットリストは反復要素で構成され、そのそれぞれに次の情報が含まれます。

  • ヒットのROWID

  • ヒットのSDATAフィールド

関連項目:

結果セット記述子の例

15.4 結果セット記述子の例

この例は、RSDの使用方法を示しています。次の例は、上位10個のヒットリスト(スコア順で並替え)と、結果の合計数をリクエストします。

<ctx_result_set_descriptor>
  <hitlist start_hit_num="1" end_hit_num="10" order="SCORE DESC">
    <rowid />
    <sdata name="title" />
    <sdata name="author" />
    <sdata name="articledate" />
    <snippet radius="20" max_length="160" starttag="&lt;b&gt;" endtag="&lt;/b&gt;" />
  </hitlist>
  <count />
</ctx_result_set_descriptor>

ヒットごとに、rowid (必要な場合、行の詳細をフェッチするために使用できる)、SDATAフィールドまたはtitleauthorおよびarticledate列の内容およびスニペット(キーワードがハイライト表示される簡単な要約、この場合は<b>...</b>)をリクエストしています。

15.5 コロケートの識別

コロケートはドキュメント内で頻繁に共起する単語のグループです。コロケートは、指定されたキーワードに関連する他のキーワードや概念の簡単な概要を示します。問合せで他のキーワードを使用してより関連性のある結果を取得できます。

検索問合せに基づいてコロケートを識別します。問合せから返されるドキュメントごとに、検索キーワードに関連するテキストのスニペットが自動的に抽出されます。次に、これらのスニペットの語が統計メジャーを使用して問合せキーワードに関連付けられ、ドキュメント・セット全体における抽出語の発生頻度に応じて、返された各共起語にスコアが割り当てられます。

コロケートを識別するには、RSIを使用します。問合せで返される必要のある共起語の数を指定できます。また、普通名詞のコロケートを指定するか、独自性を強調するコロケートを識別するか指定することもできます。指定された検索キーワードのシノニムも返すことができます。

ノート:

コロケートはBASIC_LEXERでのみサポートされます。

コロケートを識別するには:

  1. 問合せ対象のドキュメント・セット表を作成します。
  2. ドキュメント・セット表にOracle Text索引を作成します。
  3. XML問合せのRSIを使用して、コロケートを識別する問合せを定義および入力します。必要な属性を持つcollocates要素を含めます。

例15-1 ドキュメント・セット内のコロケートの識別

この例で、データ・セット内のドキュメントの問合せに使用されているキーワードは'Nobel'です。Oracle Textは、ドキュメント・セット内のこのキーワードの出現を検索します。結果セットに加えて、コロケートを使用して'Nobel'で共起する5つの共通語を検索します。max_words属性を使用して、生成するコロケートの数を識別します。use_tscore属性をTRUEに設定して、共通語をコロケート用に識別する必要があることを指定します。コロケートを識別するためにキーワードの各側で選択する単語の数は10個です。

次に、コロケートの判別に使用される入力RSI記述子を示します。

declare
rsd varchar2(32767);
 begin
  ctx_query.result_set('tdrbnbsan01idx', 'nobel',
  <ctx_result_set_descriptor>
  <collocates radius = "10" max_words="5" use_tscore="TRUE"/>
  </ctx_result_set_descriptor>',
  :rs);
  end;
/

次に、問合せの出力結果セットを示します。

<ctx_result_set>
<collocates>
    <collocation>
       <word>PRIZE</word>
       <score>82</score>
    </collocation>
    <collocation>
       <word>LAUREATE</word>
       <score>70</score>
    </collocation>
    <collocation>
       <word>NOBELPRIZE</word>
       <score>44</score>
    </collocation>
    <collocation>
       <word>AWARD</word>
       <score>42</score>
    </collocation>
    <collocation>
       <word>ORG</word>
       <score>41</score>
    </collocation
</collocates>
</ctx_result_set>

'Nobel'の上位5つの共通コロケートは、上から順に、Prize、Laureate、Nobelprize、awardおよびorgです。各語には、発生頻度を示すスコアが割り当てられます。コロケートは、hitlist要素が返された後常に返されます。

同じ例でuse_tscoreFALSEに設定すると、共通性の少ない(一意の)単語が識別されます。次に、出力結果セットを示します。

<ctx_result_set>
<collocates>   
    <collocation>
       <word>MOLA</word>
       <score>110</score>   
    </collocation>
    <collocation>
       <word>BISMARCK</word>
       <score>89</score>
    </collocation>
    <collocation>
       <word>COLONNA</word>
       <score>67</score>
    </collocation>
    <collocation>
       <word>LYNEN</word>
       <score>55</score>
    </collocation>
    <collocation>
       <word>TIMBERGEN</word>
       <score>25</score>
    </collocation>
    </collocates>
</ctx_result_set>

関連項目:

コロケートで使用する属性の詳細は、『Oracle Textリファレンス』を参照してください。

15.6 JSONの結果セット・インタフェースの概要

JSONの結果セット・インタフェース(RSI)を使用すると、JSONで問合せを実行し、JSONとして結果を戻せるようになるため、SQLの層と要件をSELECTセマンティクス内で処理する必要がなくなります。

RSIでは、単純なOracle Text問合せまたはファセット、およびJSON結果セット記述子が使用され、その結果セット記述子に応じてJSONの単一のCLOBでヒットリストが戻されます。JSONのRSIでは、グループ化およびカウントにSDATAセクションが使用されます。

アプリケーションでは、検索結果ページは最初の数ドキュメントのメタデータ、合計ヒット数、ワードごとのヒット数など、多くの個別の要素で構成されます。追加のコールのたびに、問合せを再解析して索引メタデータを検索するための時間がかかります。また、SQLでは、反復問合せ絞込みといった一部の検索操作が難しくなります。SQL文を構成して目的の結果を達成することが可能であっても、通常はこのようなSQLは次善の選択となります。

JSONのRSIでは、検索結果のページに必要な様々な種類のデータを同時に作成できるため、オーバーヘッドの共有によりパフォーマンスが向上します。RSIは、SQLでは表現しにくいデータ・ビューも返すことができます。

JSONのRSIでは、CONTEXT索引とJSON検索索引に基づく問合せがサポートされています。サポートされているグループ・カウント以外に、COUNTMINおよびMAXなど、ファセットで他の集計を実行することもできます。数値ファセットでは、AVGおよびSUMがサポートされています。

15.7 JSONの結果セット・インタフェースの使用

CTX_QUERY.RESULT_SET()およびCTX_QUERY.RESULT_SET_CLOB_QUERY() APIを使用すると、CONTAINS()問合せを何度も実行して同じ結果を得るのではなく、単一の問合せで問合せ結果を取得できます。2つのAPIは、一方がVARCHAR2問合せパラメータを使用し、もう一方がCLOB問合せを使用してより長い問合せに対応できる点を除き同じです。

使用方法

入力の結果セット記述子(RSD)の問合せは、次の部分で構成されています。
  • $query: $queryを使用して、検索問合せ、パス制約、およびパス・ベースのその他のフィルタ条件を指定します。$query部分は、JSON検索索引が列に存在する場合にのみサポートされます。

  • $search: $searchを使用して、スコアでランク付けされた検索結果とその件数を表示します。JSON以外のOracle Text全文索引の場合は、検索結果を予測するSDATAセクションも指定できます。

  • $facet: $facetを使用して、JSONドキュメントの様々なパス、またはコンテキスト索引付きドキュメントのSDATAセクションについてファセットを指定します。一意の1つの値でバケット化された複数ファセット、およびユーザーが指定した範囲バケットごとの複数ファセットがサポートされています。ファセットは、COUNTMINなどの集計のいずれかにすることもできます。

結果セットの出力は次の形式になります。

{
  "$count" : number ,               
  "$hit" :    
  [
    { 
      "score" : <search_score>,
      "rowid" : <rowid>,
      "project" : {"<sdata_name>" : <sdata_value>, … }
    },
    …
  ],
"$facets" : 
  [
    {"<field>" : [ ..., { "value" : <value_i>, "$uniqueCount" : <group_count_i>}, ...  ]},           
    {"<field>" : [ ..., { "bucket" : <bucket_object_i>, "<op>" : <group_count_i>}, ...  ]},
    {"<field>" : { "<op>" : <actual_value of the aggregation> } },
    …         
  ]
}

関連項目:

CTX_QUERY.RESULT_SETプロシージャの詳細は、Oracle Textリファレンス