Volltextrecherche mit Application Express: Erste Schritte

Auch wenn es nicht gerade ein Dokumentenarchiv von mehreren Hundertausend Dokumenten geht - die Anforderung nach Volltextsuche in einem mehr oder weniger großen Text- oder Dokumentbestand tritt recht häufig auf. Mit Application Express und der Oracle-Datenbank lässt sich dies auch leicht umsetzen - denn es gibt Oracle TEXT. Lesen Sie heute, wie Sie die den in die Datenbank eingebaute Volltextindex für Ihre Anwendungen nutzen können.

Vorbereitungen

Damit Sie mit Oracle TEXT arbeiten können, muss das Parsing Schema Ihrer Application Express-Anwendung die Rolle CTXAPP und das EXECUTE-Privileg am PL/SQL-Paket CTX_DDL besitzen - Gegebenenfalls muss der Datenbankadministrator Ihnen diese Privilegien einräumen.

Zunächst benötigen Sie eine Tabelle, welche die Dokumente aufnehmen kann. Es sollen alle möglichen Dokumente gespeichert werden können, neben reinem ASCII-Text also auch PDF-Dokumente, Microsoft Word-Dateien und andere (Das Microsoft Office2007-Format wird zur Zeit nur von der Version 11.1.0.7 unterstützt; das ist das erste Patchset von Oracle11g). Erzeugen Sie also eine Tabelle DOKUMENT_TAB mit folgenden SQL-Kommandos (sie können natürlich auch die Assistenten im SQL Workshop nutzen):

create table dokument_tab(
  id       number(10),
  dokument blob,
  mimetype varchar2(200),
  erstellt date,
  constraint pk_dokumenttab primary key (id)
)
/

create sequence seq_dokument
/

create or replace trigger tr_id_dokumenttab
before insert on dokument_tab
for each row
begin
  select seq_dokument.nextval into :new.id from dual;
  :new.erstellt := sysdate;
end;
/

Erstellen Sie nun eine APEX-Anwendung mit einer Seite zum Hochladen der Dokumente. Erzeugen Sie also ein Formular mit mindestens einem Eingabefeld zum Hochladen von Dateien ( P1_DATEI) und einer Schaltfläche zum Absenden. Das sollte dann in etwa wie in Abbildung 1 aussehen.

Anwendungsseite zum Hochladen von Dateien

Abbildung 1: Anwendungsseite zum Hochladen von Dateien

Hinterlegen Sie dann folgenden PL/SQL-Prozeß (onSubmit) zum tatsächlichen Abspeichern der Dokumente in Ihrer Tabelle:

declare
  v_dokument dokument_tab.dokument%TYPE;
  v_mimetype dokument_tab.mimetype%TYPE;
begin
  select blob_content, mime_type 
   into  v_dokument, v_mimetype
  from wwv_flow_files
  where name = :P1_DATEI;

  insert into dokument_tab (dokument, mimetype)
  values (v_dokument, v_mimetype);

  delete from wwv_flow_files where name = :P1_DATEI;
exception
  when NO_DATA_FOUND then null;
  when TOO_MANY_ROWS then null;
end;

Nun können Sie einige Dokumente in Ihre Tabelle hochladen; im nächsten Schritt werden Sie dann einen Volltextindex erstellen und so die Dokumente durchsuchen können

Indexerstellung

Prinzipiell könnten Sie den Textindex nun mit dem SQL Workshop erstellen; wenn Sie im Objektbrowser auf Erstellen und dann auf Index klicken, können Sie zwischen der Erstellung eines "normalen" und eines Textindex wählen (Abbildung 2).

Indexerstellung im SQL Workshop: Normal oder Text?

Abbildung 2: Indexerstellung im SQL Workshop: Normal oder Text?

Verwenden Sie diese Variante hier nicht. Stattdessen erstellen wir den Index mit einem SQL-Kommando - der Assistent im SQL Workshop bietet nicht die Möglichkeit, auch PDF-, Office oder andere Binärdokumente zu indizieren; dazu muss ein Parameter gesetzt werden.

