Donnerstag, 5. Februar 2015

Schnellere TEXT-Abfragen mit SNIPPET in Oracle 12c: Forward Index / Save Copy

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.

Beliebte Postings