11 Oracle Textでのドキュメント・セクションの検索

テキスト問合せアプリケーションでドキュメントのセクションを使用できます。

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

11.1 Oracle Textでのドキュメントのセクション検索について

セクション検索を使用すると、テキスト問合せをドキュメント内のテキストのブロックに絞り込むことができます。セクション検索は、HTMLやXMLのドキュメントのように、ドキュメントに内部構造がある場合に有効です。

また、テキストを文レベルと段落レベルで検索できます。

この項には、次の項目が含まれます。

11.1.1 Oracle Textでのセクション検索の使用可能化

ドキュメント・コレクションのセクション検索を使用可能にするステップは、次のとおりです。

  1. セクション・グループの作成

  2. セクションの定義

  3. ドキュメントの索引付け

  4. WITHIN演算子によるセクション検索

  5. INPATHおよびHASPATH演算子によるパス検索

  6. SDATAセクションを検索可能にする

11.1.1.1 セクション・グループの作成

セクション検索を有効にするには、セクション・グループを定義します。システム定義のセクション・グループのいずれかを使用して、セクション・グループのインスタンスを作成します。ドキュメント・コレクションに適したセクション・グループを選択します。

セクション・グループを使用して、所有しているドキュメント・セットのタイプを指定し、タグ構造を明示的に示します。たとえば、HTMLタグ付きドキュメントを索引付けするには、HTML_SECTION_GROUPを使用します。同様に、XMLタグ付きドキュメントを索引付けするには、XML_SECTION_GROUPを使用します。

表11-1は、各種のセクション・グループを示しています。

表11-1 セクション・グループのタイプ

セクション・グループ・プリファレンス 説明

NULL_SECTION_GROUP

これはデフォルトです。どのセクションも定義しないか、またはSENTENCEPARAGRAPHセクションのみを定義する場合は、このグループ・タイプを使用します。

BASIC_SECTION_GROUP

このグループ・タイプを使用して、開始および終了タグが<A>および</A>という形式のセクションを定義します。

ノート: このグループ・タイプでは、対になっていないカッコ、コメント・タグおよび属性などの入力はサポートされません。これらを入力するには、HTML_SECTION_GROUPを使用してください。

HTML_SECTION_GROUP

このグループ・タイプを使用して、HTMLドキュメントを索引付けし、HTMLドキュメントのセクションを定義します。

XML_SECTION_GROUP

このグループ・タイプを使用して、XMLドキュメントを索引付けし、XMLドキュメントのセクションを定義します。

AUTO_SECTION_GROUP

このグループ・タイプを使用して、XMLドキュメントの開始タグ/終了タグに対して自動的にゾーン・セクションを作成します。XMLと同じく、XMLタグから導出されるセクション名では大/小文字が区別されます。

属性セクションは、属性を持つXMLタグに対して自動的に作成されます。属性セクションは、tag@attributeという形式でネーミングされます。

停止セクション、空のタグ、処理命令およびコメントは、索引付けされません。

自動セクション・グループには次の制限事項が適用されます。

  • ゾーン、フィールドまたは特殊セクションは、自動セクション・グループに追加できません。

  • 自動セクション化は、XMLドキュメント・タイプ(ルート要素)を索引付けしません。

  • プリフィックスおよび名前空間を含む、索引付けされたタグの長さは、64バイト以下です。64バイトより長いタグは索引付けされません。

PATH_SECTION_GROUP

このグループ・タイプを使用して、XMLドキュメントを索引付けします。このプリファレンスは、AUTO_SECTION_GROUPのように動作します。

相違点は、INPATHおよびHASPATH演算子でパスを検索できることです。タグまたは属性名の問合せでは、大/小文字が同様に区別されます。

NEWS_SECTION_GROUP

このグループを使用して、RFC 1036に従ったニュース・グループ形式のドキュメントのセクションを定義します。

ノート:

HTMLXMLAUTOおよびPATHセクショナに送られるドキュメントは、\s*<で始まる必要があります。\s*は、0文字以上の空白文字を表します。それ以外のドキュメントはプレーンテキスト・ドキュメントとして処理され、いずれのセクションも認識されません。

CTX_DDLパッケージを使用してセクション・グループを作成し、セクション・グループの構成要素としてセクションを定義します。たとえば、HTMLドキュメントを索引付けするには、HTML_SECTION_GROUPを使用してセクション・グループを作成します。

begin
ctx_ddl.create_section_group('htmgroup', 'HTML_SECTION_GROUP');
end;

ノート:

Oracle Database 18c以降、Oracle TextのNEWS_SECTION_GROUPの使用は非推奨になりました。かわりに外部処理を使用します。

USENET投稿に索引を付ける場合、Oracle Text内でBASIC_SECTION_GROUPまたはHTML_SECTION_GROUPを使用するように投稿を前処理します。USENETは、商用ではあまり使用されません。

11.1.1.2 セクションの定義

セクションは、セクション・グループの構成要素として定義します。次の例では、HTML <H1>タグ内の全テキストに対してheadingというゾーン・セクションを定義します。

begin
ctx_ddl.create_section_group('htmgroup', 'HTML_SECTION_GROUP');
ctx_ddl.add_zone_section('htmgroup', 'heading', 'H1');
end;

ノート:

AUTO_SECTION_GROUPまたはPATH_SECTION_GROUPを使用して、XMLドキュメント・コレクションを索引付けする場合は、セクションを明示的に定義する必要はありません。索引付け中にセクションが定義されます。

関連項目:

11.1.1.3 ドキュメントの索引付け

ドキュメントの索引付け時に、セクション・グループをCREATE INDEXのPARAMETERS句に指定します。

create index myindex on docs(htmlfile) indextype is ctxsys.context 
parameters('filter ctxsys.null_filter section group htmgroup');
11.1.1.4 WITHIN演算子によるセクションの検索