Erstellen Sie den Index also in SQL*Plus, im SQL Developer oder im SQL Workshop unter SQL Skripte mit folgenden Kommandos:

begin
  ctx_ddl.drop_preference(
    preference_name => 'MY_LEXER'
  );
end;
/

begin
  ctx_ddl.create_preference(
    preference_name => 'MY_LEXER',
    object_name => 'BASIC_LEXER'
  );
  ctx_ddl.set_attribute(
    preference_name => 'MY_LEXER',
    attribute_name => 'MIXED_CASE',
    attribute_value => 'NO'
  );
end;
/

create index idx_dokument_volltext
on dokument_tab (dokument)
indextype is ctxsys.context
parameters ('FILTER CTXSYS.AUTO_FILTER LEXER MY_LEXER')
/

Die ersten Kommandos erstellen eine sog. Lexer Preference; in dieser legen Sie fest, dass der Index "Case-insensitiv" sein soll (Groß- und Kleinschreibung interessiert für die Suche nicht). Das letzte Kommando erstellt den Index unter Verwendung eben dieser Lexer Preference - zusätzlich wird festgelegt, dass Binärdokumente durch den AUTO_FILTER gefiltert und damit durchsuchbar gemacht werden sollen.

Je nach Anzahl der hochgeladenen Dokumente kann dies ein wenig Zeit in Anspruch nehmen.

Index nutzen - Volltextrecherche

Nun geht es daran, den erstellten Index auch zu nutzen. Navigieren Sie dazu zur zweiten Seite Ihrer Anwendung oder erstellen Sie diese. Erzeugen Sie eine HTML-Region mit einem Texteingabefeld (P2_SUCHE) und einer Schaltfläche zum Absenden. Diese Seite sollte in etwa wie in Abbildung 3 aussehen:

Anwendungsseite zur Recherche: Texteingabefeld zum Suchen

Abbildung 3: Anwendungsseite zur Recherche: Texteingabefeld zum Suchen

Achten Sie darauf, dass nach Klick auf die Schaltfläche zur gleichen Seite (hier: 2) verzweigt wird; legen Sie die Verzweigung gegebenenfalls an.

Die Volltextrecherche erfolgt bei Oracle TEXT mit einer SQL-Abfrage und der Funktion CONTAINS. Insofern können Sie die Trefferliste in Application Express recht einfach als SQL-Bericht erstellen. Erzeugen Sie unterhalb der HTML-Region mit dem Texteingabefeld also einen SQL-Bericht und verwenden Sie dabei folgende Abfrage:

select 
  id,
  ctx_doc.snippet('IDX_DOKUMENT_VOLLTEXT'rowid:P2_SUCHE) snippet,
  score(0) as score
from dokument_tab
where contains(dokument, :P2_SUCHE0) > 0
order by 3 desc

Hervorhebenswert ist die Funktion CTX_DOC.SNIPPET. Sie ermittelt aus den Dokumenten der Trefferliste das sog. Keyword In Context, also den Suchbegriff und die Abschnitte (Snippets) jeweils davor und danach - man bekommt damit eine Ausgabe wie man es von gängigen Suchmaschinen gewohnt ist. Bevor Sie die Seite nun starten und testen, hinterlegen Sie noch einen onLoad-Prozeß (beim Laden) mit folgendem PL/SQL-Code

begin
  ctx_doc.set_key_type('ROWID');
end;

Starten Sie die Seite nun neu, geben Sie einen Suchbegriff ein und klicken Sie auf die Schaltfläche Go. Das Ergebnis sollte dann wie in Abbildung 4 aussehen (natürlich können Sie die Spaltenüberschriften und -ausrichtungen nach Belieben einstellen).

Trefferliste

Abbildung 4: Trefferliste

Die Darstellung der Snippets kann konfiguriert werden. Um die Suchbegriffe rot zu markieren, ändern Sie die SQL-Abfrage des Berichts als Beispiel wie folgt um:

