D 全文問合せ用のXMLデータの索引付け(23ai前)

XMLデータの全文検索を行う必要がある場合は、バイナリXMLとしてXMLTypeデータを格納し、XQuery Full Text (XQFT)を使用することをお薦めします。これには、XML検索索引を使用します。これが、この項の内容です。

XML検索索引は、SEARCH INDEX FOR XML構文を使用するか、XQFT対応のCONTEXT索引を作成することで作成できます。SEARCH INDEX FOR XMLを使用してXML検索索引を作成することをお薦めします。

移植性やコードの標準化が問題にならない場合や、XMLTypeデータがオブジェクト・リレーショナル形式で格納されている場合は、かわりにOracle固有の全文構造体とOracle Textが提供している構文、具体的にはOracle SQL関数containsを使用できます。

バイナリXMLとして格納されているXMLTypeデータに対しては、XQuery Full Text (XQFT)問合せを実行できます。SQL WHERE句内のXMLExists式でXQFT全文述語を使用する場合は、XML検索索引を作成する必要があります。この項では、このような索引の作成と使用について説明します。

関連項目:

例D-6

関連トピック

XML検索索引の作成と使用

XQuery Full Text問合せでは、パフォーマンスを高めるためにXML検索索引を使用できます。

XML検索索引を作成するには、データベース・ロールCTXAPPを付与されている必要があります。一般的にこのロールは、Oracle Text索引の作成、Oracle Text索引プリファレンスの設定、またはOracle Text PL/SQLパッケージの使用に必要です。

索引を作成する前に、Oracle Textパス・セクション・グループを作成して、そのXML_ENABLE属性をtに設定する必要があります。これにより、パス・セクション・グループがXML対応になります。

パフォーマンスを向上させるには、Oracle Textデータ・ディクショナリ内にBASIC_STORAGE型の索引プレファレンスを作成して、次の属性を指定します。

  • D_TABLE_CLAUSE – XML文書の構造に関する情報が含まれている索引データ表$Dの列DOCに対して、SECUREFILE記憶域を指定します。キャッシュおよび圧縮レベル(MEDIUM)を指定します。

  • I_TABLE_CLAUSE – 全文トークンと索引付けされた文書でのその出現に関する情報が含まれている索引データ表$Iの列TOKEN_INFOに対して、SECUREFILE記憶域を指定します。キャッシュを指定します(ただし圧縮は不要)。

これについては例D-1で、XML Schemaに基づかないXMLTypepo_binxml (標準のデータベース・スキーマOE内の表purchaseorderと同じデータを持つ)を使用して説明します。

索引プレファレンスBASIC_STORAGEは、Oracle Text索引を構成するデータベース表および索引に対する表領域および作成パラメータを指定します。

関連項目:

例D-2では、データ問合せを実行して、テキストにBigStreetの両方がこの順序で含まれるDescription要素を取得します。

例D-3は、索引po_ctx_idxの取得を指示する、問合せの実行計画を示しています。

例D-1 XML検索索引の作成

