Das Indizieren binärer Dokumente, wie PDF- oder Office-Formate, ist mit Oracle TEXT bekanntlich
überhaupt kein Problem. Einfach in den Index-Parametern den "FILTER" aktivieren und los geht's.
create index idx_ppt_folien on ppt_folien(FOLIENSATZ) indextype is ctxsys.context parameters('filter ctxsys.auto_filter');
Und danach kann man auch schon abfragen ...
select dateiname from ppt_folien where contains (FOLIENSATZ, '"Oracle TEXT"') > 0; DATEINAME -------------------------------------------------------------------------------- XMLDB_US.ppt 11gDWHFeatures_us.ppt 11g_dwh_us.ppt TextMining_11g_200912_ccz.ppt SecureFiles_odd_201002_us_cc.ppt OracleText-ccz-201410.pptx 01_BigDataWorkshop_BigData_Overview_032012_ccz.pptx : 38 Zeilen ausgewählt. Abgelaufen: 00:00:00.99
Achtet auf die Ausführungszeit - die ist hier völlig OK. Nun reicht
der Dateiname zur Anzeige natürlich nicht aus; man hätte schon gerne
den Textausschnitt, in dem das Suchwort gefunden wurde - auch das ist
für Oracle TEXT kein Problem - dazu gibt es die Funktion CTX_DOC.SNIPPET; die neue Query sieht
also so aus.
select dateiname, ctx_doc.snippet('IDX_PPT_FOLIEN',rowid,'"Oracle TEXT"','**','**') as snippet from ppt_folien where contains (FOLIENSATZ, '"Oracle TEXT"') > 0; DATEINAME SNIPPET ------------------------------ -------------------------------------------------------------------- XMLDB_US.ppt **Oracle TEXT**-Index (Alle Speicherungsformen) ¦ Volltextrecherche 11gDWHFeatures_us.ppt Funktionstests mit neuen **Oracle Text** Indizes (CDI) TextMining_11g_200912_ccz.ppt in einer Tabelle abgelegt ¦ **Oracle TEXT**-Abfragesyntax : 38 Zeilen ausgewählt. Abgelaufen: 00:00:16.10
Das funktioniert sehr gut, aber die Performance lässt doch sehr zu wünschen übrig; es
sind nun 16 Sekunden (!) - vorher war es eine. Der Grund ist schnell gefunden: um das
Snippet generieren zu können, muss Oracle TEXT das Binärdokument nochmals abrufen,
nochmals filtern und dann die Snippets berechnen. Dabei geht viel Zeit verloren. Bislang wurde spätestens an
dieser Stelle empfohlen, die Dokumente einfach in gefilterter Form in eine eigene
Tabelle abzulegen und diese dann zu indizieren.
Ab Oracle 12.1
bietet Oracle TEXT ein Feature an, welches uns die Arbeit dafür abnimmt: Der Forward Index und
das Save Copy-Feature.
Das Speichern des gefilterten Textes übernimmt dann Oracle TEXT für uns; die Verwaltung der
eigenen Tabelle müssen wir nicht mehr selbst übernehmen. Zusätzlich speichert
Oracle TEXT im Forward Index weitere Informationen über die konkreten
Wortpositionen, was das Berechnen der Snippets nochmal beschleunigt. Und das ganze geht so.
- 1. Neue Storage Preference erzeugen und die Attribute SAVE_COPY und FORWARD_INDEX setzen:
begin ctx_ddl.create_preference('MY_STORAGE','BASIC_STORAGE'); ctx_ddl.set_attribute('MY_STORAGE','forward_index', 'TRUE'); ctx_ddl.set_attribute('MY_STORAGE','save_copy', 'PLAINTEXT'); ctx_ddl.set_attribute('MY_STORAGE','save_copy_max_size', '0'); end;
Wenn bereits eine Storage Preference existiert, nimmt man natürlich diese. Das Attribut SAVE_COPY wird entweder mit dem Wert NONE, PLAINTEXT oder HTML versehen. PLAINTEXT reicht für das Erzeugen der Snippets aus; möchte man auch HTML-Vorschauversionen bereitstellen (Preview-Funktion), so sollte man HTML wählen. Das Attribut SAVE_COPY_MAX_SIZE legt eine Obergrenze für die Größe des gefilterten Dokumentes fest. - 2. Index neu erstellen - mit der neuen Storage Preference
drop index idx_ppt_folien; Index wurde gelöscht. create index idx_ppt_folien on ppt_folien(FOLIENSATZ) indextype is ctxsys.context parameters('filter ctxsys.auto_filter storage MY_STORAGE'); Index wurde erstellt.
Und fertig. Setzt man die Abfrage mit dem Snippet nochmal ab, so merkt man, dass diese
nun wesentlich schneller ist ...
select dateiname, ctx_doc.snippet('IDX_PPT_FOLIEN',rowid,'"Oracle TEXT"','**','**') as snippet from ppt_folien where contains (FOLIENSATZ, '"Oracle TEXT"') > 0; DATEINAME SNIPPET ------------------------------ -------------------------------------------------------------------- XMLDB_US.ppt **Oracle TEXT**-Index (Alle Speicherungsformen) ¦ Volltextrecherche 11gDWHFeatures_us.ppt Funktionstests mit neuen **Oracle Text** Indizes (CDI) TextMining_11g_200912_ccz.ppt in einer Tabelle abgelegt ¦ **Oracle TEXT**-Abfragesyntax : 38 Zeilen ausgewählt. Abgelaufen: 00:00:00.95
Auf der anderen Seite verbraucht das Speichern des Snippets natürlich Platz - allerdings hält
dieser sich, wie man hier sehen kann, in Grenzen. Die Tabelle, welche die Plaintext-Versionen
enthält, ist die $D-Tabelle (hier rot markiert); der Forward Index ist in der $O-Tabelle
abgelegt (blau markiert). Die verschiedenen Tabellentypen sind hier beschrieben. Es werden (in
diesem Fall) etwa 8MB zusätzlich verbraucht - die indizierten PPT-Dokumente sind etwa 750MB.
Natürlich hängt dieses
Verhältnis stark von den indizierten Dokumenten ab - Folien enthalten viele Bilder und
wenig Text; bei anderen Dokumenttypen ist das anders. Generell ist das neue "Forward Index / Save Copy" Feature
jedoch eine gute Variante, um die Performance von "Snippet-Queries" zu verbessern.
select t.table_name, s.segment_name, sum(s.bytes) from user_tables t, user_lobs l, user_segments s where l.table_name = t.table_name and ( l.segment_name = s.segment_name or t.table_name = s.segment_name) and (t.table_name like 'DR$IDX_PPT_FOLIEN$%' or t.table_name = 'PPT_FOLIEN') group by t.table_name, s.segment_name order by 1 TABLE_NAME SEGMENT_NAME SUM(S.BYTES) ------------------------- ------------------------- -------------- DR$IDX_PPT_FOLIEN$D SYS_LOB0000135517C00003$$ 6.488.064 DR$IDX_PPT_FOLIEN$D SYS_LOB0000135517C00002$$ 131.072 DR$IDX_PPT_FOLIEN$D DR$IDX_PPT_FOLIEN$D 131.072 DR$IDX_PPT_FOLIEN$I SYS_LOB0000135503C00006$$ 1.245.184 DR$IDX_PPT_FOLIEN$I DR$IDX_PPT_FOLIEN$I 3.145.728 DR$IDX_PPT_FOLIEN$O SYS_LOB0000135514C00007$$ 1.245.184 DR$IDX_PPT_FOLIEN$O DR$IDX_PPT_FOLIEN$O 524.288 DR$IDX_PPT_FOLIEN$R DR$IDX_PPT_FOLIEN$R 65.536 DR$IDX_PPT_FOLIEN$R SYS_LOB0000135508C00002$$ 131.072 PPT_FOLIEN PPT_FOLIEN 131.072 PPT_FOLIEN SYS_LOB0000135467C00003$$ 785.580.032 9 Zeilen ausgewählt.
Viel Spaß damit.