Posts mit dem Label weight werden angezeigt. Alle Posts anzeigen
Posts mit dem Label weight werden angezeigt. Alle Posts anzeigen

Freitag, 20. August 2010

Anwendungsbeispiel für MULTI_COLUMN_DATASTORE, MDATA und Operatoren ACCUM und WEIGHT

Ist es möglich Dokumenten unterschiedlichen Formats (Dateityps) eine unterschiedliche Gewichtung zu geben? Beispielsweise ist die Vorgabe, dass Dokumente im Format PDF eine höhere Gewichtung erhalten sollen als Dokumente im Format HTML. Mit MULTI_COLUMN_DATASTORE, MDATA und den unterschiedlichen Operatoren wie ACCUM und WEIGHT kann dies möglich gemacht werden. Mehr Informationen zur MDATA-Nutzung und Multicolumn-Datastore finden Sie übrigens im Metadatensuche mit MDATA und im MData Section und MULTI_COLUMN_DATASTORE Blog.
Nehmen wir im folgenden Beispiel die Tabelle DOCUMENTS mit Spalten INHALT und DATEI_TYP.

CREATE TABLE documents
(id NUMBER, datei_typ VARCHAR2(10), INHALT blob);

Danach füllen wir die Tabelle mit unterschiedlichen Inhalten. Wir verwenden eine LOBLOAD-Prozedur, die die Spalteninhalte als Parameter übergibt. Der Dateiname gibt dabei Auskunft über den Inhalt und das Format.

execute lobload(1,'html','inhalt1.html')
execute lobload(2, 'html','inhalt2.html');
execute lobload(3,'PDF','inhalt1.PDF');
execute lobload(4,'PDF','inhalt2.PDF');

Danach erzeugen wir einen Multicolumn-Datastore über die beiden Spalten DATEI_TYP und INHALT, um eine einzige CONTAINS- Abfrage über die beiden Spalten durchzuführen. Um den Multicolumn-Datastore nutzen zu können, muss zunächst eine Preference erzeugt werden; hier werden die Spalten, welche gemeinsam indiziert werden sollen, konfiguriert. Da nur die Spalte INHALT und nicht die Spalte DATEI_TYP gefiltert werden soll, setzen wir die FILTER-Attribute auf 'N,Y'.

begin
ctx_ddl.create_preference('mds', 'multi_column_datastore');
ctx_ddl.set_attribute('mds', 'columns', 'datei_typ, inhalt');
ctx_ddl.set_attribute('mds', 'filter', 'N,Y');
end;
/

Die Spalten sind nun im Multicolumn-Datastore MDS zusammengeführt. Da die Spalte DATEI_TYP als Metadatenspalte aufgefasst werden kann und keine Aufarbeitung in Tokens benötigt, definieren wir die entsprechende MDATA-Section für DATEI_TYP.

begin 
ctx_ddl.create_section_group('bsg', 'basic_section_group');
ctx_ddl.add_mdata_section('bsg', 'datei_typ', 'datei_typ');
end;
/

Im letzten Schritt erzeugen wir noch den Index IDX auf die Spalte INHALT.

SQL> CREATE INDEX idx ON documents(inhalt) INDEXTYPE IS ctxsys.context 
     PARAMETERS ('section group bsg datastore mds filter ctxsys.auto_filter');
Index created.
SQL> SELECT err_index_name, err_timestamp, err_textkey, err_text
     FROM ctx_user_index_errors ORDER BY err_index_name, err_timestamp;
no rows selected

Überprüfen wir nun die Dokumente auf einen Inhalt zum Beispiel auf "external". Die Dokumente mit ID 1 und 3 enthalten offensichtlich das gesuchte Token.

SQL> SELECT score(1), id, datei_typ 
     FROM documents WHERE contains(inhalt, 'external', 1)>0;

   SCORE(1)         ID DATEI_TYP
---------- ---------- ----------
        12          1 html
        12          3 PDF


Im nächsten Schritt sollen PDF-Dokumente eine höhere Priorität als HTML-Dokumente erhalten. Dazu nutzen wir den Operator MDATA. Zu beachten ist dabei, dass MDATA Sektionen immer case-sensitiv sind. Das bedeutet wir müssen auf "PDF" und "html" abfragen. Zusätzlich liefert das Ergebnis des MDATA-Operators immer den Wert 0 für "keine Treffer" und 100 für "Treffer". Überprüfen wir zuerst das Scoring auf PDF-Formate . Dokument 3 und 4 sind PDF Dokumente und erhalten den Score 100.

SQL> SELECT score(1), id, datei_typ FROM documents 
     WHERE contains(inhalt, 'mdata(datei_typ, PDF)', 1)>0;
  SCORE(1)         ID DATEI_TYP
---------- ---------- ----------
       100          3 PDF
       100          4 PDF

Benutzen wir zusätzlich die Suchabfrage "external" und verbinden wir das Ganze mit dem ACCUM- Operator (hier mit Komma ','). Wir erhalten nun alle PDF-Dokumente und das HTML-Dokument mit dem entsprechenden Suchwort. Dann sieht das Ergebnis der Abfrage folgendermassen aus.

SQL> SELECT score(1), id, datei_typ FROM documents 
     WHERE contains(inhalt, 'mdata(datei_typ, PDF), external', 1)>0
     ORDER BY 1;
 SCORE(1)         ID DATEI_TYP
---------- ---------- ----------
         6          1 html
        50          4 PDF
        78          3 PDF

