ヘッダーをスキップ
Oracle XML DB開発者ガイド
11gリリース1(11.1)
E05669-02
  目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 

11 XMLデータの全文検索

この章では、Oracleを使用したXMLの全文検索について説明します。また、Oracle DatabaseによるXMLデータの全文検索で使用される2つの関数である、SQL関数containsおよびXPath関数ora:containsの使用方法について説明します。


関連項目:

Oracle Textの詳細は、『Oracle Textリファレンス』および『Oracle Textアプリケーション開発者ガイド』を参照してください。

この章の内容は次のとおりです。

XMLの全文検索の概要

Oracleは、Oracle Databaseにより管理される文書の全文検索をサポートしています。文書がXMLの場合は、その文書のXML構造を使用して全文検索を限定できます。たとえば、全文検索を使用してワード"electric"が含まれる発注書をすべて検索するとします。発注書がXML形式の場合は、コメント内にワード"electric"が含まれるすべての発注書を検索するか、または明細項目の下にあるコメント内にワード"electric"が含まれるすべての発注書を検索するかして、検索内容を限定できます。XML文書がXMLType型の場合は、その文書のXML構造を使用して問合せの結果を投影できます。たとえば、コメント内にワード"electric"が含まれるすべての発注書を検索した後で、コメント全体を戻すか、またはワード"electric"が含まれるコメントのみを戻すことができます。

全文検索と他の検索タイプの比較

全文検索は、構造化検索や部分文字列検索と次の点で異なります。

  • 全文検索では、部分文字列ではなくワード全体が検索されます。文字列"law"が含まれるコメントの部分文字列検索を行うと、"my lawn is going wild"が含まれるコメントが戻されます。ワード"law"の全文検索では、このコメントは戻されません。

  • 全文検索では、部分文字列検索ではサポートできない言語ベースとワードベースの検索がいくつかサポートされています。たとえば、言語ベースの検索を使用すると、"mouse"と言語語幹が同じワードを含むすべてのコメントを検索でき、Oracle Textでは"mouse"と"mice"が検索されます。ワードベースの検索の例では、"wild"を含む5ワード以内にワード"lawn"があるすべてのコメントを検索できます。

  • 全文検索には通常、関連性の概念が含まれています。たとえば、ワード"lawn"が含まれるすべてのコメントを全文検索する場合、ある結果は他の結果より関連性が高い場合があります。関連性は通常、検索ワード(または類似ワード)の文書内での出現回数に関連しています。

XMLデータの検索

XML検索は、非構造化文書の検索とは異なります。非構造化文書の検索では通常、一連の文書を検索して、指定したテキスト述語を満たす文書を戻します。XML検索では多くの場合、XML文書の構造を使用して検索を限定します。また、検索を満たす文書の一部のみを戻す場合があります。

全文検索およびXML構造を使用した文書の検索

全文検索とXML構造が含まれる検索の実行方法には、次の2通りがあります。

  • SQL関数containsを使用して、全文述語内に構造を含める方法:

    ... WHERE contains(doc, 'electric INPATH (/purchaseOrder/items/item/comment)')
              > 0 ...
    

    関数containsはSQLの拡張機能であり、すべての問合せで使用できます。この関数には、CONTEXT全文索引が必要です。

  • ora:contains XPath関数を使用して、構造内に全文述語を含める方法:

    ... '/purchaseOrder/items/item/comment[ora:contains(text(), "electric")>0]' ...
    

    ora:contains XPath関数はXPathの拡張機能であり、existsNodeextractまたはextractValueのすべてのコールで使用できます。

全文検索の例について

この項では、この章の例について詳細に説明します。

ロールおよび権限

例を実行するには、CONNECTRESOURCEの他に、CTXAPPロールが必要です。また、CTXSYSパッケージCTX_DDLに対するEXECUTE権限も必要です。

全文検索の例に使用するスキーマおよびデータ

この章の例は、W3Cの「XML Schema Part 0: Primer」にある「The Purchase Order Schema」に基づいています。

例で使用しているデータは、「発注書のXML文書、po001.xml」です。パフォーマンスの例の一部は、より大きい表(PURCHASE_ORDERS_xmltype_big)に基づいています。この表はダウンロード可能なバージョンにのみ含まれています。

ここでは、データ型としてVARCHAR2を使用する例と、XMLTypeを使用する例があります。VARCHAR2を使用している例はすべて、XMLTypeを使用することもできます。

CONTAINSおよびora:containsの概要

この項の内容は次のとおりです。

SQL関数CONTAINSの概要

SQL関数containsは、[schema.]columntext_queryと一致する行の正数を戻し、一致しない場合は0(ゼロ)を戻します。これはユーザー定義関数で、SQLの標準拡張方法の1つです。この関数には、型CONTEXTの索引が必要です。検索対象の列にCONTEXT索引がない場合、containsではエラーが発生します。

構文

contains([schema.]column, text_query VARCHAR2 [,label NUMBER])
RETURN NUMBER

例11-1 単純なCONTAINS問合せ

一般的な問合せは次のようになります。

SELECT id FROM purchase_orders WHERE contains(doc, 'lawn') > 0;

この問合せでは、表purchase_ordersおよび索引po_indexが使用されます。表purchase_orders内でdoc列にワード"lawn"が含まれる各行のIDが戻されます。

例11-2 構造化された述語を使用したCONTAINS

SQL関数containsは、すべてのSQL問合せで使用できます。次に、表purchase_ordersおよび索引po_indexの使用例を示します。

SELECT id FROM purchase_orders WHERE contains(doc, 'lawn') > 0 AND id < 25;

例11-3 XML構造を使用して問合せを限定するCONTAINS

docは、一連のXML文書が含まれる列であるとします。この場合、docに対して、そのXML構造を使用して問合せを限定する全文検索を実行できます。この問合せでは、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

SELECT id FROM purchase_orders WHERE contains(doc, 'lawn WITHIN comment') > 0;

例11-4 全文述語内で構造を使用したCONTAINS

INPATH演算子およびXPath式を使用すると、構造によるさらに複雑な限定を適用できます。この問合せでは、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

SELECT id FROM purchase_orders
  WHERE contains(doc, 'electric INPATH (/purchaseOrder/items/item/comment)') > 0;

XPath関数ora:containsの概要

XPath関数ora:containsは、XQuery式内のXPath式や、SQL関数existsNodeextractextractValueなどのコールで使用できます。この関数は、全文述語を使用する構造検索を限定する場合に使用されます。また、標準のメカニズムを使用してXPathを拡張する、Oracle XML DB名前空間ora内のユーザー定義関数です。索引は不要ですが、索引を併用することでパフォーマンスを向上できます。

構文

ora:contains(input_text NODE*, text_query STRING
             [,policy_name STRING]
             [,policy_owner STRING])

関数ora:containsは、input_texttext_queryと一致した場合は正の整数を戻します(数字が大きいほど、一致の関連性は高くなります)。一致しない場合は0(ゼロ)を戻します。XQuery式内部で使用される場合、XQueryの戻り型はxs:integer()です。XQuery式外部のXPath式で使用される場合、XPathの戻り型はnumberです。

引数input_textは単一のテキスト・ノードまたは属性に対して評価される必要があります。ora:containstext_queryの構文およびセマンティクスはcontainstext_queryと同じですが、次の制限事項があります。

  • 引数text_queryに構造演算子(WITHININPATHまたはHASPATH)を含めることはできません。

  • スコア重み付け演算子weightを使用した場合、重みは無視されます。

例11-5は、existsNodeのXPathパラメータにおけるora:containsのコールを示しています。existsNodeの3番目のパラメータ(Oracle XML DB名前空間ora)は必須ですので注意してください。この例では、表purchase_orders_xmltypeが使用されます。

例11-5 複雑な任意のテキスト問合せを使用したora:contains

SELECT id
  FROM purchase_orders_xmltype
  WHERE
    existsNode(doc,
               '/purchaseOrder/comment
                  [ora:contains(text(), "($lawns AND wild) OR flamingo") > 0]',
               'xmlns:ora="http://xmlns.oracle.com/xdb"')
    = 1;

関連項目:

ora:contains XPath関数の詳細は、「ora:contains XPath関数」を参照してください。

CONTAINSおよびora:containsの比較

containsおよびora:containsでは、いずれもXML構造の検索と全文検索を組み合せることができます。

SQL関数containsの特性は、次のとおりです。

  • 実行するにはCONTEXT索引が必要です。索引がない場合はエラーが発生します。

  • 索引検索を実行し、通常非常に高速です。

  • (SQL関数scoreを使用して)スコアを戻します。

  • ノードではなく文書(表の行)に基づいて検索を限定します。

  • XML構造ベースの投影(XML文書の一部を抽出)には使用できません。

XPath関数ora:containsの特性は、次のとおりです。

  • 索引は不要ですが、索引を使用することでパフォーマンスを向上できます。

  • 非索引検索であるため、大量のリソースを消費する場合があります。

  • 格納方法および索引付け方法に関する考慮事項からアプリケーション・ロジックを分離しています。

  • スコアを戻しません。

  • XML構造ベースの投影(XML文書の一部を抽出)に使用できます。

