Wenn man in Dokumentbeständen sucht, ist es ja vielfach so, dass man zunächst
mit recht vielen Suchbegriffen anfängt und dann (wenn man nichts findet), die
Abfrage allgemeiner macht, eben bis etwas kommt ...
Für eine CONTAINS-Abfrage mit Oracle TEXT könnte das in etwa folgendes
bedeuten:
- 1. Abfrage (keine Treffer)
select * from dokument_tabelle where contains (dokument, 'oracle and datenbank and text and contains and parameters and 11g') > 0 /
- 2. Abfrage (bspw. 1 Treffer, passt aber nicht)
select * from dokument_tabelle where contains (dokument, 'oracle and datenbank and (text or contains)') > 0 /
- 3. Abfrage (ausreichend Treffer)
select * from dokument_tabelle where contains (dokument, 'oracle or datenbank') > 0 /
Das bedeutet nun allerdings, dass man drei Abfragen absetzt. Man kann nun darüber nachdenken, einen
solchen Prozeß zu automatisieren - wenn ein Suchwort in eine Maske eingegeben wird, wird zunächst
genau danach gesucht, wenn nicht genug Treffer gefunden werden, wird das Stemming ($-Operator)
verwendet und wenn es dann immer noch nicht reicht, probiert man es mit Fuzzy (?).
Es ist allerdings recht aufwändig, das selbst zu tun - man müsste jedesmal die Treffer zählen und
bei Bedarf eine neue Abfrage absetzen: Die Antwortzeiten wären damit sicherlich irgendwann nicht
mehr akzeptabel ...
Es gibt hierfür allerdings seit Oracle10g eine Funktion: Query Relaxation. Man kann
alle diese Abfragen auf einmal übergeben und auch festlegen, wieviele Treffer man gerne haben
möchte. Oracle TEXT erledigt dann alles mit nur einem CONTAINS-Aufruf.
select * from dokument_tabelle where contains ( dokument, '<query> <textquery lang="ENGLISH" grammar="CONTEXT"> <progression> <seq>{oracle} and {datenbank} and {text} and {contains} and {parameters} and {11g}</seq> <seq>{oracle} and {datenbank} and ({text} or {contains})</seq> <seq>{oracle} or {datenbank}</seq> </progression> </textquery> <score datatype="INTEGER" algorithm="DEFAULT"/> </query>' )>0 and rownum <= 10;
Die CONTAINS-Abfrage wird im XML-Format übergeben; die sog. Query Templates
werden hier verwendet (mehr Informationen). Man sieht sehr schön, dass die Abfragen der Reihe nach aufgeführt werden.
Oracle TEXT führt alle Abfragen der Reihe nach aus, bis entweder das Ende erreicht ist
(letztes seq-Tag oder bis die gewünschte Zahl der Treffer gefunden wurde. Die gewünschte
Anzahl Treffer steckt in der zusätzlichen Bedingung and rownum <= 10.
Da nun alle Abfragen in ein und demselben CONTAINS Aufruf stecken, ist diese Variante
wesentlich schneller und effizienter als das manuelle "Nacheinander-Aufrufen" von CONTAINS-Abfragen.
Die Funktionalität zum Zugriff auf den Index wird eben nur einmal anstatt mehrmals aufgerufen;
alle evtl. Initialisierungen finden nur einmal statt.
Das im Text oben beschriebene Beispiel (zuerst "normal", dann mit Stemming, danach Fuzzy) würde
als Aufruf dann so aussehen ...
select * from dokument_tabelle where contains ( dokument, '<query> <textquery lang="GERMAN" grammar="CONTEXT"> <progression> <seq>{[suchwort]}</seq> <seq>{$[suchwort]}</seq> <seq>{FUZZY([suchwort], 75, 100, weight)}</seq> <seq>{FUZZY([suchwort], 60, 200, weight)}</seq> <seq>{FUZZY([suchwort], 40, 300, weight)}</seq> </progression> </textquery> <score datatype="INTEGER" algorithm="DEFAULT"/> </query>' )>0 where rownum < 10;
Hier habe ich mal den Operator FUZZY anstelle des einfachen Fragezeichens (?) verwendet - der Unterschied ist, dass FUZZY parametrisiert werden kann. Mehr Informationen zur Syntax des FUZZY-Operators finden sich in der Oracle Dokumentation: TEXT Reference.