Wie arbeitet dabei der Operator ACCUM? Der Operator ACCUM sucht im ersten Schritt nach erfolgreichen Bedingungen und errechnet danach den Score aus der Anzahl der Treffer-Häufigkeit. Bei zwei Bedingungen und Treffer in den beiden Bedingungen (hier PDF und Suchwort) liegt dabei der Scorewert zwischen 51 und 100, ansonsten zwischen 1 und 50.
Um weitere Möglichkeiten aufzuzeigen, kombinieren wir die Abfrage mit einer zusätzlichen Gewichtung (in unserem Fall mit "*2") und nehmen zusätzlich das Format "html" hinzu. Nun können wir folgende Resultate erhalten.

SQL> SELECT score(1), id, datei_typ FROM documents 
     WHERE contains(inhalt, 'mdata(datei_typ, PDF)*2, mdata(datei_typ, html),    
     external', 1)>0 ORDER BY 1;
 SCORE(1)         ID DATEI_TYP
---------- ---------- ----------
        25          2 html
        39          1 html
        50          4 PDF
        68          3 PDF

SQL> SELECT score(1), id, datei_typ FROM documents 
     WHERE contains(inhalt, 'mdata(datei_typ, PDF)*2, mdata(datei_typ, html), 
     external*2', 1)>0 ORDER BY 1;

  SCORE(1)         ID DATEI_TYP
---------- ---------- ----------
        20          2 html
        40          4 PDF
        48          1 html
        71          3 PDF

Wie man im letzten Beispiel sehen kann, gibt es eine Vielfalt von möglichen Kombinationen. Probieren Sie es einfach aus...

Montag, 22. Juni 2009

Wie ähnlich soll es sein ...? Ein paar Worte zum FUZZY-Operator

Es ist weitgehend bekannt, dass Oracle TEXT eine Ähnlichkeitssuche mit dem Fuzzy-Operator unterstützt. Die einfachste Variante ist die Verwendung des Fragezeichens ?. Der Fuzzy-Operator ist gut geeignet, um mit etwaigen Rechtschreibfehlern in den Dokumenten umzugehen. Sucht man bspw. nach ?Spatial, so findet der Index auch Dokumente, in denen fälschlicherweise "Sptial" geschrieben wurde.
select dateiname, score(0) from dokumente where contains (content, '?Spatial', 0) > 0
Diese Ähnlichkeitssuche kann übrigens auch parametrisiert werden: Neben dem Fragezeichen steht auch das Schlüsselwort FUZZY zur Verfügung. Oder anders ausgedrückt: Obige SQL-Abfrage ließe sich auch so schreiben:
select dateiname, score(0) from dokumente where contains (content, 'FUZZY(Spatial, 60, 100, N)'), 0) > 0
Und mit diesen Parametern kann man das Verhalten des FUZZY-Operators nun steuern. Der erste Parameter legt fest, wie ähnlich die Tokens im Dokument dem Suchbegriff sein müssen. Erlaubt sind Werte von 1 bis 80. Je niedriger Ihr den Wert ansetzt, desto mehr Begriffe kommen in Frage; desto mehr Dokumente werden also gefunden. Allerdings stellt sich die Frage, wie relevant die Dokumente bei sehr niedrigen Grenzen noch sind.
Der zweite Parameter legt fest, wieviele Werte überhaupt in die Termexpansion einbezogen werden. Dazu kurz einige Worte: Oracle TEXT führt die Fuzzy-Suche über eine Termexpansion durch; es werden also zunächst aus der Token-Tabelle ($I) die ähnlichen Tokens herausgesucht (der erste Parameter legt, wie gesagt, fest, wie ähnlich die Tokens sein müssen). Mit den so gefundenen Tokens wird dann eine ODER Suche durchgeführt.
Mit dem zweiten Parameter legt man also fest, wieviele ähnliche Wörter maximal einbezogen werden sollen. Erlaubt sind Werte zwischen 1 und 5000. Ein Wert von 20 würde bewirken, dass maximal 20 ähnliche Wörter in der Suche berücksichtigt werden, auch wenn anhand des ersten Parameters mehr in Frage kämen. Hier gilt also: Je höher der Wert gesetzt wird, desto mehr Dokumente werden tendenziell gefunden ...
Der letzte Parameter wirkt sich nur auf den Score aus, den ein Dokument im Relevanz-Ranking bekommt. Mit einem W werden die Scores anhand der Ähnlichkeit der Suchwörter gewichtet; mit einem N geschieht das nicht. Ein W führt zu tendenziell höheren Scores.
Mit diesen Parametern könnt Ihr also spielen, um mit der Fuzzy-Suche mehr oder weniger Ergebnisse zu bekommen. Was konkret gebraucht wird, hängt von den Anforderungen des Projekts ab ... zur Verdeutlichung hier nochmals zwei Extrembeispiele. Das erste ist zwar "formal" eine Ähnlichkeitssuche, aber die Parameter "würgen" die Fuzzy-Logik weitgehend ab.
select dateiname, score(0) from dokumente 
where contains(content, 'fuzzy(sptial, 80, 1, W)',0) > 0;
Das zweite bohrt die Grenzen so weit auf, dass sehr viele Dokumente in Frage kommen ...
select dateiname, score(0) from dokumente 
where contains(content, 'fuzzy(sptial, 1, 5000, W)',0) > 0;
Dies lässt sich auch sehr gut mit Query Relaxation verbinden. In einer ersten Stufe würde ohne den Fuzzy-Operator suchen, in einer nächsten Stufe dann mit dem Fuzzy-Operator, aber eher restriktiven Kriterien und danach mit sehr weit gehenden Parametern. Query Relaxation arbeitet die Stufen dann bekanntlich so lange ab, bis genügend Treffer gefunden sind - mehr dazu im Blog Posting.

Beliebte Postings