BEGIN
  CTX_DDL.create_section_group('mysecgroup', 'PATH_SECTION_GROUP');
  CTX_DDL.set_sec_grp_attr('mysecgroup', 'XML_ENABLE', 'T');

  CTX_DDL.create_preference('mypref', 'BASIC_STORAGE');
  CTX_DDL.set_attribute('mypref',
                        'D_TABLE_CLAUSE',
                        'TABLESPACE my_ts
                         LOB(DOC) STORE AS SECUREFILE 
                         (TABLESPACE my_ts COMPRESS MEDIUM CACHE)');
  CTX_DDL.set_attribute('mypref',
                        'I_TABLE_CLAUSE',
                        'TABLESPACE my_ts
                         LOB(TOKEN_INFO) STORE AS SECUREFILE
                         (TABLESPACE my_ts NOCOMPRESS CACHE)');
END;
/

CREATE INDEX po_ctx_idx ON po_binxml(OBJECT_VALUE)
  INDEXTYPE IS CTXSYS.CONTEXT
  PARAMETERS('storage mypref section group mysecgroup');

例D-2 XQuery Full Text問合せ

SELECT XMLQuery('for $i in /PurchaseOrder/LineItems/LineItem/Description
                   where $i[. contains text "Big" ftand "Street"]
               return <Title>{$i}</Title>'
               PASSING OBJECT_VALUE RETURNING CONTENT)
  FROM po_binxml
  WHERE XMLExists('/PurchaseOrder/LineItems/LineItem/Description
                   [. contains text "Big" ftand "Street"]'
                  PASSING OBJECT_VALUE);

例D-3 XQuery Full Text問合せの実行計画

------------------------------------------------------------------------------------------
| Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |            |     1 |  2014 |     4   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| PO_BINXML  |     1 |  2014 |     4   (0)| 00:00:01 |
|*  2 |   DOMAIN INDEX              | PO_CTX_IDX |       |       |     4   (0)| 00:00:01 |
------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - access("CTXSYS"."CONTAINS"(SYS_MAKEXML(0,"XMLDATA"),'<query><textquery
              grammar="CONTEXT" lang="english"> ( ( {Big} ) and ( {Street} ) )  INPATH
              (/PurchaseOrder/LineItems/LineItem/Description)</textquery></query>')>0)
 
Note
-----
   - dynamic sampling used for this statement (level=2)
   - Unoptimized XML construct detected (enable XMLOptimizationCheck for more information)
 
21 rows selected.

XML検索索引を取得できない場合の対処方法

特定の条件が確実に満たされるように問合せを変更することで、評価によってXML検索索引が取得されるようにできます。

SQL WHERE句内のXMLExists式でXQuery全文述語を使用しながら、XML検索索引を作成しなかったり、なんらかの理由でその索引を使用できない場合には、コンパイル時エラーORA-18177が発生します。

エラーが発生した場合、実行計画では、索引の取得は指示されません。計画には、操作DOMAIN INDEXの後に索引の名前は表示されません。

この場合は、索引を使用できるように問合せを変更してください。取得する索引では、次の条件の両方を満たす必要があります。

  • 検索コンテキストのXMLノードを計算する式は、ステップがforward軸およびdescendent軸のみに沿ったXPath式にする必要があります。

  • SQL/XML関数XMLExistsPASSING句にSQL式として渡すことのできるXMLTypeインスタンスは1つのみで、同じ句内に含まれるその他の非XMLType SQL式はすべて、組込みSQLデータ型のコンパイル時定数、またはこのようなデータ型のインスタンスにバインドされているバインド変数のいずれかである必要があります。

プラグマora:no_schema: XQuery Full TextでのXML Schemaに基づくデータの使用

XQuery Full TextとXML検索索引を使用する場合は、一般に、XML Schemaに基づかないXMLTypeデータの使用をお薦めします。ただし、状況によっては、バイナリXMLとして格納されているXML SchemaベースのXMLTypeデータを使用できます。このコンテキストでは、Oracle XQueryプラグマora:no_schemaが役立つ場合があります。

デフォルトで、XML検索索引を使用してXML Schemaに基づくデータを評価する場合は、コンパイル時エラーORA-18177が発生します。これは、全文索引機能が型を認識しないため、関連付けられたXML Schemaを利用しないことが原因です。適用されるすべてのテキストが型指定なしとして扱われます。このエラーは、データが適切に型キャストされている場合でも発生するため、XML Schemaの暗黙的な型キャストには依存しません。例D-4に、これを示します。

問合せの全文条件が、XML Schema型と型指定された操作に依存することを想定していたユーザーは、発生したエラーによってこれを意識するようになります。

型に依存する条件を使用するためには、関連するXQuery式を明示的に適切な型にキャストする必要があります。Oracle XML DBでは、XML Schemaを使用して暗黙的な型キャストを実行することはありません。型キャストを適切に実行できないと、予期しない結果が生じる可能性があります。

例D-5は、適切な条件が評価されるように型キャストを明示的に指定した、XML Schemaに基づくデータの問合せを示しています。

ただし、XQuery Full Text式を使用する場合は通常、XML Schemaに基づくデータを扱うときでも、型指定されたデータは含めません。型指定されたデータを条件で使用する場合は、適切な型にキャストする必要があるので注意してください。

つまり、型指定されたデータが問合せに含まれていないことがわかっている、または特定の型指定されたデータを型指定されていないデータとして扱っても問題ない、あるいは型指定が必要なデータは明示的に型キャストする場合は、問合せでOracle XQueryプラグマora:no_schemaを使用すれば、エラーの発生を防ぎつつ、XML検索索引を使用して問合せを評価できます。

例D-4 XML Schemaに基づくデータを使用したXQuery Full Text問合せ: エラーORA-18177

SELECT XMLQuery('/PurchaseOrder/LineItems/LineItem'
                PASSING OBJECT_VALUE RETURNING CONTENT)
  FROM oe.purchaseorder
  WHERE XMLExists('/PurchaseOrder
                   [LineItems/LineItem/@ItemNumber > xs:integer("20")
                    and Actions/Action/User contains text "KPARTNER"]'
                  PASSING OBJECT_VALUE);
  FROM oe.purchaseorder
          *
ERROR at line 3:
ORA-18177: XQuery full text expression '/PurchaseOrder
[LineItems/LineItem/@ItemNumber > xs:integer("20")
and Actions/Action/User contains text "KPARTNER"]'
cannot be evaluated using XML text index

例D-5 XML Schemaに基づくデータでのXQueryプラグマora:no_schemaの使用

SELECT XMLQuery('/PurchaseOrder/LineItems/LineItem'
                PASSING OBJECT_VALUE RETURNING CONTENT)
  FROM oe.purchaseorder
  WHERE XMLExists('(# ora:no_schema #)
                   {/PurchaseOrder
                    [LineItems/LineItem/@ItemNumber > xs:integer("20")
                     and Actions/Action/User contains text "KPARTNER"]}'
                  PASSING OBJECT_VALUE);

プラグマora:use_xmltext_idx: XML検索索引の強制的な使用

XQueryプラグマora:use_xmltext_idxを使用して、XML検索索引の使用を強制できます。

XMLデータを使用する問合せは、存在する索引の種類や数などによって、様々な方法で評価できます。デフォルトの評価方法が最もパフォーマンスに優れているとはかぎらず、既存のXML検索索引を強制的に使用した方がより効率的な場合があります。XQueryプラグマora:use_xmltext_idxを使用すれば、これを行うことができます。(XML検索索引は、バイナリXMLとして格納されているXMLTypeデータにのみ適用されます。)

たとえば、WHERE句に2つのXMLExists式があり、いずれか一方にのみXQuery Full Textの条件が含まれ、全文条件がない方のXMLExists式にはXMLIndex索引を適用するとします。このような問合せでは、通常、XML検索索引を使用してWHERE句全体を評価した方がより効率的です。

問合せに全文条件がない場合でも、XML検索索引を使用することによって、問合せの評価の効率性が向上する可能性があります。

例D-6の問合せでは、プラグマora:use_xmltext_idxの使用方法を示しています。XMLExistsの最初の句にのみ全文条件が使用されています。プラグマが指定されているので、全文索引(po_ctx_idx例D-1で作成)は、両方のXMLExists句で使用されます。

例D-6 XQueryプラグマora:use_xmltext_idxを使用した全文問合せ

SELECT XMLQuery('/PurchaseOrder/LineItems/LineItem'
                PASSING OBJECT_VALUE RETURNING CONTENT)
  FROM po_binxml
  WHERE XMLExists('/PurchaseOrder/LineItems/LineItem
                   [Description contains text "Picnic"]' PASSING OBJECT_VALUE)
    AND XMLExists('(# ora:use_xmltext_idx #) {/PurchaseOrder[User="SBELL"]}'
                  PASSING OBJECT_VALUE);

Oracle Text索引の使用からXML検索索引への移行

バイナリXMLとして格納されているXMLTypeデータに対するレガシー問合せで、SQL関数CONTAINSと、XML非対応のOracle Text索引が使用されている場合は、かわりにXQuery Full Text構造体を使用することを検討してください。

XQuery and XPath Full Text (XQFT)標準は、Oracle Database 12cリリース1 (12.1)からOracle XML DBでサポートされるようになりました。このサポートは、バイナリXMLとして格納されているXMLTypeデータにのみ適用されます。そのリリースより前は、XMLデータの全文問合せに使用できたのはXML非対応のOracle Text索引のみ(XML検索索引ではなく)だったので、全文問合せでは必ずOracle固有の構造体(SQL関数CONTAINS)が使用されていました。

これを使用しているレガシー・コードがある場合は、そのコードを移行してXQFTを使用することをお薦めします。この項では、問合せで使用されているCONTAINSを置き換える場合に使用できるXQFTの構造体について説明します。

Oracle Text索引のこのような使用方法は、XML検索索引を使用することで代替できます。HASPATHを使用する問合せを簡単なXQuery式を使用する問合せで置き換えるには、Oracle XQueryプラグマora:use_xmltext_idxを使用して、XML検索索引を取得するように指定します。この項では、これについても説明します。

表D-1に、Oracle固有の構造体を使用する一般的な問合せからXQuery Full Textを使用する問合せへのマッピングを示します。

表D-1 Oracle固有のXML問合せのXQuery Full Textへの移行

元の例 置換後の例
CONTAINS(t.x, 'HASPATH (/P/LIs/LI/DescriptionFoot 1)') > 0
XMLExists('(# ora:use_xmltext_idx #) 
           {$d/P/LIs/LI/DescriptionFoot 1}'
          PASSING t.x AS "d")

または、データがXML Schemaに基づく場合:

XMLExists('(# ora:use_xmltext_idx #)
           {(# ora:no_schema #) 
            {$d/P/LIs/LI/DescriptionFoot 1}}'
          PASSING t.x AS "d")
CONTAINS(t.x, 'Big INPATH
               (/P/LIs/LI/Description)') > 0
XMLExists('$d/P/LIs/LI/Description
           [. contains text "Big"]'
          PASSING t.x AS "d")

または、データがXML Schemaに基づく場合:

XMLExists('(# ora:no_schema #)
           {$d/P/LIs/LI/Description
           [. contains text "Big"]}'
          PASSING t.x AS "d")
CONTAINS(t.x, '(Big) AND (Street) INPATH
               (/P/LIs/LI/Description)') > 0
XMLExists('$d/P/LIs/LI/Description
           [. contains text "Big" ftand "Street"]'
          PASSING t.x AS "d")
CONTAINS(t.x, '(Big) OR (Street) INPATH
               (/P/LIs/LI/Description)') > 0
XMLExists('$d/P/LIs/LI/Description
           [. contains text "Big" ftor "Street"]'
          PASSING t.x AS "d")
CONTAINS(t.x, '({Big}) NOT ({Street}) INPATH
               (/P/LIs/LI/Description)') > 0
XMLExists('$d/P/LIs/LI/Description
           [. contains text
            "Big" ftand ftnot "Street"]'
          PASSING t.x AS "d")
CONTAINS(t.x, '({Street}) MNOT ({Big Street}) INPATH
               (/P/LIs/LI/Description)') > 0
XMLExists('$d/P/LIs/LI/Description
           [. contains text
            "Street" not in "Big Street"]'
          PASSING t.x AS "d")
CONTAINS(t.x, '(NEAR (({Big}, {Street}), 3) INPATH
               (/P/LIs/LI/Description)') > 0
XMLExists('$d/P/LIs/LI/Description
           [. contains text
            "Big" ftand "Street" window 3 words]'
          PASSING t.x AS "d")

(適用なし – Oracle Text問合せはXML名前空間に非対応)

XMLExists('declare namespace
           ipo="http://www.example.com/IPO";
           /ipo:P/ipo:LIs/ipo:LI/ipo:Description
           [. contains text "Big"]'
          PASSING t.x AS "d")

脚注1

パスのテストには述語式を含めることができ、それは元の問合せ(HASPATHを使用)でも置換後の問合せでも同じです。たとえば: /PurchaseOrder/LineItems/LineItem/Part[@Id < "31415927"]