ドキュメントが索引付けされている場合は、WITHIN演算子を使用して、セクション内を問い合せることができます。たとえば、ドキュメントのヘッダー内にワードOracleを含むすべてのドキュメントを検索するには、次の問合せを入力します。

'Oracle WITHIN heading'

関連項目:

WITHIN演算子の使用方法の詳細は、『Oracle Textリファレンス』を参照してください。

11.1.1.5 INPATHおよびHASPATH演算子によるパスの検索

PATH_SECTION_GROUPを使用した場合は、自動的にXMLセクションが作成されます。WITHIN演算子を使用して問合せを入力できる他、INPATH演算子とHASPATH演算子を使用してパス検索を入力できます。

関連項目:

11.1.1.6 SDATAセクションを検索可能にする
SDATAセクションを検索可能にし、$Sdatatype表を作成するには、CTX_DDL.SET_SECTION_ATTRIBUTE APIを使用します。

作成される表は、次のとおりです。

  • $SNNUMBER

  • $SDDATE

  • $SVVARCHAR2, CHAR

  • $SRRAW

  • $SBDBINARY DOUBLE

  • $SBFBINARY FLOAT

  • $STTIMESTAMP

  • $STZTIMESTAMP WITH TIMEZONE

次の例では、このSDATAセクションの$SV表を作成し、そのセクションで効率的な検索を可能にします。
ctx_ddl.add_sdata_section('sec_grp', 'sdata_sec', 'mytag', 'varchar');
ctx_ddl.set_section_attribute('sec_grp', 'sdata_sec', 'optimized_for', 'search');

この属性のデフォルト値はFALSEです。

11.1.2 Oracle Textのセクション・タイプ

セクション・タイプはすべて、ドキュメント内のテキストのブロックです。ただし、セクションを区切る方法や索引内での記録方法にそれぞれ相違があります。セクションは、次のタイプのいずれかです。

表11-2に、各種セクション・グループとともに使用されるセクション・タイプを示します。

表11-2 セクション・タイプおよびセクション・グループ

セクション・グループ ZONE FIELD STOP MDATA NDATA SDATA ATTRIBUTE SPECIAL

NULL

NO

NO

NO

NO

NO

NO

NO

YES

BASIC

YES

YES

NO

YES

YES

YES

NO

YES

HTML

YES

YES

NO

YES

YES

YES

NO

YES

XML

YES

YES

NO

YES

YES

YES

YES

YES

NEWS

YES

YES

NO

YES

YES

YES

NO

YES

AUTO

NO

NO

YES

NO

NO

NO

NO

NO

PATH

NO

NO

NO

NO

NO

NO

NO

NO

11.1.2.1 ゾーン・セクション

ゾーン・セクションは、ドキュメント内の開始タグと終了タグで区切られたテキストの本体です。開始タグと終了タグの位置は索引内に記録されているため、タグで囲まれたワードはそのセクション内に存在するとみなされます。ゾーン・セクションのインスタンスすべてに開始タグと終了タグが付いている必要があります。

たとえば、<TITLE></TITLE>の2つのタグに挟まれたテキストは、ゾーン・セクションとして次のように定義します。

<TITLE>Tale of Two Cities</TITLE>
It was the best of times...

ゾーン・セクションは、ドキュメント内でネスト、オーバーラップおよび繰返しができます。

ゾーン・セクションの問合せ時に、全セクション内の語句を検索するには、WITHIN演算子を使用します。Oracle Textにより、定義済のセクション内に問合せ語句を含むドキュメントが戻ります。

ゾーン・セクションは、HTMLおよびXMLドキュメントのセクションの定義に最適です。ゾーン・セクションを定義するには、CTX_DDL.ADD_ZONE_SECTION.を使用します

たとえば、次のようにbooktitleというセクションを定義したとします。

begin
ctx_ddl.create_section_group('htmgroup', 'HTML_SECTION_GROUP');
ctx_ddl.add_zone_section('htmgroup', 'booktitle', 'TITLE');
end;

索引付けした後で、booktitleセクション内の語句 Citiesを含むすべてのドキュメントを次のように検索できます。

'Cities WITHIN booktitle'

(dog and cat) WITHIN booktitleのような複数の問合せ語句の場合は、Oracle Textにより、booktitleセクションの同じインスタンス内にcatdogを含むドキュメントが検出されます。

繰返しゾーン・セクション

ゾーン・セクションは繰返しが可能です。出現はそれぞれ別セクションとして処理されます。たとえば、<H1>headingセクションを示す場合は、次のように同じドキュメント内でheadingを繰り返すことができます。

<H1> The Brown Fox </H1>
<H1> The Gray Wolf </H1>

これらのゾーン・セクションがHeadingという名前の場合、問合せBrown WITHIN Headingはこのドキュメントを戻します。ただし、(Brown and Gray) WITHIN Headingという問合せはできません。

ゾーン・セクションのオーバーラップ

ゾーン・セクションは互いにオーバーラップできます。たとえば、<B><I>が2つの異なるゾーン・セクションを示す場合、これらはドキュメント内で次のようにオーバーラップできます。

plain <B> bold <I> bold and italic </B> only italic </I>  plain

ネストされたゾーン・セクション

ゾーン・セクションは、次のようにネストできます。

<TD> <TABLE><TD>nested cell</TD></TABLE></TD>

WITHIN演算子を使用して、セクション内のセクションのテキストを検索するための問合せを記述できます。たとえば、BOOK1、BOOK2およびAUTHORのゾーン・セクションが、ドキュメントdoc1およびdoc2で次のように出現するとします。

doc1:

<book1> <author>Scott Tiger</author> This is a cool book to read.</book1>

doc2:

<book2> <author>Scott Tiger</author> This is a great book to read.</book2>

次のようにネストされた問合せを実行します。これはdoc1のみを戻します。

'(Scott within author) within book1'
11.1.2.2 フィールド・セクション