select 
  id,
  ctx_doc.snippet('IDX_DOKUMENT_VOLLTEXT'rowid:P2_SUCHE'<b style="color: red">','</b>') snippet,
  score(0) as score
from dokument_tab
where contains(dokument, :P2_SUCHE0) > 0
order by 3 desc

Wie der Suchbegriff innerhalb des Keyword in Context hervorgehoben werden soll, wird ebenfalls in der Funktion SNIPPET angegeben. Verwenden Sie hier normale HTML-Tags. Es können natürlich auch CSS-Klassen verwendet werden: <span class="..."> und </span>.

Natürlich lässt sich nun mit einfachen Mitteln ein Download-Link für das gefundene Dokument einbauen. Dies soll hier allerdings nicht im Detail erläutert werden, da es dazu einen eigenen Community-Tipp gibt.

Erweiterte Möglichkeiten

Die Möglichkeiten von Oracle TEXT gehen weit über eine einfache Begriffssuche hinaus: Die folgende Liste zeigt einige Beispiele für die Möglichkeiten, die Sie bei der Formulierung Ihrer Abfrage haben, auf. Eine vollständige Aufzählung finden Sie in der Dokumentation zu Oracle TEXT.

  • Ähnlichkeitssuche (Fuzzy-Suche): ?{suchbegriff}
    Die Ähnlichkeitssuche eignet sich gut zum Auffinden auch falsch geschriebener Begriffe

    Abbildung 5: Die Ähnlichkeitssuche eignet sich gut zum Auffinden auch falsch geschriebener Begriffe

    Anstelle des Fragezeichens (?) kann auch das Schlüsselwort FUZZY verwendet werden; dann lassen sich die Ähnlichkeitskriterien auch parametrisieren (mehr dazu in der Dokumentation.

  • Wortstammsuche (Stemming): ${suchbegriff}
    Mit der Wortstammsuche findet man alle Dokumente mit Begriffen des gleichen Wortstamms

    Abbildung 6: Mit der Wortstammsuche findet man alle Dokumente mit Begriffen des gleichen Wortstamms

  • Suche nach "naheliegenden" Begriffen: NEAR({begriff}, {begriff}), {Anzahl Zwischenwörter})
    Der NEAR-Operator findet Dokumente, in denen die Begriffe nahe beieinder liegen

    Abbildung 7: Der NEAR-Operator findet Dokumente, in denen die Begriffe nahe beieinder liegen

    Mit dem NEAR-Operator findet man Dokumente, in denen die Suchbegriffe nahe beieinander liegen; neben den Begriffen kann auch die Anzahl der Wörter, die sich maximal zwischen den Begriffen befinden dürfen, übergeben werden.

Synchronisierung des Textindex

Wenn Sie nach Erstellung des Textindex weitere Dokumente hochladen, werden Sie eine Besonderheit bemerken - ohne weiteres werden diese bei Suchabfragen nicht gefunden. Der Volltextindex arbeitet asynchron - neue Dokumente werden nicht sofort in den Index eingepflegt.

Die Gründe für dieses Verhalten liegen im besonderen Aufbau des Index und den Anforderungen sehr großer Dokumentarchive. Wir werden in einer der nächsten Ausgaben tiefer auf dieses Thema eingehen - und auch darauf, wie Sie sicherstellen können, dass stets alle Dokumente in die Abfrage einbezogen werden.

Bis dahin sei das Kommando zum Synchronisieren des Index schonmal verraten - so bringen Sie den Index nach dem Hochladen weiterer Dokumente wieder auf den aktuellen Stand:

begin
  ctx_ddl.sync_index('IDX_DOKUMENT_VOLLTEXT');
end;
/

Dieses Kommando können Sie im SQL Workshop, in SQL*Plus oder von einem anderen Werkzeug aus ausführen. Am sinnvollsten ist es, der Anwendung eine Administrationsseite hinzuzufügen - aber dazu mehr in einer der nächsten Ausgaben.

Weitere Informationen zu Oracle TEXT

Zurück zur Community-Seite