Wie die meisten wissen, ist Oracle TEXT in der Lage, XML-Dokumente (oder besser: "getaggte Dokumente")
zu durchsuchen. Und wie Oracle TEXT mit solchen Dokumenten umgeht, kann sehr stark beeinflusst werden. Heute
geht es also um das Section Searching und einige Grundlagen, die man dazu wissen sollte ...
Angenommen, wir haben eine Tabelle mit folgenden Inhalten.
create table xml_text( id number, doc xmltype ) / insert into xml_text values (1, '<KUNDE><NAME>Czarski</NAME><VORNAME>Carsten</VORNAME></KUNDE>') / insert into xml_text values (2, '<KUNDE><NAME>Schwinn</NAME><VORNAME>Ulrike</VORNAME></KUNDE>') / insert into xml_text values (3, '<KUNDE><NAME>Mustermann</NAME><VORNAME>Max</VORNAME></KUNDE>') /
... dann legt man den Textindex darauf bspw. so an (das ist am einfachsten).
create index ft_xmltext on xml_text (doc) indextype is ctxsys.context parameters ('section group ctxsys.auto_section_group');
Danach kann man suchen ...
SQL> select id from xml_text where contains(doc, 'Carsten within (VORNAME)') > 0; ID ---------- 1 1 Zeile wurde ausgewählt. SQL> select id from xml_text where contains(doc, 'Carsten within (NAME)') > 0; Es wurden keine Zeilen ausgewählt
So weit so gut - schauen wir mal in den Index hinein (genauer gesagt: in die Token-Tabelle):
SQL> select token_text, token_type from dr$ft_xmltext$i TOKEN_TEXT TOKEN_TYPE -------------------- ---------- CARSTEN 0 CZARSKI 0 KUNDE 2 MAX 0 MUSTERMANN 0 NAME 2 SCHWINN 0 ULRIKE 0 VORNAME 2
Man sieht, dass die XML-Tags mit im Index stehen - sie haben den Token Type 2. Das bedeutet
aber, dass der Index bei großen Tabellen eine ganze Menge Tags mitindiziert. Und vor allem indiziert er alle
Tags - manche braucht man eigentlich gar nicht: in unserem Fall hier ist das Tag KUNDE völlig überflüssig.
Grundsätzlich bietet Oracle Text verschiedene Varianten (Section Group Types) für die
Abschnittssuche an. Die Dokumentation enthält eine Übersicht. Für XML-Dokumente kommt es nun darauf an,
wie man suchen möchte.
- Möchte man eine Pfadsuche machen, also in XML-Manier (/KUNDE/VORNAME) in den Dokumenten suchen, so muss man die PATH_SECTION_GROUP verwenden. In CONTAINS kann dann mit den Abfrageoperatoren INPATH und HASPATH gearbeitet werden. Dies ist von der Indizierung her die aufwändigste Variante - der Index wird am größten. Auf der anderen Seite hat man mit INPATH und HASPATH die mächtigsten Abfragemöglichkeiten. Man sollte diese Variante aber auch nur dann wählen, wenn diese Möglichkeiten tatsächlich gebraucht werden.
- XML_SECTION_GROUP und AUTO_SECTION_GROUP erlauben die einfache Section-Suche mit WITHIN. Während die AUTO_SECTION_GROUP bis auf explizit ausgeschlossene XML-Tags alle indiziert, müssen zu indizierende Tags bei der XML_SECTION_GROUP manuell angegeben werden. Das bedeutet aber auch mehr Kontrolle.
Also könnte man mit der XML_SECTION_GROUP arbeiten und nur die Tags NAME und VORNAME
indizieren - damit würde das Tag KUNDE aus dem Index rausfallen - brauchen wir ohnehin nicht.
begin ctx_ddl.create_section_group('kunde_section_group', 'XML_SECTION_GROUP'); ctx_ddl.add_zone_section('kunde_section_group', 'NAME', 'NAME'); ctx_ddl.add_zone_section('kunde_section_group', 'VORNAME', 'VORNAME'); end; / create index ft_xmltext on xml_text (doc) indextype is ctxsys.context parameters ('section group kunde_section_group');
Die Suche funktioniert genauso wie vorhin - die Token-Tabelle ist leicht verändert.
SQL> select token_text, token_type from dr$ft_xmltext$i; TOKEN_TEXT TOKEN_TYPE -------------------- ---------- CARSTEN 0 CZARSKI 0 MAX 0 MUSTERMANN 0 NAME 2 SCHWINN 0 ULRIKE 0 VORNAME 2
Das Token KUNDE ist weg. Jetzt haben wir allerdings die Tags NAME und VORNAME
als Zone Sections indiziert. Zone Sections sind hier erklärt. Wie XML-Tags können Sie mehrfach im
Dokument vorkommen und verschachtelt sein. Bei XML-Tags wird das ja durchaus gebraucht.
In unserem Falle aber nicht! Beide kommen nur einmal vor und enthalten nur noch Text.
Wenn man weiss, dass die Tags nur noch Text enthalten (also nicht mehr verschachtelt sind) und
nur einmal im Dokument vorkommen, so kann man auch Field Sections (Dokumentation) verwenden.
begin ctx_ddl.create_section_group('kunde_section_group', 'XML_SECTION_GROUP'); ctx_ddl.add_field_section('kunde_section_group', 'NAME', 'NAME', false); ctx_ddl.add_field_section('kunde_section_group', 'VORNAME', 'VORNAME', false); end; /
Der Index ist nun noch kompakter ...
SQL> select token_text, token_type from dr$ft_xmltext$i; TOKEN_TEXT TOKEN_TYPE -------------------- ---------- CARSTEN 17 CZARSKI 16 MAX 17 MUSTERMANN 16 SCHWINN 16 ULRIKE 17
Die Suche funktioniert wieder wie vorhin ... mit einer Ausnahme ...
SQL> select id from xml_text where contains(doc, 'Carsten') > 0; Es wurden keine Zeilen ausgewählt
Eine Field Section ist im Rest des Dokumentes nicht sichtbar. Für die Vornamen und Namen
kann man in diesem Falle nur noch Section-Suche machen. Wenn man möchte, dass die
globale Dokumentsuche trotzdem funktioniert, muss man den letzten Parameter beim
Aufruf von ADD_FIELD_SECTION auf true setzen.
begin ctx_ddl.create_section_group('kunde_section_group', 'XML_SECTION_GROUP'); ctx_ddl.add_field_section('kunde_section_group', 'NAME', 'NAME', true); ctx_ddl.add_field_section('kunde_section_group', 'VORNAME', 'VORNAME', true); end; /
Aber Achtung: Die Tokens werden dann
doppelt indiziert ...
SQL> select token_text, token_type from dr$ft_xmltext$i; TOKEN_TEXT TOKEN_TYPE -------------------- ---------- CARSTEN 0 CARSTEN 17 CZARSKI 0 CZARSKI 16 MAX 0 MAX 17 MUSTERMANN 0 MUSTERMANN 16 SCHWINN 0 : :
Man sieht, dass man bei der Section-Suche eine ganze Menge Möglichkeiten hat, das Verhalten
des Index zu beeinflussen. Und gerade bei großen Dokumentbeständen und Indizes kommt es
auf die Indexgröße an - ein kleinerer Textindex kann noch in den Hauptspeicher passen und
für performantere Abfragen sorgen ... Bei Bedarf empfiehlt es sich, auf diese Aspekte besonders
Acht zu geben ...
Übrigens ist das Geschriebene auch bei Verwendung eines USER_DATASTORE oder eines MULTICOLUMN_DATASTORE relevant - in beiden Fällen werden die Informationen als XML-Dokumente aufbereitet und an den Index übergeben.