フィールド・セクションは、ゾーン・セクションと同じように、開始タグと終了タグで区切られたテキストの範囲です。フィールド・セクションはゾーン・セクションより効率的で、リージョンがドキュメントの残りの部分とは別に索引付けされる点でゾーン・セクションと異なります。作成できるフィールド・セクションの数は無制限です。

フィールド・セクションは異なる方法で索引付けされるため、大量のドキュメントが索引付けされている場合は、ゾーン・セクションに比べて問合せパフォーマンスが向上します。

フィールド・セクションは、ニュース・ヘッダーのフィールドなどドキュメントに1回のみ出現するセクションに最適です。また、フィールド・セクションは、ドキュメントの残りの部分で参照できます。

ゾーン・セクションとは異なり、フィールド・セクションには次の制限事項があります。

  • オーバーラップできません。

  • 繰り返すことはできません。

  • ネストできません。

Visibleなフィールド・セクションおよびInvisibleなフィールド・セクション

デフォルトでは、フィールド・セクションはドキュメントの残りの部分とは別にサブドキュメントとして索引付けされます。このため、フィールド・セクションは前後のテキストから参照不能であり、WITHIN句でそのセクション名を明示的に指定することによってのみ問い合せることができます。

フィールド・セクション内のテキストをドキュメント全体の一部として索引付けする場合は、フィールド・セクションを参照可能にできます。参照可能なフィールド・セクション内のテキストは、WITHIN演算子を使用してもしなくても問い合せることができます。

次の例では、参照不能なフィールド・セクションと参照可能なフィールド・セクションの相違点を示します。このコードは、BASIC_SECTION_GROUP型のbasicgroupセクション・グループを定義します。次に、<A>タグに対してAuthorというフィールド・セクションをbasicgroupに作成します。また、参照可能フラグをFALSEに設定して、参照不能なセクションを作成します。

begin
ctx_ddl.create_section_group('basicgroup', 'BASIC_SECTION_GROUP');
ctx_ddl.add_field_section('basicgroup', 'Author', 'A', FALSE);
end;

Authorフィールド・セクションは参照不能であるため、Authorセクション内のテキストを検索するには、次のようにWITHIN演算子を使用する必要があります。

'(Martin Luther King) WITHIN Author'

WITHIN演算子を使用せずにMartin Luther Kingを問い合せても、フィールド・セクション内のこの語句のインスタンスは戻りません。WITHINを指定せずにフィールド・セクション内のテキストを問い合せる場合は、セクション作成時に次のように参照可能フラグをTRUEに設定する必要があります。

begin
ctx_ddl.add_field_section('basicgroup', 'Author', 'A', TRUE);
end;

ネストされたフィールド・セクション

フィールド・セクションはネストできません。たとえば、フィールド・セクションを<TITLE>で始まるように定義し、別のフィールド・セクションを<FOO>で始まるように定義した場合、この2つのセクションを次のようにネストすることはできません

<TITLE> dog <FOO> cat </FOO> </TITLE>

ネストされたセクションを使用するには、これらをゾーン・セクションとして定義します。

繰返しフィールド・セクション

繰返しフィールド・セクションは使用できますが、WITHIN問合せはこれらを1つのセクションとして処理します。次に、ドキュメントの繰返しフィールド・セクションの例を示します。

<TITLE> cat </TITLE>
<TITLE> dog </TITLE>

問合せ(dog and cat)within titleは、これらのワードが別のセクション内に存在している場合でも、ドキュメントを検出します。

WITHIN問合せで繰返しセクションを区別するには、これらをゾーン・セクションとして定義します。

11.1.2.3 停止セクション

自動セクション・グループに停止セクションを追加すると、自動セクション索引付け演算子では、XMLドキュメントの指定されたセクションが無視されます。

ノート:

停止セクションを追加すると、索引内にセクション情報が作成されません。ただし、停止セクション内のテキストは常に検索可能です。

ユーザーのドキュメントに多数の下位レベルの情報タグが含まれているときに、停止セクションを追加すると役立ちます。また、停止セクションを追加すると、自動セクション・グループを使用した索引付けのパフォーマンスが向上します。

追加できる停止セクションの数は無制限です。

停止セクションにはセクション名がないため、セクション・ビューに記録されません。

11.1.2.4 MDATAセクション

MDATAセクションは、ドキュメントに対するユーザー定義済メタデータの参照に使用します。MDATAセクションによって複合問合せを高速化でき、問合せで戻すことができるMDATAセクションの数に制限はありません。

テキストの内容およびドキュメント・タイプ(雑誌、新聞、小説など)に応じた問合せをする場合を考えます。テキストの列およびドキュメント・タイプの列を含む索引を作成してから、この形式の複合問合せを実行できます。この場合、Adam Thorpe (小説Ulvertonの著者)という句を含むすべての小説を検索します。

SELECT id FROM documents
   WHERE doctype = 'novel'
      AND CONTAINS(text, 'Adam Thorpe')>0;

ただし、通常は、別々の列を使用するよりも、属性(この場合はドキュメント・タイプ)を1つのフィールド・セクションに組み込み、1つのCONTAINS問合せを使用する方が速くなります。

SELECT id FROM documents
  WHERE CONTAINS(text, 'Adam Thorpe AND novel WITHIN doctype')>0;

このアプローチには2つのデメリットがあります。

  • 属性が更新されるたびに、テキスト・ドキュメント全体を再索引付けする必要があります。その結果、索引の断片化が進み、データ操作言語(DML)処理のレートが遅くなります。

  • フィールド・セクションにより、セクション値がトークン化します。トークン化は、次のように影響を及ぼします。小数点または通貨記号などの、メタデータ内の特殊文字は簡単に検索できない、値の検索が困難(John Smithは検索できるが、John Smith, Jr.は検索できないなど)、マルチ・ワードの値を句で問い合せるため、単一のトークン検索よりも遅くなる、マルチ・ワードの値がブラウズ・ワードで表示されないため、作成者のブラウズや主題のブラウズが不可能になる、などです。

