Volltextrecherche mit Application Express: Wartung und Pflege des Index

In der letzten Ausgabe haben Sie erfahren, wie Sie Dokumente in einer Tabelle per Volltextindex recherchierbar machen. Nach dem Erstellen ist der Volltextindex in Application Express mit einem einfachen SQL Bericht und der Funktion CONTAINS nutzbar (Abbildung 1).

Anwendungsseite zum Hochladen von Dateien

Abbildung 1: Oracle Text in Aktion

In diesem Tipp widmen wir uns der Pflege und Wartung des Volltextindex - im Vergleich zu einem "normalen" B-Baum-Index gibt es hier ein wenig mehr zu tun ...

Weitere Dokumente hochladen

Laden Sie in der im letzten Tipp erstellten Applikation einige weitere Dokumente hoch und stellen Sie anschließend erneut Suchanfragen. Mit den aktuellen Indexeinstellungen werden diese neuen Dokumente jedoch nicht in der Ergebnisliste erscheinen. Grund dafür ist die Vorgehensweise des Volltextindex mit neu eingefügten bzw. geänderten Dokumenten.

Ein Volltextindex hat im Vergleich zu einem B-Baum-Index eine völlig andere Struktur (invertierte Liste). Das Einpflegen von Änderungen in eine invertierte Liste ist wesentlich aufwändiger als in einen B-Baum-Index. Aus diesem Grund ist der Volltextindex asynchron: Änderungen werden nicht sofort im Index berücksichtigt, sondern erst durch eine explizite Synchronisierung; diese wird mit der PL/SQL-Prozedur CTX_DDL.SYNC_INDEX ausgelöst.

Nun wäre es denkbar, ein solches Kommando (per Trigger) nach jedem eingefügten oder geänderten Dokument automatisch auszulösen - der Index wäre dadurch stets auf aktuellem Stand. Jedoch würde der Index dann recht schnell fragmentiert (speziell bei häufigen Änderungen) - wodurch sich eine schlechte Abfrageperformance ergeben würde.

Besser ist es, wenn eine Synchronisierung nicht nur ein, sondern möglichst viele Dokumente auf einmal in den Volltextindex einpflegt. Andererseits sollen alle Dokumente sofort nach dem Hochladen durchsuchbar sein. Diesen Konflikt löst der Parameter TRANSACTIONAL des Volltextindex. Ist dieser gesetzt, werden auch die Dokumente, die noch nicht in den Index eingepflegt wurden, in Suchabfragen mit einbezogen. Natürlich ist die Suche in diesen Dokumenten aufwändiger - eine Synchronisierung sollte also trotzdem erfolgen.

Zunächst stellen wir den Index nun also auf das transaktionale Verhalten um - danach fügen wir der Anwendung eine Seite mit der Möglichkeit zur Indexsynchronisierung hinzu.

Index auf transaktionales Verhalten umstellen

Führen Sie mit dem SQL Workshop, SQL*Plus oder dem SQL Developer folgende Kommandos aus.

  • 1. Index synchronisieren
    begin
      ctx_ddl.sync_index(
        idx_name => 'IDX_DOKUMENT_VOLLTEXT'
      );
    end;
    
  • 2. Indexverhalten umstellen
    alter index idx_dokument_volltext 
    parameters ('replace metadata transactional')
    

Laden Sie nun erneut Dokumente hoch, synchronisieren Sie den Index nicht und suchen Sie nach den Dokumenten - von nun an werden sie in die Suche miteinbezogen.

Indexwartung in einer Application Express-Anwendung

Navigieren Sie nun nochmals zur Seite für das Hochladen von Dokumenten: Hier werden wir nun Regionen mit Informationen über den Index einbauen. Erzeugen Sie also eine neue Berichtsregion, die auf der Seite rechts (Spalte 2) dargestellt werden soll. Hinterlegen Sie für den Bericht folgendes SQL:

select
  idx_name,
  idx_table,
  idx_docid_count 
from ctx_user_indexes
where idx_name = 'IDX_DOKUMENT_VOLLTEXT'

Erzeugen Sie direkt anschließend eine weitere Region zur Darstellung von Informationen über die noch nicht synchronisierten Dokumente. Nutzen Sie dazu folgende SQL-Abfrage.

select 
 count(pnd_rowid) anzahl_pending,
 max(pnd_timestamp) last_uploaded,
 min(pnd_timestamp) first_uploaded
from ctx_user_pending 
where pnd_index_name='IDX_DOKUMENT_VOLLTEXT'

Das Ergebnis sollte in etwa wie in Abbildung 2 aussehen (Natürlich können Sie die Spaltenüberschriften und, die Formatmaskten und die Darstellung nach Belieben einrichten).

Anwendungsseite mit Informationen über den Index