XML文書で、単純なXML構造の制約を指定している場合など、高速な索引ベースの全文検索を実行する場合は、containsを使用します。XPathナビゲーションと組み合せた全文検索の柔軟性が必要な場合(索引がない場合も含めて)、または投影は必要でスコアは不要な場合は、ora:containsを使用します。

CONTAINS SQL関数

この項の内容は次のとおりです。

SQL関数CONTAINSを使用した全文検索

SQL関数containsの2番目の引数text_queryは、全文検索を指定する文字列です。text_queryには、SQL/MMの全文標準に基づいた独自の言語があります。


関連項目:

  • ISO/IEC 13249-2:2000、「Information technology - Database languages - SQL Multimedia and Application Packages - Part 2: Full-Text」、International Organization For Standardization、2000

  • text_query言語の演算子の詳細は、『Oracle Textリファレンス』を参照してください。


この項の後半の例では、全文検索の優れた機能をいくつか示します。これらの例では、使用可能な演算子であるブール演算子(ANDORNOT)およびステミングをいくつか使用するだけです。例の問合せでは、テキスト索引(索引タイプCTXSYS.CONTEXT)を使用してVARCHAR2列(PURCHASE_ORDERS.doc)が検索されます。

全文ブール演算子AND、ORおよびNOT

text_query言語では、ANDORおよびNOTの任意の組合せがサポートされています。優先順位はカッコを使用して制御できます。ブール演算子は次のいずれの方法でも記述できます。

  • ANDORNOT

  • andornot

  • &|~

ここでは、NOTは単項演算子ではなくバイナリですので注意してください。式alpha NOT(beta)は、alpha AND unary-not(beta)と同等です。unary-notは単項否定を表します。


関連項目:

containsおよびora:containsで使用できる演算子の詳細は、『Oracle Textリファレンス』を参照してください。

例11-6 単純なブールを使用したCONTAINS問合せ

SELECT id FROM purchase_orders WHERE contains(doc, 'lawn AND wild') > 0;

この例では、表purchase_ordersおよび索引po_indexが使用されます。

例11-7 複雑なブールを使用したCONTAINS問合せ

SELECT id FROM purchase_orders
  WHERE contains(doc, '((lawn OR garden) AND (wild OR flooded)) NOT(flamingo)')
        > 0;

この例では、表purchase_ordersおよび索引po_indexが使用されます。

全文ステミング: $

text_query言語では、語幹検索がサポートされています。例11-8では、"lawns"と同じ言語語幹のワードが含まれるすべての文書が戻されるため、"lawn"または"lawns"が検索されます。ステミング演算子は、ドル記号($)で記述されます。演算子STEMまたはstemはありません。

例11-8 ステミングを使用したCONTAINS問合せ

SELECT id FROM purchase_orders WHERE contains(doc, '$(lawns)') > 0;

この例では、表purchase_ordersおよび索引po_indexが使用されます。

ブールとステミング演算子の組合せ

例11-9に示すように、text_query言語の演算子は任意に組み合せることができます。

例11-9 複雑な問合せ式を使用したCONTAINS問合せ

SELECT id FROM purchase_orders
  WHERE contains(doc, '($lawns AND wild) OR flamingo') > 0;

この例では、表purchase_ordersおよび索引po_indexが使用されます。


関連項目:

text_query演算子の完全なリストは、『Oracle Textリファレンス』を参照してください。

SCORE SQL関数

SQL関数containsには、関連付けられた関数scoreがあります。この関数は、問合せ内のどの場所でも使用できます。これは関連性を測定するもので、大規模なドキュメント・セット全体を全文検索するときに特に有効です。scoreは通常、問合せ結果の一部として戻されるか、ORDER BY句で使用されるか、あるいはその両方です。

構文

score(label NUMBER) RETURN NUMBER

例11-10score(10)では、結果セット内の各行に対するスコアが戻されます。SQL関数scoreは、関数containsの特定のコールに関する結果セット内の行の関連性を戻します。scoreのコールは、LABEL(この場合は番号10)によってcontainsのコールにリンクされます。

例11-10 SCOREを使用した単純なCONTAINS問合せ

SELECT score(10), id FROM purchase_orders
  WHERE contains(doc, 'lawn', 10) > 0 AND score(10) > 2
  ORDER BY score(10) DESC;

この例では、表purchase_ordersおよび索引po_indexが使用されます。

関数scoreは、対応するcontainsで、テキスト索引で規定された一致規則に従ってtext_query引数がinput_textと一致しない場合は、常に0を戻します。containstext_queryinput_textと一致した場合、scoreは、0より大きく100以下の数値を戻します。この数値は、input_textに対するtext_queryの関連性を示します。数値が大きいほど、一致精度が高いことを意味します。

containstext_queryHASPATH演算子およびText Pathのみで構成されている場合、HASPATHは完全一致をテストするため、スコアは0または100になります。


関連項目:

スコアの計算方法の詳細は、『Oracle Textリファレンス』を参照してください。

CONTAINS検索の範囲の限定

SQL関数containsでは、デフォルトで文書全体が全文検索されます。前述の例で、構造による限定のない"lawn"の検索では、発注書内のどこかにワード"lawn"があるすべての発注書が検索されます。

Oracleには、XML構造を使用してcontains問合せを限定する方法が3通りあります。

  • WITHIN

  • INPATH

  • HASPATH


注意:

この説明で、セクションはXMLノードと同じであると考えてください。

WITHIN構造演算子

WITHIN演算子は、問合せをXML文書内のあるセクションに限定します。コメント・セクションのどこかにワード"lawn"が含まれている発注書を検索するには、WITHINを使用します。セクション名の大/小文字は区別されます。

例11-11 WITHIN

SELECT id FROM purchase_orders WHERE contains(DOC, 'lawn WITHIN comment') > 0;

この例では、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

ネストしたWITHIN

WITHINをネストすると、問合せをさらに限定できます。例11-12では、セクション"comment"内にワード"lawn"が含まれ、"lawn"の出現箇所がセクション"item"内にもあるすべての文書が検索されます。

例11-12 ネストしたWITHIN

SELECT id FROM purchase_orders
  WHERE contains(doc, '(lawn WITHIN comment) WITHIN item') > 0;

この例では、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

例11-12では行が戻されません。使用する発注書サンプルには、コメント内にワード"lawn"が含まれています。しかし、項目内の唯一のコメントは"Confirm this is electric"です。そのため、ネストしたWITHIN問合せでは行が戻されません。

WITHIN(属性の場合)

属性内を検索することもできます。例11-13では、purchaseOrder要素のorderDate属性にワード"10"が含まれているすべての発注書が検索されます。

例11-13 属性内のWITHIN

SELECT id FROM purchase_orders
  WHERE contains(doc, '10 WITHIN purchaseOrder@orderDate') > 0;

この例では、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

デフォルトでは、マイナス記号(-)はワード・セパレータとして処理されます。つまり、"1999-10-20"は3つのワード"1999"、"10"および"20"として処理されます。したがって、この問合せでは1行戻されます。

属性内のテキストは、主検索可能文書の一部ではありません。text_queryWITHIN purchaseOrder@orderDateで修飾せずに10を検索すると、行は戻されません。

属性は、ネストしたWITHINでは検索できません。

WITHINおよびAND

コメント・セクション内にlawnとelectricの2つのワードが含まれる発注書を検索するとします。purchaseOrderにはコメント・セクションが複数ある場合があります。このため、この問合せの作成方法は2通りあり、異なる結果となります。

両方のワードが含まれ、各ワードがあるコメント・セクション内に出現する発注書を検索する場合は、例11-14のような問合せを作成します。

例11-14 WITHINおよびAND: あるコメント・セクション内の2つのワード

SELECT id FROM purchase_orders
  WHERE contains(doc, '(lawn WITHIN comment) AND (electric WITHIN comment)') > 0;

この例では、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

purchaseOrderデータに対してこの問合せを実行すると、1行戻されます。この例ではカッコは必要ありませんが、使用すると問合せがわかりやすくなります。

両方のワードが含まれ、両方のワードが同じコメント内に出現する発注書を検索する場合は、例11-15のような問合せを作成します。

例11-15 WITHINおよびAND: 同じコメント内の2つのワード

SELECT id FROM purchase_orders
  WHERE contains(doc, '(lawn AND electric) WITHIN comment') > 0;

この例では、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

例11-15では行は戻されません。例11-16のようにlawn AND electricを囲むカッコを外すと、1行戻されます。

例11-16 WITHINおよびAND: カッコを付けない場合

SELECT id FROM purchase_orders
  WHERE contains(doc, 'lawn AND electric WITHIN comment') > 0;

この例では、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

演算子WITHINの優先順位はANDより高いため、例11-16例11-17と同じように解析されます。

例11-17 WITHINおよびAND: 演算子優先順位を示すカッコ

SELECT id FROM purchase_orders
  WHERE contains(doc, 'lawn AND (electric WITHIN comment)') > 0;

この例では、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

セクションの定義