そのため、フィールド・セクションではなくMDATAセクションを使用した方が有効です。MDATAセクションは、フィールド・セクションのように索引付けされますが、メタデータ値を追加し、ドキュメント・テキストを再索引付けせずにドキュメントから削除できます。フィールド・セクションとは異なり、MDATA値はトークン化されません。また、MDATAセクションの索引付けは、通常、フィールド・セクションの索引付けよりも使用するディスク・スペースが小さくてすみます。

Oracle Database 12cリリース2 (12.2)以降、MDATAセクションを、その読取り専用タグの値に応じて更新可能または更新不可にすることができるようになりました。値はFALSEまたはTRUEに設定できます。

MDATAセクションをセクション・グループに追加するには、CTX_DDL.ADD_MDATA_SECTIONを使用します。デフォルトでは、読取り専用のMDATAセクションの値はFALSEです。これは、このMDATAセクションに対してCTX_DDL.ADD_MDATA()およびCTX_DDL.REMOVE_MDATA()をコールできることを意味します。そうしない場合は、TRUEに設定できます。FALSEに設定すると、MDATAセクションに対する問合せは、そのMDATAセクションの削除された値を追跡するために索引表でカーソルをオープンする必要があるため、効率よく実行できません。この例では、AUTHORというMDATAセクションを追加し、これに「Soseki Natsume」(小説「Kokoro」の作者)という値を指定します。

ctx_ddl.create.section.group('htmgroup', 'HTML_SECTION_GROUP');
ctx_ddl.add_mdata_section('htmgroup', 'author', 'Soseki Natsume');

MDATA値を変更するにはCTX_DDL.ADD_MDATAを使用し、削除するにはCTX_DDL.REMOVE_MDATAを使用します。また、MDATAセクションには複数の値を指定できます。索引の所有者のみがCTX_DDL.ADD_MDATAおよびCTX_DDL.REMOVE_MDATA.をコールできます

CTX_DDL.ADD_MDATAおよびCTX_DDL.REMOVE_MDATAは、両方ともCTXCAT索引およびCTXRULE索引に対してサポートされていません。

MDATA値はレクサーを介して渡されません。かわりに、すべての値は次のように簡単に正規化されます。

  • 値に隣接する空白は削除されます。

  • 値は255バイトに切り捨てられます。

  • 値は単一の値として索引付けされます。値が複数のワードから構成されていても、分割されません。

  • 大/小文字の区別は保持されます。ドキュメントが動的に生成される場合は、MDATA値を大文字化し、大文字のみが検索されることを確認することで、大/小文字区別を実装できます。

ドキュメントにMDATAメタデータを追加した後、CONTAINS問合せ演算子を使用して、メタデータを問い合せることができます。

SELECT id FROM documents
   WHERE CONTAINS(text, 'Tokyo and MDATA(author, Soseki Natsume)')>0;

AUTHORタグに正確な値Soseki Natsumeがある場合(単純なトークン化後)のみ、この問合せは成功します。SosekiまたはNatsume Sosekiで行は返されません。

以下に、MDATAの考慮事項を示します。

  • MDATA値はハイライト表示されず、CTX_DOC.TOKENSの出力には含められず、FILTER PLAINTEXTを有効にしているときも含められません。

  • MDATAセクションは、セクション・グループ内で一意にする必要があります。たとえば、同じセクション・グループでMDATAセクション、ゾーン・セクションまたはフィールド・セクションの名前としてFOOを使用しないでください。

  • フィールド・セクションと同様に、MDATAセクションはオーバーラップまたはネストできません。MDATAセクションは、最初に発生したタグにより、暗黙的にクローズされます。この例の内容は次のとおりです。

    <AUTHOR>Dickens <B>Shelley</B> Keats</AUTHOR>
    

    <B>タグにより、AUTHOR MDATAセクションがクローズされます。その結果、このドキュメントには「Shelley」や「Keats」ではなく、「Dickens」というAUTHORが含まれます。

  • 競合状態を未然に防ぐため、ADD_MDATAおよびREMOVE_MDATAをそれぞれコールして、すべての値とセクションの索引のROWIDに対する他のコールをロックします。ただし、ADD_MDATAおよびREMOVE_MDATAはコミットを行わないため、両方をコールするとアプリケーションでデッドロックが発生する可能性があります。デッドロックを回避するのはアプリケーションの役割です。

関連項目:

11.1.2.5 NDATAセクション

NDATAセクションをBASIC_SECTION_GROUPHTML_SECTION_GROUPまたはXML_SECTION_GROUPセクション・グループ・タイプに追加して、名前検索用に索引付けするデータを含むフィールドを排他的に指定できます。

ユーザーは、使用可能な2つのデータストア(MULTI_COLUMN_DATASTOREまたはUSER_DATASTORE)を使用して、名前データを含むテキスト・ドキュメントを合成できます。次の例では、MULTI_COLUMN_DATASTOREを使用して、索引付け用の名前データが含まれている関連する列を取得しています。

create table people(firstname varchar2(80), surname varchar2(80));
 insert into people values('John', 'Smith');
 commit;
 begin
   ctx_ddl.create_preference('nameds', 'MULTI_COLUMN_DATASTORE');
   ctx_ddl.set_attribute('nameds', 'columns', 'firstname,surname');
 end;
 / 

この例では、索引付けに使用する次の仮想テキストを作成しています。

<FIRSTNAME>
John
</FIRSTNAME>
<SURNAME>
Smith
</SURNAME>

これで、FIRSTNAMEおよびSURNAMEセクションにNDATAセクションを作成できます。

begin
  ctx_ddl.create_section_group('namegroup', 'BASIC_SECTION_GROUP');
  ctx_ddl.add_ndata_section('namegroup', 'FIRSTNAME', 'FIRSTNAME');
  ctx_ddl.add_ndata_section('namegroup', 'SURNAME', 'SURNAME');
