XMLデータのOracle固有の全文検索について、Oracle SQL関数containsおよびOracle XPath関数ora:containsの使用方法などを説明します。
このようなOracle固有の関数を使用すれば、XMLデータの全文検索を実行できますが、XMLTypeデータがバイナリXMLとして格納されている場合は、かわりにXQueryの全文検索機能を使用されることをお薦めします。XQuery and XPath Full Textの標準は、Oracle Database 12cリリース1 (12.1.0.1)からOracle XML DBでサポートされるようになりました。
関連項目:
Oracle Textの詳細は、『Oracle Textリファレンス』および『Oracle Textアプリケーション開発者ガイド』を参照してください。
XMLドキュメントの構造を使用して全文検索を限定できます。たとえば、コメント内にワード"electric"が含まれるすべてのXML発注書を検索するか、または明細項目の下にあるコメント内にワード"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構造を含む検索を実行する方法には、構造を全文述語に含めるか、全文述語を構造に含めるかの2つがあります。
Oracle 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]'
XPath関数ora:containsはXPathの拡張機能であり、SQL/XML関数XMLQuery、XMLTableまたはXMLExistsのコールで使用できます。
全文検索の例について詳しく説明します。
全文検索の例を実行するには、データベース・ロールCTXAPP、CONNECT、RESOURCEが必要です。また、CTXSYSパッケージCTX_DDLに対するEXECUTE権限も必要です。
全文検索の例は、『W3C XML Schema Part 0: Primer』の「The Purchase Order Schema」に基づいています。
例で使用しているデータは、「発注書のXML文書、po001.xml」の文書からのものです。
この章の例で使用している表は、「CREATE TABLE文」「CREATE TABLE文」で定義されています。ただし、パフォーマンスの例の一部は、より大きい表(purchase_orders_xmltype_big)に基づいており、この表はダウンロード可能なバージョンにのみ含まれています。http://www.w3.org/TR/xmlschema-0/#po.xmlを参照してください。
一部の例は、データ型VARCHAR2を使用しています。XMLType型を使用するものもあります。VARCHAR2を使用している例はすべて、XMLTypeを使用することもできます。
SQL関数CONTAINSとXPath関数ora:containsは、どちらも全文検索に使用できます。
Oracle SQL関数containsは、[schema.]columnがtext_queryと一致する行の正数を戻し、一致しない場合は0(ゼロ)を戻します。それ以外の場合は、0(ゼロ)を戻します。型CONTEXTの索引が必要です。検索対象の列にCONTEXT索引がない場合、containsではエラーが発生します。
CONTAINS構文
contains([schema.]column, text_query VARCHAR2 [,label NUMBER]) RETURN NUMBER
例E-1に、Oracle SQL関数containsを使用した一般的な問合せを示します。表purchase_ordersで、doc列に単語"lawn"が含まれ、idが25よりも小さい値の各行のidが戻されます。
docは、一連のXML文書が含まれる列であるとします。この場合、docに対して、そのXML構造を使用して問合せを限定する全文検索を実行できます。例E-2の問合せでは、表purchaseordersで、XML要素commentのtext()ノードにワード"lawn"が含まれるdoc列のid値が戻されます。
INPATH演算子およびXPath式を使用すると、XML構造によるさらに複雑な限定を適用できます。例E-3の問合せでは、XPath式/purchaseOrder/items/item/commentのターゲットとなるcomment要素のtext()ノードに、ワード"electric"が含まれる発注書が検索されます。
例E-1 Oracle SQL関数CONTAINSを使用した単純な問合せ
SELECT id FROM purchase_orders WHERE contains(doc, 'lawn') > 0 AND id < 25;
例E-2 CONTAINSおよびWITHINを使用した問合せの制限
SELECT id FROM purchase_orders WHERE contains(doc, 'lawn WITHIN comment') > 0;
例E-3 CONTAINSおよびINPATHを使用した問合せの制限
SELECT id FROM purchase_orders
WHERE contains(doc, 'electric INPATH (/purchaseOrder/items/item/comment)') > 0;
XPath関数ora:containsは、XQuery式内のXPath式や、SQL/XML関数XMLQuery、XMLTable、XMLExistsのコールで使用できます。これは、全文述語を伴う構成検索を限定します。
標準のメカニズムを使用してXPathを拡張する、Oracle XML DB名前空間ora内のユーザー定義関数です。索引は不要ですが、索引を使用することでパフォーマンスを向上できます。
ora:contains構文
ora:contains(input_text NODE*, text_query STRING [,policy_name STRING] [,policy_owner STRING])
関数ora:containsはinput_textがtext_queryと一致した場合は正の整数を戻し(数字が大きいほど、一致の関連性は高くなります)、一致しない場合はゼロを戻します。XQuery式で使用される場合、XQueryの戻り型はxs:integer()です。XQuery式の外部でXPath式で使用される場合、XPathの戻り型はnumberです。
引数input_textは単一のテキスト・ノードまたは属性に対して評価される必要があります。ora:containsのtext_queryの構文およびセマンティクスはcontainsのtext_queryと同じですが、次の制限事項があります。
引数text_queryに構造演算子(WITHIN、INPATHまたはHASPATH)を含めることはできません。
スコア重み付け演算子weightを使用した場合、重みは無視されます。
例E-4は、XMLExistsのXPathパラメータにおけるora:containsのコールを示しています。Oracle XML DBネームスペースを表すものとして、接頭辞oraを宣言するネームスペース宣言に注意してください。
関連項目:
「ora:contains XPath関数」の詳細は、「ora:contains XQuery関数」を参照してください。
例E-4 複雑な任意のテキスト問合せを使用したora:contains
SELECT id
FROM purchase_orders_xmltype
WHERE
XMLExists(
'declare namespace ora = "http://xmlns.oracle.com/xdb"; (: :)
$d/purchaseOrder/comment
[ora:contains(text(), "($lawns AND wild) OR flamingo") > 0]'
PASSING doc AS "d");
Oracle SQL関数containsおよびOracle XPath関数ora:containsでは、いずれもXML構造の検索と全文検索を組み合せることができます。2つの手法が比較されます。
Oracle SQL関数containsの特性は、次のとおりです。
実行するにはCONTEXT索引が必要です。索引がない場合はエラーが発生します。
索引検索を実行し、通常非常に高速です。
(Oracle SQL関数scoreを使用して)スコアを戻します。
ノードではなく文書(表の行)に基づいて検索を限定します。
XML構造ベースの投影(XML文書の一部を抽出)には使用できません。
Oracle XPath関数ora:containsの特性は、次のとおりです。
索引は不要ですが、索引を使用することでパフォーマンスを向上できます。
非索引検索であるため、大量のリソースを消費する場合があります。
格納方法および索引付け方法に関する考慮事項からアプリケーション・ロジックを分離しています。
スコアを戻しません。
XML構造ベースの投影(XML文書の一部を抽出)に使用できます。
XML文書で、単純なXML構造の制約を指定している場合など、高速な索引ベースの全文検索を実行する場合は、Oracle SQL関数containsを使用します。XPathナビゲーションと組み合せた全文検索の柔軟性が必要な場合(索引がない場合も含めて)、または投影は必要でスコアは不要な場合は、Oracle XPath関数ora:containsを使用します。
Oracle SQL関数containsを使用した全文検索について説明します。
Oracle 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リファレンス』を参照してください。
この項の後半の例では、全文検索の優れた機能をいくつか示します。使用可能な2、3の演算子を使用します。例の問合せでは、テキスト索引(索引タイプCTXSYS.CONTEXT)を使用してVARCHAR2列(PURCHASE_ORDERS.doc)が検索されます。
text_query言語では、AND、ORおよびNOTの任意の組合せがサポートされています。優先順位はカッコを使用して制御できます。ブール演算子は次のいずれの方法でも記述できます。
AND、OR、NOT
and、or、not
&、|、~
NOTは単項演算子ではなくバイナリであることに注意してください。式alpha NOT(beta)は alpha AND unary-not(beta)と同等で、unary-notは単項否定を表します。
関連項目:
containsおよびora:containsで使用できる演算子の詳細は、『Oracle Textリファレンス』を参照してください。
例E-5 単純なブール演算子を使用したCONTAINS問合せ
SELECT id FROM purchase_orders WHERE contains(doc, 'lawn AND wild') > 0;
例E-6 複雑なブールを使用したCONTAINS問合せ
SELECT id FROM purchase_orders
WHERE contains(doc, '((lawn OR garden) AND (wild OR flooded)) NOT(flamingo)')
> 0;
ステミングはtext_query言語とともに使用できます。
例E-7では、"lawns"と同じ言語語幹のワードが含まれるすべての文書が戻されるため、"lawn"または"lawns"が検索されます。ステミング演算子は、ドル記号($)で記述されます。
例E-7 ステミングを使用したCONTAINS問合せ
SELECT id FROM purchase_orders WHERE contains(doc, '$(lawns)') > 0;
text_query言語では演算子を組み合わせることができます。
例E-8に、これを示します。
関連項目:
text_query演算子の完全なリストは、『Oracle Textリファレンス』を参照してください。
例E-8 複雑な問合せ式を使用したCONTAINS問合せ
SELECT id FROM purchase_orders WHERE contains(doc, '($lawns AND wild) OR flamingo') > 0;
Oracle SQL関数scoreはOracle SQL関数containsに関連します。関数scoreは問合せ内のどの場所でも使用できます。これは関連性を測定するもので、大規模なドキュメント・セット全体を全文検索するときに特に有効です。
関数scoreは通常、問合せ結果の一部として戻されるか、ORDER BY句で使用されるか、あるいはその両方です。
SCORE構文
score(label NUMBER) RETURN NUMBER
例E-9のscore(10)では、結果セット内の各行に対するスコアが戻されます。Oracle SQL関数scoreは、関数containsの特定のコールに関する結果セット内の行の関連性を戻します。scoreのコールは、LABEL(この場合は番号10)によってcontainsのコールにリンクされます。
関数scoreは、対応するcontainsで、テキスト索引で規定された一致規則に従ってtext_query引数がinput_textと一致しない場合は、常に0を戻します。containsのtext_queryがinput_textと一致した場合、scoreは、0より大きく100以下の数値を戻します。この数値は、input_textに対するtext_queryの関連性を示します。数値が大きいほど、一致精度が高いことを意味します。
containsのtext_queryがHASPATH演算子およびText Pathのみで構成されている場合、HASPATHは完全一致をテストするため、スコアは0または100になります。
関連項目:
スコアの計算方法の詳細は、『Oracle Textリファレンス』を参照してください。
例E-9 SCOREを使用した単純なCONTAINS問合せ
SELECT score(10), id FROM purchase_orders WHERE contains(doc, 'lawn', 10) > 0 AND score(10) > 2 ORDER BY score(10) DESC;
デフォルトでは、Oracle SQL関数containsでは、文書全体が全文検索されます。XML構造を使用してcontains問合せを限定するためには、WITHIN、INPATHおよびHASPATHの3つの演算子が使用できます。
前述の例で、構造による限定のない"lawn"の検索では、発注書内のどこかにワード"lawn"があるすべての発注書が検索されます。
注意:
この説明では、セクションはXMLノードと同じであると考えてください。
WITHIN演算子は、問合せをXML文書内のあるセクションに限定します。コメント・セクションのどこかにワード"lawn"が含まれている発注書を検索するには、WITHINを使用します。セクション名の大/小文字は区別されます。
例E-10 WITHIN
SELECT id FROM purchase_orders WHERE contains(DOC, 'lawn WITHIN comment') > 0;
演算子WITHINをネストすることで問合せを限定できます。
例E-11では、セクション"comment"内にワード"lawn"が含まれ、"lawn"の出現箇所がセクション"item"内にもあるすべての文書が検索されます。
例E-11では行が戻されません。使用する発注書サンプルには、コメント内にワード"lawn"が含まれています。しかし、項目内の唯一のコメントは"Confirm this is electric"です。そのため、ネストしたWITHIN問合せでは行が戻されません。
例E-11 ネストしたWITHIN
SELECT id FROM purchase_orders WHERE contains(doc, '(lawn WITHIN comment) WITHIN item') > 0;
演算子WITHINを使用すると、属性の範囲内で検索できます。ですが、属性は、ネストしたWITHINでは検索できません。
例E-12では、purchaseOrder要素のorderDate属性にワード"10"が含まれているすべての発注書が検索されます。
デフォルトでは、マイナス記号(-)は単語セパレータとして処理されます。つまり、"1999-10-20"は3つの単語、"1999"、"10"および"20"として処理されます。したがって、この問合せでは1行戻されます。
属性内のテキストは、主検索可能文書の一部ではありません。text_queryをWITHIN purchaseOrder@orderDateで修飾せずに10を検索すると、行は戻されません。
例E-12 WITHIN (属性の場合)
SELECT id FROM purchase_orders WHERE contains(doc, '10 WITHIN purchaseOrder@orderDate') > 0;
演算子WITHINおよびANDを一緒に使用して、同じセクションに出現する一群の語や、あるセクションに個別に出現する一群の語を検索できます。
コメント・セクション内にlawnとelectricの2つのワードが含まれる発注書を検索するとします。purchaseOrderにはコメント・セクションが複数ある場合があります。このため、この問合せの作成方法は2通りあり、異なる結果となります。
両方のワードが含まれ、各ワードがあるコメント・セクション内に出現する発注書を検索する場合は、例E-13のような問合せを作成します。
purchaseOrderデータに対してこの問合せを実行すると、1行戻されます。この例ではカッコは必要ありませんが、使用すると問合せがわかりやすくなります。
両方のワードが含まれ、両方のワードが同じコメント内に出現する発注書を検索する場合は、例E-14のような問合せを作成します。
例E-14の問合せでは、行が戻されません。例E-15の問合せのように、lawn AND electricを囲むカッコを外すと、1行戻されます。
例E-13 WITHINおよびAND: あるコメント・セクション内の2つのワード
SELECT id FROM purchase_orders WHERE contains(doc, '(lawn WITHIN comment) AND (electric WITHIN comment)') > 0;
例E-14 WITHINおよびAND: 同じコメント内の2つのワード
SELECT id FROM purchase_orders WHERE contains(doc, '(lawn AND electric) WITHIN comment') > 0;
例E-15 WITHINおよびAND: カッコなし
SELECT id FROM purchase_orders WHERE contains(doc, 'lawn AND electric WITHIN comment') > 0;
例E-16 WITHINおよびAND: 演算子優先順位を示すカッコ
SELECT id FROM purchase_orders WHERE contains(doc, 'lawn AND (electric WITHIN comment)') > 0;
様々なセクションについて説明しています。
セクションは次のいずれかです。
パス・セクションまたはゾーン・セクション
これは、ノードの子孫であるテキスト・ノードのすべてを、間を空白で区切って文書順に連結したものです。ノードからゾーン・セクションに変換するには、ノードをシリアライズしてすべてのタグを空白で置換する必要があります。パス・セクションの有効範囲と動作はゾーン・セクションと同じですが、パス・セクションでは INPATHおよびHASPATH構造演算子を使用した問合せがサポートされます。
フィールド・セクション
ゾーン・セクションと同じですが、文書内の繰返しノードが空白で区切られて単一のセクションに連結されます。
属性セクション
特殊セクション(文または段落)
関連項目:
特殊セクションの詳細は、『Oracle Textリファレンス』を参照してください。
演算子WITHINを使用すると、text_queryで、単純な構造による限定を表現できます。大量のXML構造を使用する問合せでは、ネストしたWITHIN演算子のかわりに、演算子INPATHとText Pathを使用できます。
演算子INPATHでは、左側にtext_queryを記述し、右側にカッコで囲んだText Pathを記述します。例E-17では、パス/purchaseOrder/items/item/comment内でワード"electric"が含まれるpurchaseOrdersが検索されます。
例E-17の検索範囲は、Text Pathで示されたセクションです。例E-18の問合せでは例E-17の問合せよりも範囲の広いパスを使用しますが、同じように1行しか戻されません。
例E-17 全文述語内の構造: INPATH
SELECT id FROM purchase_orders WHERE contains(doc, 'electric INPATH (/purchaseOrder/items/item/comment)') > 0;
例E-18 全文述語内の構造: INPATH
SELECT id FROM purchase_orders WHERE contains(doc, 'electric INPATH (/purchaseOrder/items)') > 0;
Text Pathの構文とセマンティクスは、W3CのXPath 1.0勧告に基づいています。単純なパス式はサポートされますが(省略構文のみ)、関数はサポートされません。
関連項目:
W3CのXPath 1.0勧告の詳細は、http://www.w3.org/TR/xpathを参照してください。
Text Pathの文法については、「Text Path BNFの仕様」を参照してください。
例E-19では、属性partNumが"872-AA"と等しいitem要素の子であるcomment要素内にワード"electric"が含まれるすべての発注書が検索されます(つまり、ルート・ノードからいくつか下のレベルのitems要素の子です)。
例E-20では、3番目のレベルであるitem要素(またはその子孫)内にワード"lawnmower"が含まれ、すべてのレベルにcomment要素があるすべての発注書が検索されます。この問合せでは1行戻されます。問合せの有効範囲はcomment要素ではなく、子孫としてcomment要素を持つ一連のitems要素であることに注意してください。
例E-19 複雑なパス式を使用したINPATH (1)
SELECT id FROM purchase_orders
WHERE contains(doc, 'electric INPATH (//items/item[@partNum="872-AA"]/comment)')
> 0;
例E-20 複雑なパス式を使用したINPATH (2)
SELECT id FROM purchase_orders WHERE contains(doc, 'lawnmower INPATH (/*/*/item[.//comment])') > 0;
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式はネストできます。Text Pathのコンテキストは常にルート・ノードです。ネストしたINPATHの場合も変わりません。
例E-21では、任意のレベルのcomment要素にワード"electric"が含まれる発注書が検索されます(このワードの出現箇所は、最上位レベルpurchaseOrder要素の子であるitem要素内でもあります)。
このネストしたINPATH問合せは、例E-22に示すように、簡潔に記述できます。
例E-21 ネストしたINPATH
SELECT id FROM purchase_orders
WHERE contains(doc,
'(electric INPATH (//comment)) INPATH (/purchaseOrder/items)')
> 0;
例E-22 リライト済のネストしたINPATH
SELECT id FROM purchase_orders WHERE contains(doc, 'electric INPATH (/purchaseOrder/items//comment)') > 0;
演算子HASPATHを使用すると、=述語などを使用して、特定のパス内に特定のセクションが含まれる文書を検索できます。これは全文検索ではなく、パス検索の実行です。セクションが存在するかどうかの確認、またはセクションの内容の照合はできますが、ワード検索はできません。
データ型がXMLTypeの場合は、構造演算子HASPATHではなくSQL/XML関数XMLExistsの使用を考慮してください。
演算子HASPATHで使用するオペランドはText Pathのみで、カッコで囲み、右側に記述します。=述語などを使用して、特定のパス内に特定のセクションが含まれる文書を検索するときは、HASPATHを使用します。これは全文検索ではなく、パス検索です。セクションが存在するかどうかの確認、またはセクションの内容の照合はできますが、ワード検索はできません。データ型がXMLTypeの場合は、構造演算子HASPATHではなくSQL/XML関数XMLExistsの使用を考慮してください。
例E-23では、USPriceを持つ項目があるpurchaseOrdersが検索されます。
例E-24では、"148.95"とテキスト等値であるUSPriceを持つ項目があるpurchaseOrdersが検索されます。
関連項目:
テキスト等値の説明は、「Text PathとXPathの比較」を参照してください。
HASPATHは、INPATHなど他のcontains演算子と組み合せることができます。例E-25では、文書の任意の場所にワードelectricを含み、148.95とテキスト等値であるUSPriceを持つitemがあり、かつpurchaseOrder属性orderDate内に10が含まれるpurchaseOrdersが検索されます。
例E-23 単純なHASPATH
SELECT id FROM purchase_orders WHERE contains(DOC, 'HASPATH (/purchaseOrder//item/USPrice)') > 0;
例E-24 HASPATH (等価性)
SELECT id FROM purchase_orders WHERE contains(doc, 'HASPATH (/purchaseOrder//item/USPrice="148.95")') > 0;
例E-25 HASPATHと他の演算子の組合せ
SELECT id FROM purchase_orders
WHERE contains(doc,
'electric
AND HASPATH (/purchaseOrder//item/USPrice="148.95")
AND 10 INPATH (/purchaseOrder/@orderDate)')
> 0;
WHERE句内にcontainsを使用したSQL問合せの結果は常に、行のセット(および多くの場合score情報)、または一致する行全体の投影です。contains式を満たす各XML文書の一部のみを戻すには、SQL/XML関数XMLQueryを使用します。
この例では、XMLType表purchase_orders_xmltypeが使用されます。
例E-26では、最上位レベルのpurchaseOrder要素の子孫であるcomment要素内にワード"electric"が含まれるpurchaseOrderが検索されます。各結果の行IDを戻すかわりに、XMLQueryを使用してcomment要素のみを戻します。
例E-26の結果は、要素commentの2つのインスタンスです。関数containsは、comment要素内に単語"electric"が含まれている行(ID = 1の行)を示します。関数XMLQueryは文書内のその行にある要素commentのインスタンスをすべて抽出します。purchaseOrder要素には要素 commentのインスタンスが2つあり、問合せではその両方が戻されます。
これは希望の結果と異なる場合があります。contains式を満たすcomment要素の実例のみを問合せで戻す場合は、XMLQueryに渡されるXQuery式でその述語を繰り返す必要があります。これには、XPath関数ora:containsを使用します。例E-27に、これを示します。
例E-26 CONTAINS問合せの結果の範囲指定
SELECT XMLQuery('declare namespace ora = "http://xmlns.oracle.com/xdb"; (: :)
$d/purchaseOrder//comment'
PASSING doc AS "d" RETURNING CONTENT) "Item Comment"
FROM purchase_orders_xmltype
WHERE CONTAINS(doc, 'electric INPATH (/purchaseOrder//comment)') > 0;
例E-27 ora:containsを使用したCONTAINS問合せ結果の投影
SELECT XMLQuery('declare namespace ora = "http://xmlns.oracle.com/xdb"; (: :)
$d/purchaseOrder/items/item/comment
[ora:contains(text(), "electric") > 0]'
PASSING doc AS "d" RETURNING CONTENT) "Item Comment"
FROM purchase_orders_xmltype
WHERE CONTAINS(doc, 'electric INPATH (/purchaseOrder/items/item/comment)') > 0;
CONTEXT索引を使用して全文検索を有効化できます。
汎用の全文索引タイプは、データベース・ユーザーCTXSYSが所有するCONTEXT索引タイプです。デフォルトの全文索引を作成するには、CREATE INDEXを実行し、INDEXTYPE IS CTXSYS.CONTEXT句を追加します。PARAMETERS句を使用して索引付け設定を選択できます。
例E-28は、CONTEXT索引を作成します。
全文索引を作成するときには、多数の選択肢があります。これらの選択肢は、索引付けプリファレンスとして表されます。索引付けプリファレンスを使用するには、例E-29に示すように、CREATE INDEXにPARAMETERS句を追加します。
関連項目:
Oracle Textには、CTXCATやCTXRULEなどの他の索引タイプが用意されていますが、この章では説明しません。
関連項目:
CONTEXT索引の詳細は、『Oracle Textリファレンス』を参照してください。
例E-28 表PURCHASE_ORDERSの単純なCONTEXT索引
CREATE INDEX po_index ON purchase_orders(doc) INDEXTYPE IS CTXSYS.CONTEXT;
例E-29 パス・セクション・グループを使用したXMLType表の単純なCONTEXT索引
CREATE INDEX po_index ON purchase_orders(doc)
INDEXTYPE IS CTXSYS.CONTEXT
PARAMETERS ('section group CTXSYS.PATH_SECTION_GROUP');
CONTEXT索引は、テキストが含まれた任意のデータに対して作成できます。型がCHAR、VARCHAR、VARCHAR2、BLOB、CLOB、BFILE、XMLTypeまたはURITypeの列にCONTEXT索引を作成する構文は同じです。
例E-28では、VARCHAR2列に対するCONTEXT索引が作成されます。例E-30では、XMLType型の列に対するCONTEXT索引が作成されます。セクション・グループはデフォルトでPATH_SECTION_GROUPに設定されます。
XMLType表がある場合は、例E-31に示すように、オブジェクト構文を使用してCONTEXT索引を作成する必要があります。
例E-32に示すように、表を問合せできます。
例E-30 XMLType列の単純なCONTEXT索引
CREATE INDEX po_index_xmltype ON purchase_orders_xmltype(doc) INDEXTYPE IS CTXSYS.CONTEXT;
例E-31 XMLType表の単純なCONTEXT索引
CREATE INDEX po_index_xmltype_table ON purchase_orders_xmltype_table (OBJECT_VALUE) INDEXTYPE IS CTXSYS.CONTEXT;
例E-32 XMLType表のCONTAINS問合せ
SELECT XMLCast(XMLQuery(
'declare namespace ora = "http://xmlns.oracle.com/xdb"; (: :)
$p/purchaseOrder/@orderDate'
PASSING po.OBJECT_VALUE AS "p" RETURNING CONTENT)
AS DATE) "Order Date"
FROM purchase_orders_xmltype_table po
WHERE contains(po.OBJECT_VALUE, 'electric INPATH (/purchaseOrder//comment)')
> 0;
CONTEXT索引は非同期です。索引付けられたデータが変更されても、同期させるまで索引が変更されないことがあります。CONTEXT索引は、時間経過とともに断片化する可能性があります。断片化した索引では通常より多くの領域が使用されるため、問合せが遅くなります。CONTEXT索引を最適化(断片化解消)する方法はたくさんあります。
関連項目:
CONTEXT索引のメンテナンスの詳細は、『Oracle Textリファレンス』を参照してください。
Oracle SQL関数containsを使用するには、CONTEXT型の索引を作成する必要があります。containsをコールしたとき、最初の引数で指定された列にCONTEXT型の索引がない場合は、エラーが発生します。
text_queryの構文およびセマンティクスは、CONTEXT索引の作成時に選択した内容によって異なります。次に例を示します。
ワードとしてカウントする対象
最も一般的なワードを処理対象とするかどうか
最も一般的なワード
テキスト検索で大/小文字を区別するかどうか
テキスト検索にキーワードの他にテーマ(概念)を含めることができるかどうか
プリファレンスは、索引付けに関する選択肢の集合と考えることができます。プリファレンスには、セクション・グループ、データストア、フィルタ、ワードリスト、ストップリストおよび記憶域が含まれます。検索で大/小文字を区別するためのレクサー・プリファレンスを設定できます。
プリファレンスを作成するには、プロシージャCTX_DDL.create_preference(またはCTX_DDL.create_stoplist)を使用します。プロシージャCTX_DDL.set_attributeを使用して新規プリファレンスの属性を設定することによって、そのプリファレンス・グループのデフォルトの選択肢をオーバーライドします。その後、CREATE INDEXのPARAMETERS文字列内にpreference type preference_nameを含めることによって、CONTEXT索引でプリファレンスを使用します。
プリファレンスを作成すると、それを使用して索引をいくつでも作成できます。
containsを使用した全文検索では、デフォルトで大/小文字が区別されません,。文書内のワードに対してtext_query内のワードを照合する際に、大/小文字は考慮されません。ただし、セクション名および属性名は常に、大/小文字が区別されます。CONTEXT索引を作成する場合、全文検索で大文字と小文字を区別するように選択できます。
例E-33では、text_query内の"HURRY"が、デフォルトの大/小文字が区別されない索引が設定されたpurchaseOrder内の"Hurry"と一致するため、1行戻されます。
例E-34では、属性mixed_caseがTRUEに設定された新しいレクサー・プリファレンスmy_lexerが作成されます。この例では、printjoin文字も"-"、"!"、","に設定されます。CONTEXT索引の作成およびポリシーの作成に同じプリファレンスを使用できます。
関連項目:
レクサー属性の完全なリストは、『Oracle Textリファレンス』を参照してください。
例E-35では、新しいmy_lexerレクサー・プレファレンスを使用してCONTEXT索引が作成されます。ここではプレファレンスpreference-case-mixedが使用されます。
例E-33では、text_query内の"HURRY"がpurchaseOrder内の"Hurry"と一致しないため、行は戻されません。例E-36では、text_queryの"Hurry"がpurchaseOrder内のワード"Hurry"と正確に一致するため、1行戻されます。
例E-33 CONTAINS: デフォルトの大/小文字を区別しない一致
SELECT id FROM purchase_orders WHERE contains(doc, 'HURRY INPATH (/purchaseOrder/comment)') > 0;
例E-34 大/小文字混合のプリファレンスの作成
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;
/
例E-35 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');
例E-36 CONTAINS: 大/小文字混合の(正確な)一致
SELECT id FROM purchase_orders WHERE contains(doc, 'Hurry INPATH (/purchaseOrder/comment)') > 0;
セクション・グループ・インスタンスは、文書の構造の種類、およびその構造の索引付け方法(したがって検索方法)を指定するセクション・グループ・タイプに基づいています。セクション・グループ・インスタンスによって、索引付けされる要素が指定される場合もあります。ほとんどのユーザーは、デフォルトのセクション・グループまたは事前定義のセクション・グループのいずれかを使用します。
CONTEXT索引の作成時に行う選択の1つにセクション・グループがあります。セクション・グループ・インスタンスは、セクション・グループ・タイプに基づいています。セクション・グループ・タイプでは、文書の構造の種類、およびその構造の索引付け方法(したがって検索方法)が指定されます。セクション・グループ・インスタンスによって、索引付けされる構造要素が指定される場合もあります。ほとんどのユーザーは、デフォルトのセクション・グループまたは事前定義のセクション・グループのいずれかを使用します。
XQuery Full Textを使用しないXML検索で役立つセクション・グループ・タイプについて説明します。
XMLの全文検索要件がある大部分のユーザーは、PATH_SECTION_GROUPを使用することをお薦めします。一部のユーザーには、FIELDセクションを使用するXML_SECTION_GROUPの使用が適している場合もあります。この選択によって、通常、問合せパフォーマンスが向上し、索引が小さくなりますが、フィールド化構造の文書に限定されます(検索可能なノードは、繰返しのないすべてのリーフ・ノードです)。
XMLでの使用に役に立つセクション・グループ・タイプには、次のものがあります。
PATH_SECTION_GROUP
問合せでWITHIN、INPATHおよび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_SECTION_GROUPセクション・グループ・タイプの詳細は、『Oracle Textリファレンス』を参照してください。
索引で使用するセクション・グループを選択するときは、提供されているセクション・グループを選択するか、デフォルトを使用するか、または選択したセクション・グループ・タイプに基づく新しいセクション・グループを作成するかを選択できます。
セクション・グループ・タイプPATH_SECTION_GROUP、AUTO_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リファレンス』を参照してください。
セクション・グループを索引と関連付けるには、例E-37のように、PARAMETERS文字列にsection group <section group name>を追加します。
例E-37 パス・セクション・グループを使用したpurchase_orders表の単純なCONTEXT索引
CREATE INDEX po_index ON purchase_orders(doc)
INDEXTYPE IS CTXSYS.CONTEXT
PARAMETERS ('section group CTXSYS.PATH_SECTION_GROUP');
関数ora:containsは、SQL/XML関数XMLQuery、XMLTableおよびXMLExistsのXQuery式の引数で使用するために、Oracleによって定義されたXQuery(XPath)関数です。関数ora:containsは常に数値を戻します。スコアは戻しません。text_queryがinput_textと一致した場合、正数を戻します。そうでない場合は0(ゼロ)を戻します。
ora:containsを使用する場合は、Oracle XML DB名前空間xmlns:ora="http://xmlns.oracle.com/xdb"に接頭辞oraをマップする名前空間宣言も指定する必要があります。
ora:containsの引数text_queryは、全文検索を指定する文字列です。それはSQL関数contains text_queryのtext_query引数と同じですが、いくつかの制限事項があります。
ora:containsのtext_queryには、構造演算子WITHIN、INPATHまたはHASPATHを含めることができません。
ora:containsのtext_queryには、スコア重み付け演算子weight(*)を含めることができますが、重みは無視されます。
ora:containsのtext_queryに次のいずれかを含めた場合は、その問合せでCONTEXT索引を使用できません。
スコアベースの演算子MINUS(-)またはthreshold(>)
選択的なコーパスベースの拡張演算子FUZZY(?)またはsoundex(!)
例E-4に、ブール演算子と$(ステミング)を任意に組み合せた全文検索を示します。
関連項目:
全文演算子の詳細は、「SQL関数CONTAINSを使用した全文検索」を参照してください。
containsおよびora:containsで使用できる演算子の完全なリストは、『Oracle Textリファレンス』を参照してください。
一致規則は、ポリシーpolicy_owner.policy_nameで定義されます。policy_ownerの指定がない場合、ポリシー所有者はデフォルトで現行ユーザーに設定されます。policy_nameとpolicy_ownerの両方が指定されない場合、ポリシーはデフォルトでCTXSYS.DEFAULT_POLICY_ORACONTAINSに設定されます。
ora:containsのスコープは引数input_textによって定義され、それは現在のXPathコンテキストで評価されます。結果が単一のテキスト・ノードまたは属性である場合、それは検索ターゲットです。input_textが単一のテキスト・ノードまたは属性に対して評価されない場合は、エラーが発生します。
ポリシーによって、ora:containsの一致規則が決定されます。ora:containsのデフォルト・ポリシーに関連付けられたセクション・グループの型はNULL_SECTION_GROUPです。
ora:containsはXPath式のどこでも使用でき、そのinput_text引数は単一のテキスト・ノードまたは属性に対して評価されるXPath式です。
各XML文書の一部のみを戻す場合は、関数XMLQueryを使用してノード順序を投影し、その結果にXMLCastを適用してノードのスカラー値を投影します。
例E-38では、ワード"lawn"を含むcommentがある各発注書のorderDateが戻されます。
関数XMLExistsは、ワード"lawn"の入ったcommentがpurchaseOrder要素に含まれる行(文書)に結果を限定します。その後、関数XMLQueryが、それらのpurchaseOrder要素から属性orderDateの値を戻します。関数XMLCastは、この結果をSQL DATE値としてキャストします。
//commentが抽出されていれば、WHERE句と一致したコメントのみではなく、両方のコメントがサンプル・ドキュメントから戻されます。
関連項目:
例E-38 XMLQueryおよびXMLExistsでのora:containsの使用
SELECT XMLCast(XMLQuery(
'declare namespace ora = "http://xmlns.oracle.com/xdb"; (: :)
$d/purchaseOrder/@orderDate'
PASSING doc AS "d" RETURNING CONTENT)
AS DATE) "Order date"
FROM purchase_orders_xmltype
WHERE XMLExists(
'declare namespace ora = "http://xmlns.oracle.com/xdb"; (: :)
$d/purchaseOrder/comment
[ora:contains(text(), "($lawns AND wild) OR flamingo") > 0]'
PASSING doc AS "d");
ポリシーは、ora:contains問合せに関連付けることができるプリファレンスの集合であり、索引付けに関する選択で、SQL containsの索引付け選択と同じようなセマンティクス制御を提供します。
列のCONTEXT索引によって、その列に対するSQL contains問合せのセマンティクスが決まります。ポリシーはora:containsに対して用意されています。サポートしている索引に依存しないためです。
ストップワード・リストが空のポリシーと、続いてポリシーを伴う、あるいは伴わずにora:containsを使用して問合せを作成する例を示し、相違点を説明します。
例E-39では、空のストップワード・リストを持つポリシーが作成されます。
わかりやすいように、このポリシーは空のストップリストで構成されており、所有者はユーザーCTXSYSです。このポリシーに組み込む新しいストップリストを作成するか、またはCONTEXT索引用に作成したストップリスト(またはレクサー)定義を再利用できます。
最も一般的なワード(ストップワード)も含めてすべてのワードを検索するには、ora:contains式でこのポリシーを参照してください。例E-40では、"is"はデフォルトでストップワードであり問合せできないため、コメントは戻されません。
例E-41では、空のストップワード・リストを指定するために、例E-39で作成されたポリシーが使用されます。この問合せでは"is"が検索され、コメントが1つ戻されます。
例E-41では、ポリシーmy_nostopwords_policyを使用します。例E-39では、このポリシーの名前は暗黙的にすべて大文字になります。XPathでは大/小文字が区別されるため、XPath述語内でこのポリシーは、my_nostopwords_policyではなくMY_NOSTOPWORDS_POLICYのように、すべて大文字を使用して記述する必要があります。
関連項目:
例E-39 ora:containsで使用するポリシーの作成
BEGIN
CTX_DDL.create_policy(POLICY_NAME => 'my_nostopwords_policy',
STOPLIST => 'CTXSYS.EMPTY_STOPLIST');
END;
/
例E-40 ora:containsを使用したストップワードの検索
SELECT id FROM purchase_orders_xmltype
WHERE XMLExists(
'declare namespace ora = "http://xmlns.oracle.com/xdb"; (: :)
$d/purchaseOrder/comment[ora:contains(text(), "is") > 0]'
PASSING doc AS "d");
例E-41 ora:containsおよびポリシーmy_nostopwords_policyを使用したストップワードの検索
SELECT id FROM purchase_orders_xmltype
WHERE XMLExists(
'declare namespace ora = "http://xmlns.oracle.com/xdb"; (: :)
$d/purchaseOrder/comment
[ora:contains(text(), "is", "MY_NOSTOPWORDS_POLICY") > 0]'
PASSING doc AS "d");
ora:containsポリシーは、text_queryの一致セマンティクスに影響を与えます。ポリシーには、レクサー、ストップリスト、ワードリスト・プリファレンスまたはこれらの組合せが含まれる場合があります。CONTEXT索引の作成に使用できる他のプリファレンスは、ora:containsには適用できません。
プリファレンスの効果は次のとおりです。
ワードリスト・プリファレンスによって、ステミング演算子のセマンティクスが改良されます。
ストップリスト・プリファレンスによって、一般的であるために索引付け(検索可能に)しないワードが定義されます。
レクサー・プリファレンスによって、ワードのトークン化および一致方法が定義されます。たとえば、ワードの一部としてカウントする文字および一致で大/小文字を区別するかどうかが定義されます。
関連項目:
事前定義のストップリストを使用したポリシーの作成例は、「ポリシーの例: 提供されているストップリスト」を参照してください。
大/小文字区別のポリシーの例は、「ポリシーの例: ユーザー定義レクサー」を参照してください。
ora:contains検索でのレクサー・プリファレンスの定義および使用の例を示しています。
特定のワードが含まれる文書を検索する場合は通常、検索で大/小文字を区別しない方法が使用されます。大文字と小文字を区別して検索すると、期待される結果の一部が省略されることがよくあります。たとえば、"baby monitor"という句が含まれるpurchaseOrdersを検索する場合、使用しているサンプル文書では"Baby Monitor"と記述されているというだけの理由で、この文書の検索が行われないとは予測しません。
ora:containsを使用した全文検索では、デフォルトで大/小文字が区別されません。ただし、セクション名および属性名は常に、大/小文字が区別されます。
全文検索で大/小文字を区別する場合は、ポリシーの作成時にそのように選択する必要があります。次の手順を使用します。
プロシージャCTX_DDL.create_preference(またはCTX_DDL.create_stoplist)を使用して、プリファレンスを作成します。
プロシージャCTX_DDL.set_attributeを使用して新規プリファレンスの属性を設定することによって、そのプリファレンス・オブジェクトのデフォルトの選択肢をオーバーライドします。
そのプリファレンスをCTX_DDL.create_policyのパラメータとして使用します。
問合せではora:containsの3番目の引数として、ポリシー名を使用します。
プリファレンスを作成した後は、そのプリファレンスを他のポリシーまたはCONTEXT索引の定義で再利用できます。すべてのora:contains問合せで、任意のポリシーを使用できます。
例E-42では、text_query内の"HURRY"が、デフォルトの大/小文字が区別されない索引が設定されたpurchaseOrder内の"Hurry"と一致するため、1行戻されます。
例E-43では、属性mixed_caseがTRUEに設定された新しいレクサー・プリファレンスmy_lexerが作成されます。この例では、printjoin文字も"-"、"!"、","に設定されます。CONTEXT索引の作成およびポリシーの作成に同じプリファレンスを使用できます。
関連項目:
レクサー属性の完全なリストは、『Oracle Textリファレンス』を参照してください。
例E-44では、新規ポリシーmy_policyが作成され、レクサーのみが指定されます。他のプリファレンスはすべてデフォルトに設定されます。例E-44では、preference-case-mixedが使用されます。
例E-45では、問合せで新規ポリシーが使用されます。text_query内の"HURRY"はpurchaseOrder内の"Hurry"と一致しないため、行は戻されません。
例E-46では、text_queryの"Hurry"がcomment要素内のテキスト"Hurry"と正確に一致するため、1行戻されます。
例E-42 ora:contains、デフォルトの大/小文字の区別
SELECT id FROM purchase_orders_xmltype
WHERE XMLExists(
'declare namespace ora = "http://xmlns.oracle.com/xdb"; (: :)
$d/purchaseOrder/comment[ora:contains(text(), "HURRY") > 0]'
PASSING doc AS "d");
例E-43 大/小文字混合のプリファレンスの作成
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;
/
例E-44 大/小文字混合の(大/小文字が区別されない)ポリシーの作成
BEGIN
CTX_DDL.create_policy(POLICY_NAME => 'my_policy',
LEXER => 'my_lexer');
END;
/
例E-45 ora:contains、大/小文字の区別(1)
SELECT id FROM purchase_orders_xmltype
WHERE XMLExists(
'declare namespace ora = "http://xmlns.oracle.com/xdb"; (: :)
$d/purchaseOrder/comment
[ora:contains(text(), "HURRY", "my_policy") > 0]'
PASSING doc AS "d");
例E-46 ora:contains、大/小文字の区別(2)
SELECT id FROM purchase_orders_xmltype
WHERE XMLExists(
'declare namespace ora = "http://xmlns.oracle.com/xdb"; (: :)
$d/purchaseOrder/comment[ora:contains(text(), "Hurry") > 0]'
PASSING doc AS "d");
ora:containsのポリシーの引数はオプションです。省略した場合、問合せではデフォルトのポリシーCTXSYS.DEFAULT_POLICY_ORACONTAINSが使用されます。
ora:containsで使用するポリシーを作成するときは、すべてのプリファレンスを指定する必要はありません。たとえば、例E-44では、レクサー・プリファレンスのみが指定されていました。指定されないプリファレンスについては、CREATE_POLICYによって次のデフォルトのプリファレンスが使用されます。
CTXSYS.DEFAULT_LEXER
CTXSYS.DEFAULT_STOPLIST
CTXSYS.DEFAULT_ WORDLIST
ポリシーの作成では、CONTEXT索引の作成が索引メタデータのコピー・セマンティクスに従うのと同様に、プリファレンスとその属性のコピー・セマンティクスに従います。
XPath関数ora:containsはサポートしている索引に依存しません。非常に柔軟です。しかし、索引のない大量のデータを検索する場合、大量のリソースを消費することもあります。そのような場合のパフォーマンス向上の助けになるテクニックを示します。
この項では、XPath関数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を使用しても生成できます。コマンドAUTOTRACE、traceおよびtkprofについては、この章で説明しません。
この項の内容は次のとおりです。
XPath関数ora:containsは、処理のコストが比較的かかるため、可能な場合は1次フィルタを組み込んだ問合せの作成をお薦めします。この結果、ora:containsで処理される行数が最小化されます。
例E-47では、実行計画からわかるように、表内の各行が検査(全表スキャン)されます。この例で、ora:containsは各行に対して評価されます。
例E-48のように、列idに対して索引を作成し、例E-49のように、選択性の高い述語idを問合せに追加すると、実行計画に示すように、索引idによって実行処理が起動されます。関数ora:containsは、idが5未満の行でのみ実行されます。
例E-47 大規模な表のora:contains
SELECT id FROM purchase_orders_xmltype_big
WHERE XMLExists(
'declare namespace ora = "http://xmlns.oracle.com/xdb"; (: :)
$d/purchaseOrder/comment[ora:contains(text(), "constitution") > 0]'
PASSING doc AS "d");
Execution Plan
------------------------------------------------------------------------------------------------
| Id | Operation | Name |Rows|Bytes|Cost(%CPU)| Time|
------------------------------------------------------------------------------------------------
| 0| SELECT STATEMENT | | 32|64480|686(38)|00:00:09|
|* 1| FILTER | | | | | |
| 2|TABLE ACCESS FULL |PURCHASE_ORDERS_XMLTYPE_BIG|1161|2284K| 140(3)|00:00:02|
|* 3|COLLECTION ITERATOR PICKLER FETCH| XMLSEQUENCEFROMXMLTYPE | | | | |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter( EXISTS (SELECT 0 FROM TABLE() "KOKBF$" WHERE
SYS_XMLCONTAINS(SYS_XQ_UPKXML2SQL(SYS_XQEXVAL(SYS_XQEXTRACT(SYS_XQCON2SEQ(VALUE(KOKBF$)),
'/comment/text()'),1,50),50,1,0),'constitution')>0))
3 - filter(SYS_XMLCONTAINS(SYS_XQ_UPKXML2SQL(SYS_XQEXVAL(SYS_XQEXTRACT(SYS_XQCON2SEQ(VALUE(KOKBF$)),
'/comment/text()'),1,50),50,1,0),'constitution')>0)
Note
-----
- dynamic sampling used for this statement
例E-48 IDのBツリー索引
CREATE INDEX id_index ON purchase_orders_xmltype_big(id);
例E-49 大規模な表のora:contains (追加の述語を使用)
SELECT id FROM purchase_orders_xmltype_big
WHERE XMLExists(
'declare namespace ora = "http://xmlns.oracle.com/xdb"; (: :)
$d/purchaseOrder/comment[ora:contains(text(), "constitution") > 0]'
PASSING doc AS "d")
AND id > 5;
Execution Plan
-----------------------------------------------------------------------------------------------
| Id | Operation | Name |Rows| Bytes |Cost(%CPU)| Time|
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2015 |8 (13)|00:00:01|
|* 1 | TABLE ACCESS BY INDEX ROWID|PURCHASE_ORDERS_XMLTYPE_BIG| 1 | 2015 |8 (13)|00:00:01|
|* 2 | INDEX RANGE SCAN |ID_INDEX | 10 | |2 (0)|00:00:01|
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(EXISTSNODE(SYS_MAKEXML("PURCHASE_ORDERS_XMLTYPE_BIG"."SYS_NC00003$
"),'/purchaseOrder/items/item/comment[ora:contains(text(), "constitution") >
0]','xmlns:ora="http://xmlns.oracle.com/xdb"')=1)
2 - access("ID">5)
Note
-----
- dynamic sampling used for this statement
Oracle XQuery関数ora:containsはサポートしている索引に依存しませんが、XPathリライトが行われる際には多くの場合、高いパフォーマンスを得るためにora:containsは既存のCONTEXT索引を使用します。
Oracle Databaseでは、XPath式を使用する問合せを最適化することがあります。このXPathリライトは、問合せの最適化の一部として自動的に行われます。
例E-50のXPath式の単純評価では、列docの各セルがその式と一致しているかどうかをテストします。
しかし、docがXML Schemaに基づいており、purchaseOrder文書がオブジェクト・リレーショナル表XMLTypeに物理的に格納されている場合は、列comment(存在する場合)に直接アクセスし、そこで各セルが"electric"と一致しているかどうかをテストするほうが効率的です。
ora:containsの最初の引数が単一のリレーショナル列にマップされている場合、完全なXPath式をXML文書全体に適用するかわりに、ora:containsをその列に適用することができます。この結果、索引が含まれていない場合でも、問合せのパフォーマンスが大幅に向上します。
ora:containsをCONTEXT索引を持つ列にマップするテキスト・ノードまたは属性とともに使用している場合、その索引を基礎となる列のデータに適用することがあります。CONTEXT索引をオブジェクト・リレーショナルXMLTypeデータとともに使用するには、次の両方の条件を満たす必要があります。
ora:containsのターゲット(input_text)は、親ノードが列にマップされている(a)単一のテキスト・ノード、または(b)列にマップされている属性の必要があります。列は(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です。
最後に、CONTEXT索引は通常非同期です。ワード"dog"が含まれる新しい文書を追加した場合にCONTEXT索引を同期化しないと、"dog"のcontains問合せでその文書が戻されません。しかし、同じデータに対するora:contains問合せでは戻されます。ora:containsとリライトされたSQL containsで常に同じ結果が戻されるようにするには、PARAMETERS文字列にTRANSACTIONALキーワードを指定してCONTEXT索引を作成します。
関連項目:
パラメータTRANSACTIONALを指定してALTER INDEXを使用してトランザクション型のCONTEXT索引を作成する方法については、『Oracle Textリファレンス』を参照してください
XMLQuery、XMLTableまたはXMLExistsを使用した問合せ。XPath式にはora:containsが含まれ、ora:containsポリシーがCONTEXT索引の索引に関する選択内容と正確に一致し、次のいずれかの条件が当てはまる場合、XPathリライト対象とみなすことができます。
XMLデータはobject-relationallyに格納されます。最初のora:contains引数(input_text)が、親ノードが単一のリレーショナル列にマップされている単一のテキスト・ノードであるか、または単一のリレーショナル列にマップされている属性である場合。その列には、トランザクション型のCONTEXT索引があります。
XMLデータがXMLIndex索引によって索引付けされたバイナリXMLで、非構造化XMLIndexコンポーネントのパス表VALUE列または構造化XMLIndexコンポーネントのスカラー値列にCONTEXT索引があります。
CONTEXT索引が非トランザクション型の場合は、XQuery拡張式プラグマora:use_text_indexを使用して、CONTEXT索引の使用を強制する必要もあります。例E-51に、これを示します。
例E-51では、例6-10で作成したXMLIndex索引を使用しています。非構造化XMLIndexコンポーネントのVALUE列にCONTEXT索引を作成します。実行計画では、XMLIndex索引とCONTEXT索引の両方が選択されていることが示されています。前者はmy_path_tableおよびpikey索引SYS89559_PO_XMLINDE_PIKEY_IXへの参照によって示されます。後者はpo_otext_ixおよび述語アクセスのCONTAINSへの参照によって示されます。
例E-50 ora:containsでの"electric"の検索
SELECT id FROM purchase_orders_xmltype
WHERE XMLExists(
'declare namespace ora = "http://xmlns.oracle.com/xdb"; (: :)
$d/purchaseOrder/items/item/comment
[ora:contains(text(), "electric") > 0]'
PASSING doc AS "d");
例E-51 XQueryプラグマora:use_text_indexをora:containsとともに使用する
CREATE INDEX po_otext_ix ON my_path_table (VALUE) INDEXTYPE IS CTXSYS.CONTEXT; EXPLAIN PLAN FOR SELECT DISTINCT XMLCast(XMLQuery('$p/PurchaseOrder/ShippingInstructions/address' PASSING po.OBJECT_VALUE AS "p" RETURNING CONTENT) AS VARCHAR2(256)) "Address" FROM po_binxml po WHERE XMLExists( '$p/PurchaseOrder/ShippingInstructions/address [(# ora:use_text_index #) {ora:contains(., "$(Fortieth)")} > 0]' PASSING po.OBJECT_VALUE AS "p");
---------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes|Cost (%CPU)| Time | ---------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 3046 | 12 (17)|00:00:01| | 1 | SORT GROUP BY | | 1 | 3524 | | | |* 2 | TABLE ACCESS BY INDEX ROWID BATCHED| MY_PATH_TABLE | 2 | 7048 | 3 (0)|00:00:01| |* 3 | INDEX RANGE SCAN | SYS89559_PO_XMLINDE_PIKEY_IX | 1 | | 2 (0)|00:00:01| | 4 | HASH UNIQUE | | 1 | 3046 | 12 (17)|00:00:01| | 5 | NESTED LOOPS | | 1 | 3046 | 8 (13)|00:00:01| | 6 | SORT UNIQUE | | 1 | 3034 | 6 (0)|00:00:01| |* 7 | TABLE ACCESS BY INDEX ROWID | MY_PATH_TABLE | 1 | 3034 | 6 (0)|00:00:01| |* 8 | DOMAIN INDEX | PO_OTEXT_IX | | | 4 (0)|00:00:01| | 9 | TABLE ACCESS BY USER ROWID | PO_BINXML | 1 | 12 | 1 (0)|00:00:01| ---------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter(SYS_XMLI_LOC_ISNODE("SYS_P3"."LOCATOR")=1) 3 - access("SYS_P3"."RID"=:B1 AND "SYS_P3"."PATHID"=HEXTORAW('6F7F')) 7 - filter("SYS_P1"."PATHID"=HEXTORAW('6F7F') AND SYS_XMLI_LOC_ISNODE("SYS_P1"."LOCATOR")=1) 8 - access("CTXSYS"."CONTAINS"("SYS_P1"."VALUE",'$(Fortieth)')>0) Note ----- - dynamic sampling used for this statement (level=2) 28 rows selected.
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 ::= "_"
XQueryを使用しないXMLデータの全文検索の例としてコードのサポートを示します。
発注書XML文書が示されています。XQueryを使用しないXMLでの全文検索の例で使用されます。
例E-52 発注書の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>
XQueryを使用しない全文検索の例で使用される発注書表を作成するCREATE TABLE文が示されています。
例E-53 表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;
例E-54 表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;
例E-55 表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が示されています。XML発注書に対する全文検索の例で使用されます。
例E-56 全文検索する発注書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="en">
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>