前述の例では、セクション内を検索するためにWITHIN演算子を使用しました。次のセクションを指定できます。

  • パス・セクションまたはゾーン・セクション

    このセクションは、ノードの子孫であるテキスト・ノードのすべてを、間を空白で区切って文書順に連結したものです。ノードからゾーン・セクションに変換するには、ノードをシリアライズしてすべてのタグを空白で置換する必要があります。パス・セクションの有効範囲と動作はゾーン・セクションと同じですが、パス・セクションではINPATHおよびHASPATH構造演算子を使用した問合せがサポートされます。

  • フィールド・セクション

    ゾーン・セクションと同じですが、文書内の繰返しノードが空白で区切られて単一のセクションに連結されます。

  • 属性セクション

  • 特殊セクション(文または段落)


    関連項目:

    特殊セクションの詳細は、『Oracle Textリファレンス』を参照してください。

INPATH構造演算子

演算子WITHINは、構造による単純な限定をtext_queryで表す簡単で直観的な方法です。豊富なXML構造を使用する問合せでは、ネストしたWITHIN演算子のかわりに、演算子INPATHとText Pathを使用できます。

演算子INPATHでは、左側にtext_queryを記述し、右側にカッコで囲んだText Pathを記述します。例11-18では、パス/purchaseOrder/items/item/comment内でワード"electric"が含まれるpurchaseOrdersが検索されます。

例11-18 全文述語内の構造: INPATH

SELECT id FROM purchase_orders
  WHERE contains(doc, 'electric INPATH (/purchaseOrder/items/item/comment)') > 0;

この例では、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

検索範囲は、Text Pathで示されたセクションです。例11-19に示すように、/purchaseOrder/itemsなどの範囲の広いパスを選択しても、戻されるのは1行です。

例11-19 全文述語内の構造: INPATH

SELECT id FROM purchase_orders
  WHERE contains(doc, 'electric INPATH (/purchaseOrder/items)') > 0;

この例では、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

Text Path

Text Pathの構文とセマンティクスは、W3CのXPath 1.0勧告に基づいています。単純なパス式はサポートされますが(省略構文のみ)、関数はサポートされません。以降の各例は、一般的な変形例を示しています。


関連項目:


例11-20では、属性partNumが"872-AA"と等しいitem要素の子であるcomment内にワード"electric"が含まれるすべての発注書が検索されます。このitem要素は、ルート・ノードからいくつか下のレベルのitems要素の子です。

例11-20 複雑なパス式を使用したINPATH(1)

SELECT id FROM purchase_orders
  WHERE contains(doc, 'electric INPATH (//items/item[@partNum="872-AA"]/comment)')
        > 0;

この例では、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

例11-21では、3番目のレベルであるitem要素(またはその子孫)内にワード"lawnmower"が含まれ、itemのいくつか下のレベルにcomment要素の子孫があるすべての発注書が検索されます。この問合せでは1行戻されます。問合せの有効範囲はcomment要素ではなく、子孫としてcomment要素を持つ一連のitem要素です。

例11-21 複雑なパス式を使用したINPATH(2)

SELECT id FROM purchase_orders
  WHERE contains(doc, 'lawnmower INPATH (/*/*/item[.//comment])') > 0;

この例では、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

Text PathとXPathの比較

Text Path言語は、XPath言語と次の点で異なります。

  • すべてのXPath演算子がText Path言語に含まれているわけではありません。

  • XPathの組込み関数はText Path言語に含まれていません。

  • Text Path言語の演算子は大/小文字が区別されません。

  • フィルタ内(カッコ内)で=を使用した場合、一致はテキスト一致規則に従います。

    大/小文字の区別、正規化、ストップワードおよび空白の規則はテキスト索引の定義によって異なります。この相違を強調するために、この種類の等価性をこのマニュアルではテキスト等値と呼びます。

  • 名前空間サポートはText Path言語に含まれていません。

    名前空間接頭辞(存在する場合)など、要素名は文字列として処理されます。そのため、同じ名前空間URIにマップされている2つの名前空間接頭辞は、Text Path言語では等価として処理されません。

  • Text Pathでは、コンテキストは常に文書のルート・ノードです。

    したがって、発注データpurchaseOrder/items/item/purchaseOrder/items/itemおよび./purchaseOrder/items/itemはすべて等価です。

  • 属性値内を検索する場合は、属性の直接の親を指定する必要があります(ワイルド・カードは使用できません)。

  • Text Pathはワイルド・カード(*)で終了できません。


関連項目:

Text Pathの文法については、「Text Path BNFの仕様」を参照してください。

ネストしたINPATH

INPATH式はネストできます。Text Pathのコンテキストは常にルート・ノードです。ネストしたINPATHの場合も変わりません。

例11-22では、任意のレベルのcomment要素にワード"electric"が含まれる発注書が検索されます。このワードの出現箇所は、最上位レベルpurchaseOrder要素の子であるitem要素内でもあります。

例11-22 ネストしたINPATH

SELECT id FROM purchase_orders
  WHERE contains(doc,
                 '(electric INPATH (//comment)) INPATH (/purchaseOrder/items)')
        > 0;

この例では、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

このネストしたINPATH問合せは、例11-23に示すように、簡潔に記述できます。

例11-23 リライト済のネストしたINPATH

SELECT id FROM purchase_orders
  WHERE contains(doc, 'electric INPATH (/purchaseOrder/items//comment)') > 0;

この例では、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

HASPATH構造演算子

演算子HASPATHで使用するオペランドはText Pathのみで、カッコで囲み、右側に記述します。=述語などを使用して、特定のパス内に特定のセクションが含まれる文書を検索するときは、HASPATHを使用します。これは全文検索ではなく、パス検索です。セクションが存在するかどうかの確認、またはセクションの内容の照合はできますが、ワード検索はできません。データ型がXMLTypeの場合は、構造演算子HASPATHではなくSQL関数existsNodeの使用を考慮してください。

例11-24では、USPriceを持つ項目があるpurchaseOrdersが検索されます。

例11-24 単純なHASPATH

SELECT id FROM purchase_orders
  WHERE contains(DOC, 'HASPATH (/purchaseOrder//item/USPrice)') > 0;

この例では、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

例11-25では、"148.95"とテキスト等値であるUSPriceを持つ項目があるpurchaseOrdersが検索されます。


関連項目:

テキスト等値の説明は、「Text PathとXPathの比較」を参照してください。

例11-25 HASPATHの等値式

SELECT id FROM purchase_orders
  WHERE contains(doc, 'HASPATH (/purchaseOrder//item/USPrice="148.95")') > 0;

この例では、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

HASPATHは、INPATHなど他のcontains演算子と組み合せることができます。例11-26では、文書の任意の場所にワード electricを含み、148.95とテキスト等値であるUSPriceを持つitemがあり、かつpurchaseOrder属性orderDate内に10が含まれるpurchaseOrdersが検索されます。

例11-26 HASPATHと他の演算子の組合せ