end;
/

次に、以前に作成したデータストア・プリファレンスとセクション・グループ・プリファレンスを使用して、索引を作成します。

create index peopleidx on people(firstname) indextype is ctxsys.context
parameters('section group namegroup datastore nameds');

NDATAセクションでは、シングルバイト・データとマルチバイト・データの両方がサポートされていますが、文字および語句に関する制約があります。索引付けされるNDATAセクション・データには、次の制約があります。

  • 1文字の空白で区切られた語句の文字数: 511

  • 空白で区切られた語句の数: 255

  • 空白を含めた文字の総数: 511

11.1.2.6 SDATAセクション

SDATAセクションの値は、他のセクションなどのドキュメント・テキストから抽出されますが、構造化データとして索引付けされ、SDATAとも呼ばれます。SDATAセクションは、投影、範囲検索、順序付けなどの操作をサポートしています。また、SDATAセクションでは、セクション・データ(埋込みタグなど)およびディテール表のSDATA索引付けやファンクション起動ができます。1つのSQL文でテキスト検索と構造化検索の様々な組合せを実行できます。

SDATA演算子は、SDATA以外の子孫もあるAND演算子の子としてのみ使用してください。SDATA演算子は、二次的な(確認または非駆動)基準として使用することが意図されています。たとえば、「評価が> 4のドキュメントの検索」ではなく、「DOGという語句が含まれており、価格が> 5でもあるドキュメントの検索」に使用します。

SDATAセクションをセクション・グループに追加するには、CTX_DDL.ADD_SDATA_SECTIONを使用します。既存のSDATAセクションの値を更新するには、CTX_DDL.UPDATE_SDATAを使用します。SDATAセクション内で問い合せる場合は、CONTAINS演算子を使用する必要があります。次の例では、itemsという表を作成し、my_sec_groupというSDATAセクションを追加して、セクション内のSDATAを問い合せます。

SDATAセクションの作成後に、CTX_DDL.SET_SECTION_ATTRIBUTEを使用すればSDATAセクションの属性をさらに変更できます。

items表を作成します。

CREATE TABLE items 
(id  NUMBER PRIMARY KEY, 
 doc VARCHAR2(4000));
 
