Freitag, 9. April 2010

Die Wordlist und das wildcard_maxterms Attribut

In folgendem Blog wird das WILDCARD_MAXTERMS Attribut, das eine Eigenschaft der BASIC_WORDLIST ist, kurz beschrieben und an einem Beispiel erklärt. Die Einstellung von WILDCARD_MAXTERMS gibt die maximale Anzahl der Ergebnisbegriffe einer Wildcard Suche an. Was bedeutet dies nun?

Wir nutzen im Beispiel die Tabelle TEXTTABELLE aus dem Blog und definieren zusätzlich die Präferenz für Mixed Case.

execute ctx_ddl.drop_preference('MY_LEXER');
begin
  ctx_ddl.create_preference(
    preference_name => 'MY_LEXER',
    object_name     => 'BASIC_LEXER');
  -- Mixed Case abschalten
  ctx_ddl.set_attribute(
    preference_name => 'MY_LEXER',
    attribute_name  => 'MIXED_CASE',
    attribute_value => 'NO');
end;
/

Danach setzen wir explizit die BASIC_WORDLIST auf den Wert 1, um einen Fehler auszulösen.

execute ctx_ddl.drop_preference('my_wordlist');
BEGIN
  ctx_ddl.create_preference('my_wordlist', 'BASIC_WORDLIST');
  ctx_ddl.set_attribute('my_wordlist', 'WILDCARD_MAXTERMS', 1);
END;
/

Nun wird der Index angelegt ...

CREATE INDEX idx_text ON texttabelle (dokument)
INDEXTYPE IS CTXSYS.CONTEXT
PARAMETERS ('WORDLIST my_wordlist LEXER MY_LEXER')
/

Bei der folgenden Abfrage erhalten wir nun einen Fehler, da eigentlich mehr als ein Ergebnis zu erwarten ist.

SQL> SELECT * FROM texttabelle WHERE contains (dokument,'%gewinn%')>0;
SELECT * FROM texttabelle WHERE contains (dokument,'%gewinn%')>0
*
FEHLER in Zeile 1:
ORA-29902: Fehler bei der Ausführung von Routine ODCIIndexStart()
ORA-20000: Oracle Text error:
DRG-51030: wildcard query expansion resulted in too many terms

Verifizieren wir das Ganze nun mit der Token-Tabelle, um die Ergebnisbegriffe einzusehen.

SQL> SELECT token_text FROM dr$idx_text$i WHERE upper(token_text) like '%GEWINN%';

TOKEN_TEXT
----------------------------------------------------------------
GEWINNT
GEWINNZUWACHS

Ändern wir also in der Wordlist das WILDCARD_MAXTERMS Attribut auf den Wert 20000. Dies ist übrigens in 11g der Default-Wert.
 
execute ctd_ddl.drop_preference('my_wordlist');
BEGIN  
  ctx_ddl.create_preference ('my_wordlist', 'BASIC_WORDLIST');
  ctx_ddl.set_attribute ('my_wordlist', 'WILDCARD_MAXTERMS', 20000);
END;
/

Passen wir im nächsten Schritt die Wordlist des Index an. Dies könnte Online mit Unterstützung des Shadow Index durchgeführt (siehe Blog) werden.

execute ctx_ddl.recreate_index_online('IDX_TEXT','REPLACE WORDLIST my_wordlist');

Nun erhalten wir das erwartete Ergebnis.

SQL> SELECT * FROM texttabelle WHERE contains (dokument,'%gewinn%')>0

        ID DOKUMENT
---------- --------------------------------------------------
         2 A-Partei gewinnt Wahl in Hansestadt
         4 Wirtschaft: Erneuter Gewinnzuwachs in diesem Jahr

Je nach Release der Datenbank gibt es unterschiedliche Default-Werte für das WILDCARD_MAXTERMS Attribut. Prüfen lässt sich dies mit folgender Abfrage:

SQL> SELECT oat_default, oat_min, oat_max  
FROM ctx_object_attributes 
WHERE oat_attribute LIKE '%MAXTERM%'

OAT_DEFAULT             OAT_MIN OAT_MAX
-------------------- ---------- ----------------------------------------
20000                         0 50000

Der aktuelle Wert lässt sich über folgende Abfrage ermitteln:

SQL> SELECT * FROM ctx_user_preference_values;

PRV_PREFERENCE                 PRV_ATTRIBUTE                  PRV_VALUE
------------------------------ ------------------------------ ----------
MY_LEXER                       MIXED_CASE                     NO
MY_WORDLIST                    WILDCARD_MAXTERMS              50000

Eine Anmerkung zum Schluss: Eine Erhöhung von WILDCARD_MAXTERMS muss nicht die optimale Lösung sein. Manchmal hilft eine Erweiterung der Stoppliste oder eine Anpassung der Auswahlliste innerhalb einer Webapplikation um den Anforderungen zu genügen.

Beliebte Postings