Abbildung 2: Anwendungsseite mit Informationen über den Index

Fehlt nur noch die Möglichkeit, den Index per Klick zu synchronisieren. Erzeugen Sie also eine Schaltfläche und einen PL/SQL-Prozeß, der bei Klick auf die Schaltfläche ausgelöst werden soll, hinzu (onSubmit). Als Code für den PL/SQL-Prozeß verwenden Sie den bereits oben verwendeten Aufruf von CTX_DDL.SYNC_INDEX :

begin
  ctx_ddl.sync_index(
    idx_name => 'IDX_DOKUMENT_VOLLTEXT'
  );
end;

Achten Sie darauf, dass der Prozeß nur dann ausgeführt wird, wenn die Schaltfläche geklickt wurde (Abbildung 3).

Prozeß nur bei Klick auf die Schaltfläche ausführen

Abbildung 3: Prozeß nur bei Klick auf die Schaltfläche ausführen

Starten Sie die Seite anschließend neu und testen Sie die neue Schaltfläche - nach erfolgter Synchronisierung sollte die Seite dann wie in Abbildung 4 aussehen.

Der Index wurde synchronisiert

Abbildung 4: Der Index wurde synchronisiert

Natürlich lässt sich diese Synchronisierung auch als Job einrichten; dazu können Sie das PL/SQL-Paket DBMS_SCHEDULER nutzen; dieses wurde in einem früheren Community Tipp bereits vorgestellt. Wichtig ist dabei stets, dass eine Synchronisierung stets mehrere Dokumente umfasst; nur ein Dokument pro Synchronisierung wäre der ungünstigste Fall.

Index-Statistiken

Zum Abschluß dieses Community-Tipps sei nun noch vorgestellt, wie Sie Informationen über den Inhalt Ihres Volltextindex in Ihrer Anwendung darstellen können. Legen Sie dazu eine neue Seite in Ihrer Applikation an - nennen Sie die Seite Index-Statistik.

Fügen Sie dieser Seite dann eine neue Region vom Typ dynamischer PL/SQL Inhalt hinzu und hinterlegen Sie dort folgenden PL/SQL-Code:

declare
  v_idx_stats  clob;
  v_disp_chars pls_integer := 0;
  v_chunksize  pls_integer := 4000;
begin
  ctx_report.index_stats(
    index_name    => 'IDX_DOKUMENT_VOLLTEXT',
    report        => v_idx_stats,
    report_format => 'CLOB',
    frag_stats    => true
  );
  while v_disp_chars < dbms_lob.getlength(v_idx_stats) loop
   v_chunksize := least(4000,  dbms_lob.getlength(v_idx_stats) - v_disp_chars);
   htp.p(dbms_lob.substr(v_idx_stats, v_chunksize, v_disp_chars + 1));
   v_disp_chars := v_disp_chars + v_chunksize;
  end loop;
end; 

Damit der Index-Bericht richtig dargestellt wird, sind noch Angaben im Seiten Header ...

<pre style="font-family: monospace; height: 500px; width: 800px; overflow: scroll;">

... und im Seiten Footer ...

</pre>

erforderlich. Starten Sie die Seite anschließend - sie sollte wie in Abbildung 5 dargestellt aussehen.

Informationen über den Textindex

Abbildung 5: Informationen über den Textindex

In diesem Bericht finden Sie diverse Statistiken rund um Ihren Volltextindex; unter anderem (weiter unten) auch Informationen zur Index-Fragmentierung.

:
---------------------------------------------------------------------------
                         FRAGMENTATION STATISTICS
---------------------------------------------------------------------------

total size of $I data:                                  11,671 (11.40 KB)

$I rows:                                                            1,491
estimated $I rows if optimal:                                       1,491
estimated row fragmentation:                                          0 %

garbage docids:                                                         0
estimated garbage size:                                                 0
:

Speziell bei größeren Indizes nimmt die Abfrageperformance mit steigender Fragmentierung ab. Eine Index-Optimierung mit der PL/SQL-Prozedur CTX_DDL.OPTIMIZE_INDEX kann dann Abhilfe schaffen ...

begin
  ctx_ddl.optimize_index(
    idx_name => 'IDX_DOKUMENT_VOLLTEXT',
    optlevel => CTX_DDL.OPTLEVEL_FULL
  );
end;

... und analog zur Index-Synchronisierung lässt sich auch dieser Schritt per Schaltfläche aus der APEX-Applikation heraus starten.

Generell lässt sich sagen, dass die Index-Fragmentierung um so schneller ansteigt, je häufiger der Index mit wenig Dokumenten synchronisiert wird; eine Synchronisierung nach jedem Dokument würde die Fragmentierung am schnellsten ansteigen lassen.

Weitere Informationen zu Oracle TEXT

Zurück zur Community-Seite