INSERT INTO items VALUES (1, '<description> Honda Pilot </description>
                              <category> Cars & Trucks </category>
                              <price> 27000 </price>');
INSERT INTO items VALUES (2, '<description> Toyota Sequoia </description>
                              <category> Cars & Trucks </category>
                              <price> 35000 </price>');
INSERT INTO items VALUES (3, '<description> Toyota Land Cruiser </description>
                              <category> Cars & Trucks </category>
                              <price> 45000 </price>');
INSERT INTO items VALUES (4, '<description> Palm Pilot </description>
                              <category> Electronics </category>
                              <price> 5 </price>');
INSERT INTO items VALUES (5, '<description> Toyota Land Cruiser Grill </description>
                              <category> Parts & Accessories </category>
                              <price> 100 </price>');
COMMIT;

my_sec_group SDATAセクションを追加します。

BEGIN
  CTX_DDL.CREATE_SECTION_GROUP('my_sec_group', 'BASIC_SECTION_GROUP');
  CTX_DDL.ADD_SDATA_SECTION('my_sec_group', 'category', 'category', 'VARCHAR2');
  CTX_DDL.ADD_SDATA_SECTION('my_sec_group', 'price', 'price', 'NUMBER');
END;
 

CONTEXT索引を作成します。

CREATE INDEX items$doc 
  ON items(doc) 
  INDEXTYPE IS CTXSYS.CONTEXT
  PARAMETERS('SECTION GROUP my_sec_group');
 

問合せを実行します。

SELECT id, doc
  FROM items
  WHERE contains(doc, 'Toyota 
                       AND SDATA(category = ''Cars & Trucks'') 
                       AND SDATA(price <= 40000 )') > 0;

結果を返します。

  ID DOC
---- ----------------------------------------------------------------------
   2 <description> Toyota Sequoia </description>
                                   <category> Cars & Trucks </category>
                                   <price> 35000 </price>

ROWIDが1であるドキュメントについて考えてみます。この例では、price SDATAセクションの値を新しい値30000に更新しています。

BEGIN
    SELECT ROWID INTO rowid_to_update FROM items WHERE id=1;

    CTX_DDL.UPDATE_SDATA('items$doc', 
                         'price',
                         SYS.ANYDATA.CONVERTVARCHAR2('30000'),
                         rowid_to_update);
END;

この問合せを実行すると、Honda Pilotの価格が27000から30000に変更されます。

ノート:

  • SDATAセクションを既存の索引に追加することもできます。ALTER INDEX PARAMETERS文のADD SDATA SECTIONパラメータを使用します。詳細は、『Oracle Textリファレンス』のALTER INDEXセクションに関する項を参照してください。

  • SDATAセクションを追加する前に索引付けされたドキュメントには、この新しいプリファレンスは反映されません。この場合は索引を再構築してください。

関連項目:

  • SDATA演算子の詳細は、『Oracle Textリファレンス』CONTAINSの問合せに関する項を参照してください

  • SDATAセクションの追加および更新と、ADD_SDATA_SECTIONSET_SECTION_ATTRIBUTEおよびUPDATE_SDATAプロシージャを使用してその属性を変更する方法の詳細は、『Oracle Textリファレンス』CTX_DDLパッケージに関する項を参照

記憶域

optimized_for search SDATAセクションでは、CTX_DDL.SET_ATTRIBUTEを使用して、$Sdatatype表とこれらの表の索引の記憶域プリファレンスを指定できます。

デフォルトでは、ラージ・オブジェクト(LOB)キャッシュは$S*表に対してはオンになり、$S*索引に対してはオフになります。これらの属性はSDATAセクションでのみ有効です。

問合せ演算子

Optimized_for search SDATAでは、次の問合せ演算子がサポートされます。

  • =

  • <>

  • 範囲内

  • 範囲外

  • <=

  • <

  • >=

  • >

  • NULLである

  • NULLでない

  • 類似

  • 非類似

11.1.2.7 属性セクション

属性セクションを定義すると、XMLの属性テキストを問い合せることができます。また、システムで自動的にXML属性を定義し、索引付けすることもできます。

11.1.2.8 特殊セクション

特殊セクションは、タグで認識されるのではありません。現在、特殊セクションとしては文および段落のみがサポートされ、これらを使用すると、文または段落内でワードの組合せを検索できます。

文および段落の境界は、レクサーが判断します。たとえば、BASIC_LEXERは、文および段落のセクション境界を次のように認識します。

表11-3 BASIC_LEXERの文および段落セクション境界

特殊セクション 境界

SENTENCE

  • WORD/PUNCT/WHITESPACE

  • WORD/PUNCT/NEWLINE

PARAGRAPH

  • WORD/PUNCT/NEWLINE/WHITESPACE

  • WORD/PUNCT/NEWLINE/NEWLINE

レクサーが境界を認識できない場合、文または段落のセクションには索引が付けられません。

特殊セクションを追加するには、CTX_DDL.ADD_SPECIAL_SECTIONプロシージャを使用します。たとえば、次のコードではHTMLドキュメントの文内を検索できます。

begin
ctx_ddl.create_section_group('htmgroup', 'HTML_SECTION_GROUP');
ctx_ddl.add_special_section('htmgroup', 'SENTENCE');
end;

ゾーンおよび文の検索を有効にするには、ゾーン・セクションをグループに追加します。次の例では、Headlineゾーン・セクションをhtmgroupセクション・グループに追加しています。

begin
ctx_ddl.create_section_group('htmgroup', 'HTML_SECTION_GROUP');
ctx_ddl.add_special_section('htmgroup', 'SENTENCE');
ctx_ddl.add_zone_section('htmgroup', 'Headline', 'H1');
end;

11.1.3 Oracle Textセクション属性

セクション属性は、フィールド、ゾーン、ハイブリッド、SDATAなど、トークン化されたタイプのOracle Textセクションの設定です。セクション属性を使用すると、ドキュメント・レベルや索引レベルではなくセクション・レベルでより細かく制御することで、問合せパフォーマンスが向上します。

セクション属性を使用して、次のことを指定できます。

  • ドキュメントの特定のセクションに対するレクサー・プリファレンス。このプリファレンスは、部分名検索に便利です。ドキュメントで部分名を含む特定のセクションについては、ドキュメントの他の部分とは異なるレクサー処理が必要なためです。また、レクサー・プリファレンスは、言語マッピングへのセクションがある複数言語のドキュメントの処理にも使用できます。

  • ドキュメントの特定セクションでのみのサブストリング索引。この索引は、索引サイズの削減に効果があります。

  • ドキュメントの特定セクションでのみのプリフィックス・トークン。プリフィックス・トークンにより、前方一致問合せのパフォーマンスが向上しますが、索引サイズは短時間で大きくなります。プリフィックス・トークンを特定セクションのみに指定すれば、特定セクションでの後方一致問合せのパフォーマンスが向上する一方、索引サイズが短時間で増加することがなくなります。

  • ドキュメントの特定セクションのストップリスト。

  • ゾーン・セクションの柔軟性とフィールド・セクションのパフォーマンスをあわせ持つ新しいセクション・タイプ。現在、ゾーン・セクションはフィールド・セクションに比べるとパフォーマンスの点で劣ります。しかし、フィールド・セクションはネストしたセクション検索をサポートしていません。

セクション属性を設定するには、CTX_DDL.SET_SECTION_ATTRIBUTEプロシージャを使用します。

表11-4に、使用できるセクション属性を示します。

表11-4 セクション属性

セクション属性 説明

visible

visible属性は、ゾーン・セクション・タイプを除き、トークン化されたすべてのセクション・タイプに使用します。つまり、visible属性を使用できるのはフィールド、ハイブリッド、SDATAの各セクション・タイプです。

ドキュメントでテキストを参照可能にするとき、TRUEに指定します。フィールド・セクション内のテキストは、ドキュメント全体の一部として索引付けされます。

デフォルトはFALSEです。フィールド・セクション内のテキストは、ドキュメントの他の部分とは別に索引付けされます。

フィールド・セクション・タイプの場合、visible属性はCTX_DDL.ADD_FIELD_SECTIONプロシージャで指定された値より優先されます。

lexer

lexer属性は、トークン化されたすべてのセクション・タイプ(フィールド、ゾーン、ハイブリッドおよびSDATAセクション)で使用します。

SDATAセクションのトークン化を決定するレクサー・プリファレンス名を指定します。デフォルトはNULLで、メイン・ドキュメントのレクサーが使用されます。

レクサー・プリファレンスは、set_section_attributeプロシージャをコールするときに有効である必要があります。既存のフィールド・セクションがレクサー・プリファレンスを参照するときにプリファレンスのいずれかを削除しようとすると、drop_preferenceプロシージャが失敗します。

wordlist

wordlist属性は、トークン化されたすべてのセクション・タイプ(フィールド、ゾーン、ハイブリッドおよびSDATAセクション)で使用します。

セクション固有のプリフィックス索引付けとサブストリング索引付けを有効にするには、セクションのワードリスト・プリファレンス名を指定します。デフォルトはNULLで、メイン・ドキュメントのワードリストが使用されます。

ワードリスト・プリファレンスは、set_section_attributeプロシージャをコールするときに有効である必要があります。既存のフィールド・セクションがワードリスト・プリファレンスを参照するときにプリファレンスのいずれかを削除しようとすると、drop_preferenceプロシージャが失敗します。

stoplist

stoplist属性は、トークン化されたすべてのセクション・タイプ(フィールド、ゾーン、ハイブリッドおよびSDATAセクション)で使用します。

セクション固有のストップリストを有効にするには、ストップリスト・プリファレンス名を指定します。デフォルトはNULLで、メイン・ドキュメントのストップリストが使用されます。

ストップリスト・プリファレンスは、set_section_attributeプロシージャをコールするときに有効である必要があります。既存のフィールド・セクションがストップリスト・プリファレンスを参照するときにプリファレンスのいずれかを削除しようとすると、drop_preferenceプロシージャが失敗します。

次の例は、フィールド・セクションのvisible属性を有効にします。

begin
ctx_ddl.create_section_group(‘fieldgroup', ‘BASIC_SECTION_GROUP');
ctx_ddl.add_field_section(‘fieldgroup', ‘author', ‘AUTHOR');
ctx_ddl.set_section_attribute(‘fieldgroup', ‘author', ‘visible', ‘true');
end;

関連項目:

CTX_DDL.SET_SECTION_ATTRIBUTEプロシージャの構文は、『Oracle Textリファレンス』を参照してください。

11.2 Oracle Textを使用したHTMLのセクション検索

HTMLには、セクション検索に使用できるタグ付きテキスト形式の内部構造があります。たとえば、<H1>タグに対してheadingsというセクションを定義し、ドキュメント・セット全体でこれらのタグ内でのみ語句を検索します。

問合せには、WITHIN演算子を使用します。Oracle Textにより、headingsセクション内に問合せ語句を含むすべてのドキュメントを検出します。たとえば、headingsセクション内にワードoracleを含むすべてのドキュメントを検索する場合は、次の問合せを入力します。

'oracle within headings'

この項には、次の項目が含まれます。

11.2.1 HTMLのセクションの作成

次のコードは、HTML_SECTION_GROUP型のhtmgroupというセクション・グループを定義します。次に、htmgroupに、<H1>タグで識別するheadingというゾーン・セクションを作成します。

begin
ctx_ddl.create_section_group('htmgroup', 'HTML_SECTION_GROUP');
ctx_ddl.add_zone_section('htmgroup', 'heading', 'H1');
end;

ドキュメントを次のように索引付けできます。

create index myindex on docs(htmlfile) indextype is ctxsys.context
parameters('filter ctxsys.null_filter section group htmgroup');

htmgroupセクション・グループで索引付けした後、次の問合せを発行してheadingセクション内を問い合せることができます。

'Oracle WITHIN heading'

11.2.2 HTMLのMetaタグの検索

HTMLドキュメントの場合は、<META>タグのNAME/CONTENTのペアにセクションを作成できます。このとき、検索をCONTENT内のテキストに制限できます。

次のMETAタグを持つHTMLドキュメントがあるとします。

<META NAME="author" CONTENT="ken">

METAタグに対してすべてのCONTENT属性を索引付けるゾーン・セクションを作成します。この場合、METAタグのNAME値はauthorです。

begin
ctx_ddl.create_section_group('htmgroup', 'HTML_SECTION_GROUP');
ctx_ddl.add_zone_section('htmgroup', 'author', 'meta@author');
end

htmgroupセクション・グループで索引付けした後、次のようにドキュメントを問い合せることができます。

'ken WITHIN author'

11.3 Oracle Textを使用したXMLのセクション検索

HTMLドキュメントと同様、XMLドキュメントにもタグ付きテキストがあるため、これを使用して、セクション検索を行うテキストのブロックを定義できます。セクションの内容を検索するには、WITHIN演算子またはINPATH演算子を使用します。

次の各項では、様々なタイプのXML検索について説明します。

11.3.1 自動セクション

XMLドキュメントからセクションを自動的に作成するように索引付け操作を設定するには、AUTO_SECTION_GROUPセクション・グループを使用します。システムは、XMLタグに対してゾーン・セクションを作成します。属性セクションは、属性を持つタグに対して作成され、tag@attributeという形式でネーミングされます。

たとえば、次の文はAUTO_SECTION_GROUPを使用して、XMLファイルを含む列にmyindex索引を作成します。

CREATE INDEX myindex
ON xmldocs(xmlfile)
 INDEXTYPE IS ctxsys.context
PARAMETERS ('datastore ctxsys.default_datastore 
             filter ctxsys.null_filter 
             section group ctxsys.auto_section_group'
           );

11.3.2 属性検索

XML属性テキストは、次のいずれかの方法で検索できます。

  • 属性セクションの作成

    属性セクションを作成するにはCTX_DDL.ADD_ATTR_SECTIONを使用し、索引付けするにはXML_SECTION_GROUPを使用します。索引付けするときにAUTO_SECTION_GROUPを使用した場合は、属性セクションが自動的に作成されます。属性セクションは、WITHIN演算子で問い合せることができます。

    次のように、TITLE属性を持つBOOKタグを定義するXMLファイルがあるとします。

    <BOOK TITLE="Tale of Two Cities"> 
      It was the best of times. 
    </BOOK> 
    

    タイトル属性を属性セクションとして定義するには、次のようにXML_SECTION_GROUPを作成し、属性セクションを定義します。

    begin
    ctx_ddl.create_section_group('myxmlgroup', 'XML_SECTION_GROUP');
    ctx_ddl.add_attr_section('myxmlgroup', 'booktitle', 'book@title');
    end;
    

    索引付けするには:

    CREATE INDEX myindex
    ON xmldocs(xmlfile)
    INDEXTYPE IS ctxsys.context
    PARAMETERS ('datastore ctxsys.default_datastore 
                 filter ctxsys.null_filter 
                 section group myxmlgroup'
               );
    

    booktitle XML属性セクションを問い合せるには:

    'Cities within booktitle'
  • INPATH演算子による属性の検索

    PATH_SECTION_GROUPを使用して索引付けし、INPATH演算子で属性テキストを問い合せます。

関連項目:

パス・セクションの検索

11.3.3 ドキュメント・タイプ別のセクション

異なるドキュメント・タイプに対して宣言された<book>タグを持つXMLドキュメント・セットの場合、各ドキュメント・タイプに対して個別のbookセクションを作成すると、検索機能を改善できます。次の例では、各ドキュメント・タイプに対してbookセクションを作成する方法を示します。

mydocname1がXMLドキュメント・タイプ(ルート要素)として、次のように宣言されているとします。

<!DOCTYPE mydocname1 ... [...

mydocname1の中で、<book>要素が宣言されています。このタグに対し、タグのドキュメント・タイプを区別するmybooksec1という名前のセクションを次のように作成できます。

begin
ctx_ddl.create_section_group('myxmlgroup', 'XML_SECTION_GROUP');
ctx_ddl.add_zone_section('myxmlgroup', 'mybooksec1', 'mydocname1(book)');
end;

mydocname2が別のXMLドキュメント・タイプ(ルート要素)として、次のように宣言されているとします。

<!DOCTYPE mydocname2 ... [...

mydocname2の中で、<book>要素が宣言されています。このタグに対し、タグのドキュメント・タイプを区別するmybooksec2という名前のセクションを次のように作成できます。

begin
ctx_ddl.create_section_group('myxmlgroup', 'XML_SECTION_GROUP');
ctx_ddl.add_zone_section('myxmlgroup', 'mybooksec2', 'mydocname2(book)');
end;

mybooksec1セクション内で問合せを行うには、WITHINを次のように使用します。

'oracle within mybooksec1'

11.3.4 パス・セクション検索

XMLドキュメントには、次のような親子タグの構造を設定できます。

<A> <B> <C> dog </C> </B> </A>

この例のタグCは、タグAの子であるタグBの子です。

Oracle Textでは、PATH_SECTION_GROUPでパスを検索できます。このセクション・グループを使用すると、問合せ内に直接の親子関係を指定できます。たとえば、要素Bの子である要素Cにある語句dogを含むすべてのドキュメントを検索できます。

PATH_SECTION_GROUPを使用すると、属性値検索および属性の等価性のテストも実行できます。

この機能に関連する新しい演算子は、次のとおりです。

  • INPATH

  • HASPATH

この項では、次の項目について説明します。

11.3.4.1 PATH_SECTION_GROUPによる索引の作成

パス・セクション検索を使用可能にするには、PATH_SECTION_GROUPを使用してXMLドキュメント・セットを索引付けします。たとえば、次のようにします。

プリファレンスを作成します。

begin
ctx_ddl.create_section_group('xmlpathgroup', 'PATH_SECTION_GROUP');
end;

索引を作成します。

CREATE INDEX myindex
ON xmldocs(xmlfile)
INDEXTYPE IS ctxsys.context
PARAMETERS ('datastore ctxsys.default_datastore 
             filter ctxsys.null_filter 
             section group xmlpathgroup'
           );

索引を作成するときに、INPATH演算子とHASPATH演算子を使用できます。

11.3.4.2 トップレベルのタグ検索

トップレベルのタグ<A>に、語句dogが含まれているすべてのドキュメントを検索するには、次の問合せを行います。

dog INPATH (/A)

または

dog INPATH(A)
11.3.4.3 任意レベルのタグ検索

任意レベルの<A>タグに語句dogが含まれているすべてのドキュメントを検索するには、次の問合せを行います。

dog INPATH(//A)

この問合せは、次のドキュメントを検索します。

<A>dog</A>

および

<C><B><A>dog</A></B></C>
11.3.4.4 直接の親子関係の検索

トップレベルの要素Aの直接の子である要素Bに語句dogが含まれているすべてのドキュメントを検索するには、次の問合せを行います。

dog INPATH(A/B)

この問合せは、次のXMLドキュメントを検索します。

<A><B>My dog is friendly.</B></A>

ただし、次の語句は検索しません。

<C><B>My dog is friendly.</B></C>
11.3.4.5 タグ値のテスト

タグの値をテストできます。たとえば、次の問合せ

dog INPATH(A[B="dog"])

は、次のドキュメントを検索します。

<A><B>dog</B></A>

ただし、次のドキュメントは検索しません。

<A><B>My dog is friendly.</B></A>
11.3.4.6 属性検索

属性の内容を検索できます。たとえば、次の問合せ

dog INPATH(//A/@B)

次のドキュメントを検索します。

<C><A  B="snoop dog"> </A> </C>
11.3.4.7 属性値のテスト

属性の値をテストできます。たとえば、次の問合せ

California INPATH (//A[@B = "home address"])

次のドキュメントを検索します。

<A B="home address">San Francisco, California, USA</A>

ただし、次の語句は検索しません。

<A B="work address">San Francisco, California, USA</A>
11.3.4.8 パスのテスト

HASPATH演算子を使用して、パスの存在をテストできます。たとえば、次の問合せ

HASPATH(A/B/C)

は、次のドキュメントを検索して、スコア100を戻します。

<A><B><C>dog</C></B></A>

この問合せでは、dogは参照されません。

11.3.4.9 HASPATHによるセクションの等価性のテスト

HASPATH演算子を使用すると、セクションの等価性をテストできます。たとえば、次の問合せを考えてみます。

dog INPATH A

次のように検索されます。

<A>dog</A>

さらに、次のドキュメントも検索します。:

<A>dog park</A>

問合せを、語句dogのみに制限し、それ以外の語句を検索しないようにする場合は、HASPATH演算子によるセクションの等価性のテストを使用できます。たとえば、次のようになります

HASPATH(A="dog")

最初のドキュメントのみを検索し、スコア100を戻します。2番目のドキュメントは検索しません。

関連項目:

INPATHおよびHASPATH演算子の使用方法の詳細は、『Oracle Textリファレンス』を参照してください。