SELECT id FROM purchase_orders
  WHERE contains(doc,
                 'electric
                  AND HASPATH (/purchaseOrder//item/USPrice="148.95")
                  AND 10 INPATH (/purchaseOrder/@orderDate)')
        > 0;

この例では、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

CONTAINS結果の投影

WHERE句内にcontains式を使用したSQL問合せの結果は常に、行のセット(および多くの場合score情報)、または問合せと一致する行全体の投影です。contains式を満たす各XML文書の一部のみを戻すには、SQL関数extractおよびextractValueを使用します。extractおよびextractValueXMLTypeで動作するため、次の例では表 purchase_orders_xmltypeが使用されることに注意してください。

例11-27では、最上位レベルのpurchaseOrder要素の子孫であるcomment要素内にワード"electric"が含まれるpurchaseOrderが検索されます。各結果の行IDを戻すかわりに、extractを使用してcomment要素のみを戻します。

例11-27 extractを使用したCONTAINS問合せの結果の範囲指定

SELECT extract(doc,
               '/purchaseOrder//comment',
               'xmlns:ora="http://xmlns.oracle.com/xdb"') "Item Comment"
  FROM purchase_orders_xmltype
  WHERE contains(doc, 'electric INPATH (/purchaseOrder//comment)') > 0;

この例では、表purchase_orders_xmltypeおよび索引po_index_xmltypeが使用されます。

例11-27の結果は、comment要素の2つの実例であることに注意してください。関数containsは、comment要素内にワード"electric"の含まれている行(ID=1の行)を示します。extract関数は、文書内のその行にあるcomment要素の実例をすべて抽出します。使用しているpurchaseOrder要素にはcomment要素の実例が2つあり、問合せではその両方が戻されます。

これは希望の結果と異なる場合があります。contains式を満たすcomment要素の実例のみを問合せで戻す場合は、extract式でその述語を繰り返す必要があります。これには、XPath関数ora:containsを使用します。

例11-28では、contains式と一致するcomment要素のみが戻されます。

例11-28 EXTRACTとora:containsを使用したCONTAINS問合せ結果の投影

SELECT
  extract(doc,
          '/purchaseOrder/items/item/comment
            [ora:contains(text(), "electric") > 0]',
          'xmlns:ora="http://xmlns.oracle.com/xdb"') "Item Comment"
  FROM purchase_orders_xmltype
  WHERE contains(doc, 'electric INPATH (/purchaseOrder/items/item/comment)') > 0;

この例では、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

CONTEXT索引を使用した索引付け

この項の内容は次のとおりです。

CONTEXT索引の概要

汎用の全文索引タイプは、データベース・ユーザーCTXSYSが所有するCONTEXT索引タイプです。デフォルトの全文索引を作成するには、例11-29に示すように、通常のSQL CREATE INDEXコマンドを使用し、句INDEXTYPE IS CTXSYS.CONTEXTを追加します。

例11-29 表PURCHASE_ORDERSの単純なCONTEXT索引

CREATE INDEX po_index ON purchase_orders(doc)
  INDEXTYPE IS CTXSYS.CONTEXT ;

この例では、表PURCHASE_ORDERSが使用されます。

全文索引を作成するときには、多数の選択肢があります。これらの選択肢は、索引付けプリファレンスとして表されます。索引付けプリファレンスを使用するには、例11-30に示すように、CREATE INDEXPARAMETERS句を追加します。

例11-30 パス・セクション・グループを使用した表PURCHASE_ORDERSの単純なCONTEXT索引

CREATE INDEX po_index ON purchase_orders(doc)
  INDEXTYPE IS CTXSYS.CONTEXT
  PARAMETERS ('section group CTXSYS.PATH_SECTION_GROUP');

この例では、表purchase_ordersが使用されます。

Oracle Textには、CTXCATCTXRULEなどの他の索引タイプが用意されていますが、この章では説明しません。


関連項目:

CONTEXT索引の詳細は、『Oracle Textリファレンス』を参照してください。

XMLType表のCONTEXT索引

CONTEXT索引は、テキストが含まれた任意のデータに対して作成できます。例11-29では、VARCHAR2列に対するCONTEXT索引が作成されます。型がCHARVARCHARVARCHAR2BLOBCLOBBFILEXMLTypeまたはURITypeの列にCONTEXT索引を作成する構文は同じです。例11-31では、型XMLTypeの列に対するCONTEXT索引が作成されます。

例11-31 表PURCHASE_ORDERS_xmltypeの単純なCONTEXT索引

CREATE INDEX po_index_xmltype ON purchase_orders_xmltype(doc)
  INDEXTYPE IS CTXSYS.CONTEXT;

この例では、表purchase_orders_xmltypeが使用されます。セクション・グループはデフォルトでPATH_SECTION_GROUPに設定されます。

表の型がXMLTypeである場合は、例11-32に示すように、オブジェクト構文を使用してCONTEXT索引を作成する必要があります。

例11-32 XMLType表の単純なCONTEXT索引

CREATE INDEX po_index_xmltype_table
  ON purchase_orders_xmltype_table (OBJECT_VALUE)
  INDEXTYPE IS CTXSYS.CONTEXT;

この例では、表purchase_orders_xmltypeが使用されます。

例11-33の構文を使用して、表を問合せできます。

例11-33 XMLType表のCONTAINS問合せ

SELECT extract(OBJECT_VALUE, '/purchaseOrder/@orderDate') "Order Date"
  FROM purchase_orders_xmltype_table
  WHERE contains(OBJECT_VALUE, 'electric INPATH (/purchaseOrder//comment)') > 0;

この例では、表purchase_orders_xmltype_tableおよび索引po_index_xmltype_tableが使用されます。

CONTEXT索引のメンテナンス

ほとんどの全文索引と同様に、CONTEXT索引は非同期です。索引付けされたデータが変更された場合、CONTEXT索引は、プロシージャをコールして索引を同期化するなど、なんらかの処理を行うまで変更されません。CONTEXT索引の変更を管理する方法は複数あり、いくつかは今回のリリースでの新機能です。

CONTEXT索引は、時間経過とともに断片化される可能性があります。断片化された索引では通常より多くの領域が使用されるため、問合せが遅くなります。CONTEXT索引の最適化(断片化解消)方法は複数あり、いくつかは今回のリリースでの新機能です。


関連項目:

CONTEXT索引のメンテナンスの詳細は、『Oracle Textリファレンス』を参照してください。

ロールおよび権限

CONTEXT索引の作成に特別な権限は必要ありません。プリファレンスの作成と削除、およびOracle TextのPL/SQLパッケージの使用には、CTXAPPロールが必要です。また、CTXSYSパッケージCTX_DDLに対するEXECUTE権限も必要です。

CONTAINSにおけるCONTEXT索引の効果

SQL関数containsを使用するには、CONTEXT型の索引を作成する必要があります。containsをコールしたとき、最初の引数で指定された列にCONTEXT型の索引がない場合は、エラーが発生します。

text_queryの構文およびセマンティクスは、CONTEXT索引の作成時に選択した内容によって異なります。次に例を示します。

  • ワードとしてカウントする対象

  • 最も一般的なワードを処理対象とするかどうか

  • 最も一般的なワード

  • テキスト検索で大/小文字を区別するかどうか

  • テキスト検索にキーワードの他にテーマ(概念)を含めることができるかどうか

CONTEXT索引プリファレンス

プリファレンスは、索引付けに関する選択肢の集合と考えることができます。プリファレンスには、セクション・グループ、データストア、フィルタ、ワードリスト、ストップリストおよび記憶域が含まれます。この項では、検索で大/小文字を区別するためのレクサー・プリファレンスの設定方法を示します。

プリファレンスを作成するには、プロシージャCTX_DDL.create_preference(またはCTX_DDL.create_stoplist)を使用します。プロシージャCTX_DDL.set_attributeを使用して新規プリファレンスの属性を設定することによって、そのプリファレンス・グループのデフォルトの選択肢をオーバーライドします。その後、CREATE INDEXPARAMETERS文字列内にpreference type preference_nameを含めることによって、CONTEXT索引でプリファレンスを使用します。

プリファレンスを作成すると、それを使用して索引をいくつでも作成できます。

検索で大/小文字を区別する方法

containsを使用した全文検索では、デフォルトで大/小文字が区別されません。つまり、文書内のワードに対してtext_query内のワードを照合する際に、大/小文字は考慮されません。ただし、セクション名および属性名は常に、大/小文字が区別されます。

全文検索で大/小文字を区別する場合は、CONTEXT索引の作成時にそのように選択する必要があります。例11-34では1行戻されます。これは、text_query内の"HURRY"が、デフォルトの大/小文字が区別されない索引が設定されたpurchaseOrder内の"Hurry"と一致するためです。

例11-34 CONTAINS: デフォルトの大/小文字を区別しない一致

SELECT id FROM purchase_orders
  WHERE contains(doc, 'HURRY INPATH (/purchaseOrder/comment)') > 0;

この例では、表purchase_ordersおよび索引po_index-path-sectionが使用されます。

例11-35では、属性mixed_caseTRUEに設定された新規のレクサー・プリファレンスmy_lexerが作成されます。この例では、printjoin文字も"-"、"!"、","に設定されます。CONTEXT索引の作成およびポリシーの作成に同じプリファレンスを使用できます。


関連項目:

レクサー属性の完全なリストは、『Oracle Textリファレンス』を参照してください。

例11-35 大/小文字混合のプリファレンスの作成

BEGIN
  CTX_DDL.create_preference(PREFERENCE_NAME  =>  'my_lexer',
                            OBJECT_NAME      =>  'BASIC_LEXER');

  CTX_DDL.set_attribute(PREFERENCE_NAME  =>  'my_lexer',
                        ATTRIBUTE_NAME   =>  'mixed_case',
                        ATTRIBUTE_VALUE  =>  'TRUE');

  CTX_DDL.set_attribute(PREFERENCE_NAME  =>  'my_lexer',
                        ATTRIBUTE_NAME   =>  'printjoins',
                        ATTRIBUTE_VALUE  =>  '-,!');
END ;
/

例11-36では、my_lexerという新しいレクサー・プリファレンスを使用してCONTEXT索引が作成されます。

例11-36 PURCHASE_ORDERS表のCONTEXT索引、大/小文字混合

CREATE INDEX po_index ON purchase_orders(doc)
  INDEXTYPE IS CTXSYS.CONTEXT
  PARAMETERS('lexer my_lexer section group CTXSYS.PATH_SECTION_GROUP');

この例では、表purchase_ordersおよびプリファレンスpreference-case-mixedが使用されます。

例11-34では、text_query内の"HURRY"がpurchaseOrder内の"Hurry"と一致しないため、行は戻されません。例11-37では、text_queryの"Hurry"がpurchaseOrder内のワード"Hurry"と正確に一致するため、1行戻されます。

例11-37 CONTAINS: 大/小文字混合の(正確な)一致

SELECT id FROM purchase_orders
  WHERE contains(doc, 'Hurry INPATH (/purchaseOrder/comment)') > 0;

この例では、表purchase_ordersおよび索引po_index-case-mixedが使用されます。

セクション・グループの概要

CONTEXT索引の作成時に行う選択の1つにセクション・グループがあります。セクション・グループ・インスタンスは、セクション・グループ・タイプに基づいています。セクション・グループ・タイプでは、文書の構造の種類、およびその構造の索引付け方法(したがって検索方法)が指定されます。セクション・グループ・インスタンスによって、索引付けされる構造要素が指定される場合もあります。ほとんどのユーザーは、デフォルトのセクション・グループまたは事前定義のセクション・グループのいずれかを使用します。

セクション・グループ・タイプの選択

XMLの検索で有効なセクション・グループ・タイプは、次のとおりです。

  • PATH_SECTION_GROUP

    問合せでWITHININPATHおよびHASPATHを使用し、すべてのセクションを問合せの有効範囲とする場合はこのタイプを選択します。

  • XML_SECTION_GROUP

    問合せでWITHINを使用するが、INPATHおよびHASPATHは使用せず、明示的に定義されたセクションのみを問合せの有効範囲とする場合は、このタイプを選択します。XML_SECTION_GROUPセクション・グループ・タイプでは、ZONEセクションの他にFIELDセクションがサポートされます。状況によっては、FIELDセクションの方が問合せのパフォーマンスが大幅に向上する場合があります。

  • AUTO_SECTION_GROUP

    問合せでWITHINを使用するが、INPATHおよびHASPATHは使用せず、大部分のセクションを問合せの有効範囲とする場合は、このタイプを選択します。デフォルトでは、すべてのセクションが索引付けされます(問合せの限定に使用可能)。一部のセクションには索引付けしないことを指定できます(STOPセクションを定義)。

  • NULL_SECTION_GROUP

    XMLセクションを定義しない場合は、このタイプを選択します。

その他のセクション・グループ・タイプは、次のとおりです。

  • BASIC_SECTION_GROUP

  • HTML_SECTION_GROUP

  • NEWS_SECTION_GROUP

XMLの全文検索要件がある大部分のユーザーは、PATH_SECTION_GROUPを使用することをお薦めします。一部のユーザーには、FIELDセクションを使用するXML_SECTION_GROUPの使用が適している場合もあります。この選択によって、通常、問合せパフォーマンスが向上し、索引が小さくなりますが、フィールド化構造の文書に限定されます(検索可能なノードは、繰返しのないすべてのリーフ・ノードです)。


関連項目:

XML_SECTION_GROUPセクション・グループ・タイプの詳細は、『Oracle Textリファレンス』を参照してください。

セクション・グループの選択

索引で使用するセクション・グループを選択するときは、選択したセクション・グループ・タイプに基づいて、提供されているセクション・グループを選択するか、デフォルトを使用するか、または新しいセクション・グループを作成するかを選択できます。

セクション・グループ・タイプPATH_SECTION_GROUPAUTO_SECTION_GROUPおよびNULL_SECTION_GROUPには、提供されているセクション・グループがあります。提供されているセクション・グループの所有者はCTXSYSで、名前はセクション・グループ・タイプと同じです。たとえば、セクション・グループ・タイプPATH_SECTION_GROUPの提供されているセクション・グループはCTXSYS.PATH_SECTION_GROUPです。

セクション・グループ・タイプXML_SECTION_GROUPには提供されているセクション・グループがありません。これは、デフォルトのXML_SECTION_GROUPは空であり、無意味であるためです。セクション・グループ・タイプXML_SECTION_GROUPを使用する場合は、新しいセクション・グループを作成し、セクションとして組み込む各ノードを指定する必要があります。

XMLType型のデータにCONTEXT索引を作成した場合、デフォルトのセクション・グループは、提供されているセクション・グループCTXSYS.PATH_SECTION_GROUPです。データがVARCHARまたはCLOBの場合、デフォルトのセクション・グループはCTXSYS.NULL_SECTION_GROUPです。


関連項目:

独自のセクション・グループを作成する方法は、『Oracle Textリファレンス』を参照してください。

セクション・グループを索引と関連付けるには、例11-38のように、PARAMETERS文字列にsection group <section group name>を追加します。

例11-38 パス・セクション・グループを使用したpurchase_orders表の単純なCONTEXT索引

CREATE INDEX po_index ON purchase_orders(doc)
  INDEXTYPE IS CTXSYS.CONTEXT
  PARAMETERS ('section group CTXSYS.PATH_SECTION_GROUP');

この例では、表purchase_ordersが使用されます。

ora:contains XPath関数

関数ora:containsは、SQL関数existsNodeextractおよびextractValueのXPath引数で使用するために、Oracleによって定義されたXPath関数です。

ora:containsの関数名は、名前(contains)および名前空間接頭辞(ora)で構成されます。existsNodeextractまたはextractValueora:containsを使用するときは、名前空間マッピング・パラメータxmlns:ora="http://xmlns.oracle.com/xdb"も指定する必要があります。

ora:containsは、スコアではなく数値を戻します。text_queryinput_textと一致した場合、正数を戻します。そうでない場合は0(ゼロ)を戻します。

XPath関数ora:containsを使用した全文検索

ora:containsの引数text_queryは、全文検索を指定する文字列です。ora:containstext_querycontainstext_queryと同じですが、次の制限事項があります。

  • ora:containstext_queryには、構造演算子WITHININPATHまたはHASPATHを含めることができません。

  • ora:containstext_queryには、スコア重み付け演算子weight(*)を含めることができますが、重みは無視されます。

ora:containstext_queryに次のいずれかの演算子を含めた場合は、その問合せでCONTEXT索引を使用できません。

  • スコアベースの演算子MINUS(-)またはthreshold>

  • 選択的なコーパスベースの拡張演算子FUZZY?)またはsoundex!

例11-39に、ブール演算子と$(ステミング)を任意に組み合せた全文検索を示します。

例11-39 複雑な任意のテキスト問合せを使用したora:contains

SELECT id FROM purchase_orders_xmltype
  WHERE existsNode(doc,
                   '/purchaseOrder/comment
                     [ora:contains(text(), "($lawns AND wild) OR flamingo") > 0]',
                   'xmlns:ora="http://xmlns.oracle.com/xdb"')
        = 1;

この例では、表purchase_orders_xmltypeが使用されます。


関連項目:

  • 全文演算子の詳細は、「関数CONTAINSを使用した全文検索」を参照してください。

  • containsおよびora:containsで使用できる演算子の完全なリストは、『Oracle Textリファレンス』を参照してください。


一致規則は、ポリシーpolicy_owner.policy_nameで定義されます。policy_ownerの指定がない場合、ポリシー所有者はデフォルトで現行ユーザーに設定されます。policy_namepolicy_ownerの両方が指定されない場合、ポリシーはデフォルトでCTXSYS.DEFAULT_POLICY_ORACONTAINSに設定されます。

ora:contains問合せの範囲の限定

XPath式でora:containsを使用する場合、有効範囲は引数input_textで定義されます。この引数は、現在のXPathのコンテキスト内で評価されます。結果が単一のテキスト・ノードまたは属性の場合、そのノードはora:contains検索のターゲットです。input_textが単一のテキスト・ノードまたは属性に対して評価されない場合は、エラーが発生します。

ポリシーによって、ora:containsの一致規則が決定されます。ora:containsのデフォルト・ポリシーに関連付けられたセクション・グループの型はNULL_SECTION_GROUPです。

ora:containsはXPath式のどこでも使用でき、そのinput_text引数は単一のテキスト・ノードまたは属性に対して評価されるXPath式です。

ora:contains結果の投影

各XML文書の一部のみを戻す場合は、ノード順序を投影するextract、またはノードの値を投影するextractValueを使用します。

例11-40 EXISTSNODEおよびEXTRACT内のora:contains

この例では、ワード"lawn"を含むcommentがある各purchaseOrderorderDateが戻されます。表purchase_orders_xmltypeが使用されます。

SELECT extract(doc, '/purchaseOrder/@orderDate') "Order date"
  FROM purchase_orders_xmltype
  WHERE existsNode(doc,
                   '/purchaseOrder/comment[ora:contains(text(), "lawn") > 0]',
                   'xmlns:ora="http://xmlns.oracle.com/xdb"')
        = 1;

関数existsNodeは、ワード"lawn"の入ったcommentpurchaseOrder要素に含まれる行(文書)に結果を限定します。その後、関数extractが、それらのpurchaseOrder要素から属性orderDateの値を戻します。//commentが抽出されていれば、WHERE句と一致したコメントのみではなく、両方のコメントがサンプル・ドキュメントから戻されます。

ora:contains問合せのポリシー

列のCONTEXT索引によって、その列に対するcontains問合せのセマンティクスが決まります。ora:containsはサポートしている索引に依存しないため、ora:contains問合せを実行するときは、同様の選択肢を多数提供する他の方法を検索する必要があります。ポリシーは、ora:contains問合せに関連付けることができるプリファレンスの集合であり、索引付けに関する選択でcontainsユーザーに提供される内容と同じようなセマンティクス制御を提供します。

ora:contains問合せのポリシーの概要

SQL関数containsを使用すると、索引付けのプリファレンスが問合せのセマンティクスに影響を与えます。プロシージャCTX_DDL.create_preference(またはCTX_DDL.create_stoplist)を使用して、プリファレンスを作成します。プロシージャCTX_DDL.set_attributeを使用して新規プリファレンスの属性を設定することによって、デフォルトの選択肢をオーバーライドします。その後、CREATE INDEXPARAMETERS文字列内にpreference_type preference_nameを含めることによって、CONTEXT索引でプリファレンスを使用します。

ora:containsにはサポートしている索引がないため、問合せにプリファレンスを適用するには、別のメカニズムが必要です。そのメカニズムはポリシーであり、プリファレンスの集合で構成されます。これはora:containsのパラメータとして使用されます。

ポリシーの例: 提供されているストップリスト

例11-41では、空のストップワード・リストを持つポリシーが作成されます。

例11-41 ora:containsで使用するポリシーの作成

BEGIN
  CTX_DDL.create_policy(POLICY_NAME  =>  'my_nostopwords_policy',
                        STOPLIST     =>  'CTXSYS.EMPTY_STOPLIST');
END;
/

わかりやすいように、このポリシーは空のストップリストで構成されており、所有者はユーザーCTXSYSです。このポリシーに組み込む新しいストップリストを作成するか、またはCONTEXT索引用に作成したストップリスト(またはレクサー)定義を再利用できます。

最も一般的なワード(ストップワード)も含めてすべてのワードを検索するには、ora:contains式でこのポリシーを参照してください。例11-42では、"is"はデフォルトでストップワードであり問合せできないため、コメントは戻されません。

例11-42 ora:containsを使用した一般的なワードの問合せ

SELECT id FROM purchase_orders_xmltype
  WHERE existsNode(doc,
                   '/purchaseOrder/comment[ora:contains(text(), "is") > 0]',
                   'xmlns:ora="http://xmlns.oracle.com/xdb"')
        = 1;

この例では、表purchase_orders_xmltypeが使用されます。

例11-43では、空のストップワード・リストを指定するために、例11-41で作成されたポリシーが使用されます。この問合せでは"is"が検索され、コメントが1つ戻されます。

例11-43 ora:containsおよびポリシーmy_nostopwords_policyを使用した一般的なワードの問合せ

SELECT id FROM purchase_orders_xmltype
  WHERE existsNode(doc,
                   '/purchaseOrder/comment
                     [ora:contains(text(), "is", "MY_NOSTOPWORDS_POLICY") > 0]',
                   'xmlns:ora="http://xmlns.oracle.com/xdb"')
        = 1;

この例では、表purchase_orders_xmltypeおよびポリシーmy_nostopwords_policyが使用されます。(例11-41では、このポリシーの名前は暗黙的にすべて大文字になります。XPathでは大/小文字が区別されるため、XPath述語内でこのポリシーは、my_nostopwords_policyではなくMY_NOSTOPWORDS_POLICYのように、すべて大文字を使用して記述する必要があります。)

ora:containsでのポリシーの効果

ora:containsポリシーは、text_queryの一致セマンティクスに影響を与えます。ora:containsポリシーには、レクサー、ストップリスト、ワードリスト・プリファレンスまたはこれらの組合せが含まれる場合があります。CONTEXT索引の作成に使用できる他のプリファレンスは、ora:containsには適用できません。プリファレンスの効果は次のとおりです。

  • ワードリスト・プリファレンスによって、ステミング演算子のセマンティクスが改良されます。

  • ストップリスト・プリファレンスによって、一般的であるために索引付け(検索可能に)しないワードが定義されます。

  • レクサー・プリファレンスによって、ワードのトークン化および一致方法が定義されます。たとえば、ワードの一部としてカウントする文字および一致で大/小文字を区別するかどうかが定義されます。


関連項目:


ポリシーの例: ユーザー定義レクサー

特定のワードが含まれる文書を検索する場合は通常、検索で大/小文字を区別しない方法が使用されます。大/小文字を区別する検索を実行すると、予期した結果を得られない場合があリます。たとえば、"baby monitor"という句が含まれるpurchaseOrdersを検索する場合、使用しているサンプル文書では"Baby Monitor"と記述されているというだけの理由で、この文書の検索が行われないとは予測しません。

ora:containsを使用した全文検索では、デフォルトで大/小文字が区別されません。ただし、セクション名および属性名は常に、大/小文字が区別されます。

全文検索で大/小文字を区別する場合は、ポリシーの作成時にそのように選択する必要があります。次の手順を使用します。

  1. プロシージャCTX_DDL.create_preference(またはCTX_DDL.create_stoplist)を使用して、プリファレンスを作成します。

  2. プロシージャCTX_DDL.set_attributeを使用して新規プリファレンスの属性を設定することによって、そのプリファレンス・オブジェクトのデフォルトの選択肢をオーバーライドします。

  3. そのプリファレンスをCTX_DDL.create_policyのパラメータとして使用します。

  4. 問合せではora:containsの3番目の引数として、ポリシー名を使用します。

プリファレンスを作成した後は、そのプリファレンスを他のポリシーまたはCONTEXT索引の定義で再利用できます。すべてのora:contains問合せで、任意のポリシーを使用できます。

例11-44では1行戻されます。これは、text_query内の"HURRY"が、デフォルトの大/小文字が区別されない索引が設定されたpurchaseOrder内の"Hurry"と一致するためです。

例11-44 ora:contains、デフォルトの大/小文字の区別

SELECT id FROM purchase_orders_xmltype
  WHERE existsNode(doc,
                   '/purchaseOrder/comment[ora:contains(text(), "HURRY") > 0]',
                   'xmlns:ora="http://xmlns.oracle.com/xdb"')
        = 1;

この例では、表purchase_orders_xmltypeが使用されます。

例11-45では、属性mixed_caseTRUEに設定された新しいレクサー・プリファレンスmy_lexerが作成されます。この例では、printjoin文字も"-"、"!"、","に設定されます。CONTEXT索引の作成およびポリシーの作成に同じプリファレンスを使用できます。


関連項目:

レクサー属性の完全なリストは、『Oracle Textリファレンス』を参照してください。

例11-45 大/小文字混合のプリファレンスの作成

BEGIN
  CTX_DDL.create_preference(PREFERENCE_NAME  =>  'my_lexer',
                            OBJECT_NAME      =>  'BASIC_LEXER');
  CTX_DDL.set_attribute(PREFERENCE_NAME  =>  'MY_LEXER',
                        ATTRIBUTE_NAME   =>  'MIXED_CASE',
                        ATTRIBUTE_VALUE  =>  'TRUE');
  CTX_DDL.set_attribute(PREFERENCE_NAME  =>  'my_lexer',
                        ATTRIBUTE_NAME   =>  'printjoins',
                        ATTRIBUTE_VALUE  =>  '-,!');
END ;
/

例11-46では、新規ポリシーmy_policyが作成され、レクサーのみが指定されます。他のプリファレンスはすべてデフォルトに設定されます。

例11-46 大/小文字混合の(大/小文字が区別されない)ポリシーの作成

BEGIN
  CTX_DDL.create_policy(POLICY_NAME  => 'my_policy',
                        LEXER        => 'my_lexer');
END ;
/

この例ではpreference-case-mixedが使用されます。

例11-47では、問合せで新規ポリシーが使用されます。text_query内の"HURRY"は、purchaseOrder内の"Hurry"と一致しないため、行は戻されません。

例11-47 ora:contains、大/小文字の区別(1)

SELECT id FROM purchase_orders_xmltype
  WHERE existsNode(doc,
                   '/purchaseOrder/comment
                     [ora:contains(text(), "HURRY", "my_policy") > 0]',
                   'xmlns:ora="http://xmlns.oracle.com/xdb"')
        = 1;

この例では、表purchase_orders_xmltypeが使用されます。

例11-48では、text_queryの"Hurry"がcomment要素内のテキスト"Hurry"と正確に一致するため、1行戻されます。

例11-48 ora:contains、大/小文字の区別(2)

SELECT id FROM purchase_orders_xmltype
  WHERE existsNode(doc,
                   '/purchaseOrder/comment
                     [ora:contains(text(), "Hurry") > 0]',
                   'xmlns:ora="http://xmlns.oracle.com/xdb"')
        = 1;

この例では、表purchase_orders_xmltypeが使用されます。

ポリシーのデフォルト

ora:containsのポリシーの引数はオプションです。省略した場合、問合せではデフォルトのポリシーCTXSYS.DEFAULT_POLICY_ORACONTAINSが使用されます。

ora:containsで使用するポリシーを作成するときは、すべてのプリファレンスを指定する必要はありません。たとえば、例11-46では、レクサー・プリファレンスのみが指定されていました。指定されないプリファレンスについては、CREATE_POLICYによって次のデフォルトのプリファレンスが使用されます。

  • CTXSYS.DEFAULT_LEXER

  • CTXSYS.DEFAULT_STOPLIST

  • CTXSYS.DEFAULT_ WORDLIST

ポリシーの作成では、CONTEXT索引の作成が索引メタデータのコピー・セマンティクスに従うのと同様に、プリファレンスとその属性のコピー・セマンティクスに従います。

ora:containsのパフォーマンス

ora:containsのXPath関数は、サポートしている索引に依存しません。ora:containsは非常に柔軟性があります。しかし、索引のない大量のデータを検索する場合、大量のリソースを消費することもあります。この項では、ora:containsを使用するXPath式が含まれる問合せのパフォーマンスを最大にする方法を説明します。


注意:

ファンクション索引はXML問合せの高速化にも非常に有効ですが、一般的にテキスト問合せには適用できません。

この項の例では、表PURCHASE_ORDERS_xmltype_bigが使用されます。この表には、PURCHASE_ORDERS_xmltypeと同じ表構造とXML Schemaがありますが、約1,000行が格納されています。各行には、(id列に)一意のIDと、/purchaseOrder/items/item/comment内に少しずつ異なるテキストが含まれています。示されている実行計画は、SQL*PlusコマンドAUTOTRACEを使用して生成されたものです。実行計画は、SQLコマンドTRACEおよびTKPROFを使用しても生成できます。コマンドAUTOTRACEtraceおよびtkprofについては、この章で説明しません。

この項の内容は次のとおりです。

問合せでの1次フィルタの使用

ora:containsは、処理のコストが比較的かかるため、可能な場合は1次フィルタを組み込んだ問合せの作成をお薦めします。この結果、ora:containsで処理される行数が最小化されます。

例11-49では、例11-50の計画からわかるように、表内のすべての行が検査されます(全表スキャンの実行)。この例で、ora:containsはすべての行に対して評価されます。

例11-49 EXISTSNODE内のora:contains、大規模な表

SELECT id FROM purchase_orders_xmltype_big
  WHERE existsNode(doc,
                   '/purchaseOrder/items/item/comment
                     [ora:contains(text(), "constitution") > 0]',
                   'xmlns:ora="http://xmlns.oracle.com/xdb"')
        = 1;

例11-50 EXPLAIN PLAN: EXISTSNODE

Execution Plan
----------------------------------------------------------
0      SELECT STATEMENT Optimizer=CHOOSE
1     0   TABLE ACCESS (FULL) OF 'PURCHASE_ORDERS_XMLTYPE_BIG' (TABLE)

例11-51に示すようにid列に索引を作成し、例11-52に示すように選択的なid述語を問合せに追加した場合は、例11-53からもわかるように、Oracleではid索引が使用されません。ora:containsは、id述語がtrue(idが5未満)の行に対してのみ実行されます。

例11-51 IDのBツリー索引

CREATE INDEX id_index ON purchase_orders_xmltype_big(id);

この例では、表purchase_ordersが使用されます。

例11-52 EXISTSNODE内のora:contains、問合せの混合

SELECT id FROM purchase_orders_xmltype_big
  WHERE existsNode(doc,
                   '/purchaseOrder/items/item/comment
                     [ora:contains(text(), "constitution") > 0]',
                   'xmlns:ora="http://xmlns.oracle.com/xdb"')
        = 1
    AND id > 5;

例11-53 EXPLAIN PLAN: EXISTSNODE

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0    TABLE ACCESS (BY INDEX ROWSELECT ID) OF 'PURCHASE_ORDERS_XMLTYPE_BIG' (TABLE)
   2    1         INDEX (RANGE SCAN) OF 'SELECT ID_INDEX' (INDEX)

XPathリライトおよびCONTEXT索引

ora:containsはサポートしている索引に依存しません。ただし、状況によっては、パフォーマンス向上のために、ora:containsで既存のCONTEXT索引が使用される場合があります。

XPathリライトのメリット

Oracleでは、状況によってSQL/XML問合せがオブジェクト・リレーショナル問合せにリライトされます。これは問合せ最適化の一部として行われ、ユーザーに対しては透過的です。XPathリライトには、次の2つのメリットがあります。

  • リライトされた問合せは、XML文書全体を処理するかわりに、基礎となるオブジェクト・リレーショナル表に直接アクセスできます。

  • リライトされた問合せは使用可能な索引をすべて利用できます。

XPathリライトは、パフォーマンスの最適化です。XPathリライトが実行されるのは、XMLデータがオブジェクト・リレーショナル形式で格納される場合、つまりXMLデータがXML Schemaに基づく必要がある場合のみです。


関連項目:


文書からノードへの変換

単純なora:contains問合せである例11-54について考えてみます。この問合せのXPath式をネイティブに処理するには、doc列内の各セルを考慮する必要があり、各セルがこのXPath式と一致しているかどうかをテストする必要があります。

/purchaseOrder/items/item/comment[ora:contains(text(), "electric")>0]

例11-54 EXISTSNODE内のora:contains

SELECT id FROM purchase_orders_xmltype
  WHERE existsNode(doc,
                   '/purchaseOrder/items/item/comment
                     [ora:contains(text(), "electric") > 0]',
                   'xmlns:ora="http://xmlns.oracle.com/xdb"')
        = 1 ;

この例では、表purchase_orders_xmltypeが使用されます。

しかし、docがXML Schemaに基づいており、purchaseOrder文書がオブジェクト・リレーショナル表に物理的に格納されている場合は、列/purchaseOrder/items/item/comment(存在する場合)に直接アクセスし、そこで各セルが"electric"と一致しているかどうかをテストするほうが効率的です。

これは、XPathリライトの最初のステップです。ora:containsの最初の引数(text_input)が単一のリレーショナル列にマップされている場合、ora:containsはその列に対して実行されます。この結果、索引が含まれていない場合でも、問合せのパフォーマンスが大幅に向上します。

ora:containsからcontainsへの変換

「文書からノードへの変換」で説明したように、Oracle XML DBでは、XPath式全体をXML文書全体に適用するのではなく、基礎となる列にora:containsを適用することによって関数existsNodeに渡されたXPath式が解決されるように、問合せがリライトされる場合があります。この項では、その問合せで、基礎となる列のCONTEXT索引を利用する方法を示します。

CONTEXT索引が付いた列にマップされているテキスト・ノードまたは属性に対してora:containsを実行している場合、その索引を使用しない理由を考えてみます。1つの理由は、リライトされた問合せが元の問合せと同じ結果になる必要があることです。一貫した結果を保証するには、CONTEXT索引を使用する前に次の条件を満たす必要があります。

  • ora:containsのターゲット(input_text)は、親ノードが列にマップされている単一のテキスト・ノード、または列にマップされている属性の必要があります。列は(Ordered Collection Table内の列も含めて)、単一のリレーショナル列である必要があります。

  • 「ora:contains問合せのポリシー」で説明したように、索引付けに関する選択内容(contains用)およびポリシーの選択内容(ora:contains用)は問合せのセマンティクスに影響を与えます。単純な違いは、索引ベースのcontainsでは大/小文字が区別される検索であるのに対して、ora:containsでは大/小文字が区別されない検索が指定される点です。ora:containsおよびリライトされたcontainsのセマンティクスが同じになるように、ora:containsのポリシーがCONTEXT索引の索引に関する選択内容と正確に一致する必要があります。

ora:containsのポリシーとCONTEXTの索引の両方で、NULL_SECTION_GROUPセクション・グループ・タイプを使用する必要もあります。ora:containsポリシーのデフォルトのセクション・グループはctxsys.NULL_SECTION_GROUPです。

3番目に、CONTEXT索引は通常非同期です。ワード"dog"が含まれる新しい文書を追加した場合にCONTEXT索引を同期化しないと、"dog"のcontains問合せでその文書が戻されません。しかし、同じデータに対するora:contains問合せでは戻されます。ora:containsとリライトされたcontainsで常に同じ結果が戻されるようにするには、PARAMETERS文字列にTRANSACTIONALキーワードを指定してCONTEXT索引を作成する必要があります。


関連項目:

『Oracle Textリファレンス』

XPathリライトでのora:containsの使用の概要

XPathにora:containsが含まれているexistsNodeextractまたはextractValueを使用する問合せでは、次の場合にXPathリライトを考慮できます。

  • XMLがXML Schemaに基づいている場合。

  • ora:containsの最初の引数(text_input)が、親ノードが列にマップされている単一のテキスト・ノードであるか、または列にマップされている属性である場合。列は(Ordered Collection Table内の列も含めて)、単一のリレーショナル列である必要があります。

リライトされた問合せでは、次の場合にCONTEXT索引が使用されます。

  • text_inputの親ノード(または属性ノード)がマップされる列に、CONTEXT索引が設定されている場合。

  • ora:containsポリシーがCONTEXT索引の索引に関する選択内容と完全に一致する場合。

  • CONTEXT索引が、PARAMETERS文字列にTRANSACTIONALキーワードを指定して作成された場合。

XPathリライトは、最適なCONTEXT索引がある場合は特に、問合せを大幅に高速化できます。

Text Path BNFの仕様

HasPathArg           ::=    LocationPath
                         |  EqualityExpr
InPathArg            ::=    LocationPath
LocationPath         ::=    RelativeLocationPath
                         |  AbsoluteLocationPath
AbsoluteLocationPath ::=    ("/" RelativeLocationPath)
                         |  ("//" RelativeLocationPath)
RelativeLocationPath ::=    Step
                         |  (RelativeLocationPath "/" Step)
                         |  (RelativeLocationPath "//" Step)
Step                 ::=    ("@" NCName)
                         |  NCName
                         |  (NCName Predicate)
                         |  Dot
                         |  "*"
Predicate            ::=    ("[" OrExp "]")
                         |  ("[" Digit+ "]")
OrExpr               ::=    AndExpr
                         |  (OrExpr "or" AndExpr)
AndExpr              ::=    BooleanExpr
                         |  (AndExpr "and" BooleanExpr)
BooleanExpr          ::=    RelativeLocationPath
                         |  EqualityExpr
                         |  ("(" OrExpr ")")
                         |  ("not" "(" OrExpr ")")
EqualityExpr         ::=    (RelativeLocationPath "=" Literal)
                         |  (Literal "=" RelativeLocationPath)
                         |  (RelativeLocationPath "=" Literal)
                         |  (Literal "!=" RelativeLocationPath)
                         |  (RelativeLocationPath "=" Literal)
                         |  (Literal "!=" RelativeLocationPath)
Literal              ::=    (DoubleQuote [~"]* DoubleQuote)
                         |  (SingleQuote [~']* SingleQuote)
NCName               ::=    (Letter |  Underscore) NCNameChar*
NCNameChar           ::=    Letter
                         |  Digit
                         |  Dot
                         |  Dash
                         |  Underscore
Letter               ::=    ([a-z] | [A-Z])
Digit                ::=    [0-9]
Dot                  ::=    "."
Dash                 ::=    "-"
Underscore           ::=    "_"

全文XMLのサポートの例

この項の内容は次のとおりです。

発注書のXML文書、po001.xml

例11-55 発注書のXML文書、po001.xml

<?xml version="1.0" encoding="UTF-8"?>
<purchaseOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:noNamespaceSchemaLocation="xmlschema/po.xsd"
               orderDate="1999-10-20">
  <shipTo country="US">
    <name>Alice Smith</name>
    <street>123 Maple Street</street>
    <city>Mill Valley</city>
    <state>CA</state>
    <zip>90952</zip>
  </shipTo>
  <billTo country="US">
    <name>Robert Smith</name>
    <street>8 Oak Avenue</street>
    <city>Old Town</city>
    <state>PA</state>
    <zip>95819</zip>
  </billTo>
  <comment>Hurry, my lawn is going wild!</comment>
  <items>
    <item partNum="872-AA">
      <productName>Lawnmower</productName>
      <quantity>1</quantity>
      <USPrice>148.95</USPrice>
      <comment>Confirm this is electric</comment>
    </item>
    <item partNum="926-AA">
      <productName>Baby Monitor</productName>
      <quantity>1</quantity>
      <USPrice>39.98</USPrice>
      <shipDate>1999-05-21</shipDate>
    </item>
  </items>
</purchaseOrder>

CREATE TABLE文

例11-56 CREATE TABLE purchase_orders

CREATE TABLE purchase_orders (id   NUMBER,
                              doc  VARCHAR2(4000));
INSERT INTO purchase_orders (id, doc)
  VALUES (1,
          '<?xml version="1.0" encoding="UTF-8"?>
           <purchaseOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                          xsi:noNamespaceSchemaLocation="xmlschema/po.xsd"
                          orderDate="1999-10-20">
             <shipTo country="US">
               <name>Alice Smith</name>
               <street>123 Maple Street</street>
               <city>Mill Valley</city>
               <state>CA</state>
               <zip>90952</zip>
             </shipTo>
             <billTo country="US">
               <name>Robert Smith</name>
               <street>8 Oak Avenue</street>
               <city>Old Town</city>
               <state>PA</state>
               <zip>95819</zip>
             </billTo>
             <comment>Hurry, my lawn is going wild!</comment>
             <items>
               <item partNum="872-AA">
                 <productName>Lawnmower</productName>
                 <quantity>1</quantity>
                 <USPrice>148.95</USPrice>
                 <comment>Confirm this is electric</comment>
               </item>
               <item partNum="926-AA">
                 <productName>Baby Monitor</productName>
                 <quantity>1</quantity>
                 <USPrice>39.98</USPrice>
                 <shipDate>1999-05-21</shipDate>
               </item>
             </items>           </purchaseOrder>');COMMIT;

例11-57 CREATE TABLE purchase_orders_xmltype

CREATE TABLE purchase_orders_xmltype (id  NUMBER ,
                                      doc XMLType);
INSERT INTO purchase_orders_xmltype (id, doc)
  VALUES (1,
          XMLTYPE ('<?xml version="1.0" encoding="UTF-8"?>
                     <purchaseOrder
                       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                       xsi:noNamespaceSchemaLocation="po.xsd"
                       orderDate="1999-10-20">
                       <shipTo country="US">
                         <name>Alice Smith</name>
                         <street>123 Maple Street</street>
                         <city>Mill Valley</city>
                         <state>CA</state>
                         <zip>90952</zip>
                       </shipTo>
                       <billTo country="US">
                         <name>Robert Smith</name>
                         <street>8 Oak Avenue</street>
                         <city>Old Town</city>
                         <state>PA</state>
                         <zip>95819</zip>
                       </billTo>
                       <comment>Hurry, my lawn is going wild!</comment>
                       <items>
                         <item partNum="872-AA">
                           <productName>Lawnmower</productName>
                           <quantity>1</quantity>
                           <USPrice>148.95</USPrice>
                           <comment>Confirm this is electric</comment>
                         </item>
                         <item partNum="926-AA">
                           <productName>Baby Monitor</productName>
                           <quantity>1</quantity>
                           <USPrice>39.98</USPrice>
                           <shipDate>1999-05-21</shipDate>
                         </item>
                       </items>
                   </purchaseOrder>'));
COMMIT;

例11-58 CREATE TABLE purchase_orders_xmltype_table

CREATE TABLE purchase_orders_xmltype_table OF XMLType;

INSERT INTO purchase_orders_xmltype_table
  VALUES (
    XMLType ('<?xml version="1.0" encoding="UTF-8"?>              <purchaseOrder
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:noNamespaceSchemaLocation="xmlschema/po.xsd"
                orderDate="1999-10-20">
                <shipTo country="US">
                  <name>Alice Smith</name>
                  <street>123 Maple Street</street>
                  <city>Mill Valley</city>
                  <state>CA</state>
                  <zip>90952</zip>
                </shipTo>
                <billTo country="US">
                  <name>Robert Smith</name>
                  <street>8 Oak Avenue</street>
                  <city>Old Town</city>
                  <state>PA</state>
                  <zip>95819</zip>
                </billTo>
                <comment>Hurry, my lawn is going wild!</comment>
                <items>
                  <item partNum="872-AA">
                    <productName>Lawnmower</productName>
                    <quantity>1</quantity>
                    <USPrice>148.95</USPrice>
                    <comment>Confirm this is electric</comment>
                  </item>
                  <item partNum="926-AA">
                    <productName>Baby Monitor</productName>
                    <quantity>1</quantity>
                    <USPrice>39.98</USPrice>
                    <shipDate>1999-05-21</shipDate>
                  </item>
                </items>
              </purchaseOrder>'));
COMMIT;

全文検索する発注書XML Schemaの例

例11-59 全文検索する発注書XML Schemaの例

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:annotation>
    <xsd:documentation xml:lang="ja">
      Purchase order schema for Example.com.
      Copyright 2000 Example.com. All rights reserved.
    </xsd:documentation>
  </xsd:annotation>
  <xsd:element name="purchaseOrder" type="PurchaseOrderType"/>
  <xsd:element name="comment" type="xsd:string"/>
  <xsd:complexType name="PurchaseOrderType">
    <xsd:sequence>
      <xsd:element name="shipTo" type="USAddress"/>
      <xsd:element name="billTo" type="USAddress"/>
      <xsd:element ref="comment" minOccurs="0"/>
      <xsd:element name="items" type="Items"/>
    </xsd:sequence>
    <xsd:attribute name="orderDate" type="xsd:date"/>
  </xsd:complexType>
  <xsd:complexType name="USAddress">
    <xsd:sequence>
      <xsd:element name="name" type="xsd:string"/>
      <xsd:element name="street" type="xsd:string"/>
      <xsd:element name="city" type="xsd:string"/>
      <xsd:element name="state" type="xsd:string"/>
      <xsd:element name="zip" type="xsd:decimal"/>
    </xsd:sequence>
    <xsd:attribute name="country" type="xsd:NMTOKEN" fixed="US"/>
  </xsd:complexType>
  <xsd:complexType name="Items">
    <xsd:sequence>
      <xsd:element name="item" minOccurs="0" maxOccurs="unbounded">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="productName" type="xsd:string"/>
            <xsd:element name="quantity">
              <xsd:simpleType>
                <xsd:restriction base="xsd:positiveInteger">
                  <xsd:maxExclusive value="100"/>
                </xsd:restriction>
              </xsd:simpleType>
            </xsd:element>
            <xsd:element name="USPrice" type="xsd:decimal"/>
            <xsd:element ref="comment" minOccurs="0"/>
            <xsd:element name="shipDate" type="xsd:date" minOccurs="0"/>
          </xsd:sequence>
          <xsd:attribute name="partNum" type="SKU" use="required"/>
        </xsd:complexType>
      </xsd:element>
    </xsd:sequence>
  </xsd:complexType>
  <!-- Stock Keeping Unit, a code for identifying products -->
  <xsd:simpleType name="SKU">
    <xsd:restriction base="xsd:string">
      <xsd:pattern value="\d{3}-[A-Z]{2}"/>
    </xsd:restriction>
  </xsd:simpleType>
</xsd:schema>