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>