Stellen Sie sich vor, dass Sie ca. 1 Million Dokumente in Word- und PDF-Formaten haben. Diese Dokumente liegen im Filesystem eines Fileservers. Wie kann man eine Kontextsuche in diesem Chaos organisieren, ohne alle Dokumente neu zu verarbeiten bzw. manuell in der Datenbank einzulesen?
Oracle Fulltext Search ermöglicht das!
Sie können mit Hilfe der Search-Maschine alle Inhalte aller Dateien indizieren. Darauf aufbauend kann die Datenbank für Sie nach relevanten Dokumenten suchen. Zum Beispiel alle Dokumente, in denen „Stadt München“ steht.
Ein Textindex besteht aus mehreren internen Objekten und hat zahlreiche Einstellungen. Wie ein Index ganz genau definiert ist, kann mittels PL/SQL Packages „CTX_REPORT“ abgefragt werden. Die folgende Abfrage liefert uns das fertige Skript für den kompletten Neuaufbau eines Indices.
SQL> select ctx_report.create_index_script('IM_XXX') from dual;
begin
ctx_ddl.create_preference('"IM_XXX_DST"','DIRECT_DATASTORE');
end;
/
begin
ctx_ddl.create_preference('"IM_XXX_FIL"','NULL_FILTER');
end;
/
begin
ctx_ddl.create_section_group('"IM_XXX_SGP"','NULL_SECTION_GROUP');
end;
/
begin
ctx_ddl.create_preference('"IM_XXX_LEX"','BASIC_LEXER');
ctx_ddl.set_attribute('"IM_XXX_LEX"','BASE_LETTER','YES');
ctx_ddl.set_attribute('"IM_XXX_LEX"','MIXED_CASE','NO');
ctx_ddl.set_attribute('"IM_XXX_LEX"','INDEX_TEXT','YES');
ctx_ddl.set_attribute('"IM_XXX_LEX"','INDEX_THEMES','NO');
ctx_ddl.set_attribute('"IM_XXX_LEX"','ALTERNATE_SPELLING','GERMAN');
end;
/
begin
ctx_ddl.create_preference('"IM_XXX_WDL"','BASIC_WORDLIST');
ctx_ddl.set_attribute('"IM_XXX_WDL"','STEMMER','GERMAN');
ctx_ddl.set_attribute('"IM_XXX_WDL"','FUZZY_MATCH','GERMAN');
end;
/
begin
ctx_ddl.create_stoplist('"IM_XXX_SPL"','BASIC_STOPLIST');
end;
/
begin
ctx_ddl.create_preference('"IM_XXX_STO"','BASIC_STORAGE');
ctx_ddl.set_attribute('"IM_XXX_STO"','R_TABLE_CLAUSE','lob (data) store as (cache)');
end;
/
begin
ctx_output.start_log('IM_XXX_LOG');
end;
/
create index "USR"."IM_XXX" on "USR"."XXXTEST" ("XXX")
indextype is ctxsys.context
parameters('
datastore "IM_XXX_DST"
filter "IM_XXX_FIL"
section group "IM_XXX_SGP"
lexer "IM_XXX_LEX"
wordlist "IM_XXX_WDL"
stoplist "IM_XXX_SPL"
storage "IM_XXX_STO"
')
/
begin
ctx_output.end_log;
end;
/
Mittels ctx_ddl.create_preference werden die unterschiedlichen internen Eigenschaften für die Text-Suchmaschine definiert. „Datastore“ und „Storage“ teilen der Datenbank zum Beispiel mit, wo sich die zu durchsuchenden Dateien befinden und wie auf diese zugegriffen werden kann. Die Preference „Lexer“ sagt, welche semantische Regeln („German“ für die deutsche Sprache in unserem Beispiel) benutzt werden sollen.
Muss man aber wirklich alle diese Parameter bei jeder Indexerstellung explizit angeben? Natürlich nicht. Mit der folgenden, verkürzten Form wird normalerweise ein Textindex angelegt:
create index im_xxx on xxxtest(xxx) indextype is ctxsys.context
Parameters('lexer ctxsys.us_lexer stoplist ctxsys.no_stopword memory 400M')";
Soweit keine anderen Parameter direkt im Create-Statement mitgegeben werden, werden die bereits definierten Einstellungen verwendet. Man muss also die Parametrisierung für die ganze Oracle-Text-Maschine nur einmal durchführen.
Wie kann man die bereits konfigurierten Parameter sehen?
SQL> select * from ctx_parameters;
Was tun, falls Probleme mit Textindices auftreten?
Tipp: Logging einzuschalten.
Gehen wir zurück zu unserem Beispiel, der Befehl zum Aufbau des Indices mit Logging sieht wie folgt aus:
begin
ctx_output.start_log('IM_XXX_LOG');
end;
/
create index "USR"."IM_XXX" on "USR"."XXXTEST" ("XXX")
indextype is ctxsys.context
parameters('
datastore "IM_XXX_DST"
filter "IM_XXX_FIL"
section group "IM_XXX_SGP"
lexer "IM_XXX_LEX"
wordlist "IM_XXX_WDL"
stoplist "IM_XXX_SPL"
storage "IM_XXX_STO"
')
/
begin
ctx_output.end_log;
end;
/
Mittels der Prozedur ctx_output.start_log starten wir das Logging. Der Parameter „IMM_XXX_LOG“ steht für den Filenamen, unter welchem unser Logfile gespeichert wird. Den kompletten Verzeichnispfad findet man unter dem Parameter 'LOG_DIRECTORY' im 'CTX_PARAMETERS' View.
Wenn nötig kann der Verzeichnisname wie im folgenden Beispiel angepasst werden:
execute CTXSYS.CTX_ADM.SET_PARAMETER ('LOG_DIRECTORY','/tmp');
Mittels der Prozedur ctx_output.stop_log wird das Logging ausgeschaltet.
Schauen wir nun einmal so ein Logfile (in gekürzter Form) an. Was passiert beim Aufbau eines Oracle Textindices:
Oracle Text, 11.2.0.1.0
16:34:24 10/07/19 begin logging
16:34:36 10/07/19 Current values of enabled traces:
16:37:22 10/07/19 populate index: USER.IM_XXX
16:37:22 10/07/19 Begin document indexing
16:37:22 10/07/19 100 documents indexed
16:37:22 10/07/19 200 documents indexed
16:37:22 10/07/19 300 documents indexed
….
16:59:02 10/07/19 17926000 documents indexed
16:59:02 10/07/19 17926100 documents indexed
16:59:02 10/07/19 17926200 documents indexed
16:59:02 10/07/19 Errors reading documents: 0
16:59:02 10/07/19 Index data for 3414826 documents to be written to database
16:59:02 10/07/19 memory use: 223254929
16:59:02 10/07/19 Begin sorting the inverted list.
16:59:03 10/07/19 End sorting the inverted list.
16:59:03 10/07/19 Writing index data ($I) to database.
16:59:03 10/07/19 Inserting using direct path loading
16:59:10 10/07/19 Wrote 857419 rows (9526 big rows) to $I.
16:59:10 10/07/19 Writing index data ($R) to database.
16:59:10 10/07/19 index data written to database.
16:59:10 10/07/19 End of document indexing. 17926216 documents indexed.
16:59:10 10/07/19 Writing index data ($K) to database.
17:00:48 10/07/19 Wrote 17926216 rows to $K.
17:00:48 10/07/19 Creating Oracle index "USER"."DR$IM_XXX$X"
17:00:53 10/07/19 Oracle index "USER"."DR$IM_XXX$X" created
Einer unserer Kunden hatte folgendes Problem: in seinem Betrieb werden regelmäßig neue Applikations-Releases eingespielt. Dabei werden auch alle Textindices gelöscht und neu aufgebaut. Plötzlich kam bei der Erstellung eines neuen Textindices die folgende Fehlermeldung:
errMsg
"SQL execution error, ORA-29855: Fehler bei Ausführung der Routine ODCIINDEXCREATE
ORA-20000: Oracle Text-Fehler:
DRG-50857: oracle error in drvxtab.create_index_indexes
ORA-00955: Es gibt bereits ein Objekt mit diesem Namen
ORA-06512: in ""CTXSYS.DRUE"", Zeile 160
ORA-06512: in ""CTXSYS.TEXTINDEXMETHODS"", Zeile 366 "
Wie in Kapitel 3 beschrieben, schalteten wir das Logging ein. Dort wurde zwar kein Fehler protokolliert, aber es war ersichtlich, dass bei der Erstellung $X-Objekten der letzte Satz „Oracle index "USER"."DR$IM_XXX$X" created“ nicht im Log vorhanden war. Genau an dieser Stelle erhalten wir die oben beschriebene Fehlermeldung in der SQL-Plus Konsole.
Weitere Untersuchungen ergaben, dass ein Textindice aus mehreren internen Objekten besteht:
SQL> select object_name, object_type from user_objects where object_name like 'DR$IM_XXX%';
OBJECT_NAME OBJECT_TYPE
--------------- ----------------------
DR$IM_XXX$X INDEX
DR$IM_XXX$R TABLE
DR$IM_XXX$N TABLE
DR$IM_XXX$K TABLE
DR$IM_XXX$I TABLE
Der Problemindice wurde nochmals gelöscht und die Abfrage nochmal laufen gelassen:
SQL> drop index IM_XXX;
Index dropped.
SQL> select object_name, object_type from user_objects where object_name like 'DR$IM_XXX%';
OBJECT_NAME OBJECT_TYPE
------------- -------------
DR$IM_XXX$X INDEX
Offensichtlich wurde das X-Objekt (interner Index unseres Textindices) beim „drop index“ nicht vollständig entfernt. Deswegen wurde die Neuerstellung dieses Indexes abgebrochen, denn das Objekt mit dem gleichen Namen existiert ja bereits. Genau dies teilt uns auch die Datenbank mit der Fehlermeldung oben mit!
Die Lösung für das Problem?
Ganz einfach: das „Zombie-Objekt“ bereinigen.
SQL> drop index DR$IM_XXX$X;
Index dropped.
SQL> select object_name, object_type from user_objects where object_name like 'DR$IM_XXX%';
no rows selected
Und voilà!
SQL> create index im_XXX on XXXTEST(XXX) indextype is ctxsys.context Parameters('lexer ctxsys.us_lexer stoplist ctxsys.no_stopword memory 400M');
Index created.
Nach dieser „Reparatur“ hatte Oracle seine internen Objekte wieder im Griff und auch beim nächsten Release gab es keine Probleme mehr beim Neuanlegen des Textindices.
Grundlegendes Verständnis über den Aufbau von Oracle Textindices ist wichtig. Und ebenso wichtig für das Eingrenzen von Fehlern ist die Nutzung der Logging-Funktion. Für weitere Fragen steht unser DBA-Team Ihnen gerne zur Verfügung.
In unserer Know-How Datenbank finden Sie mehr als 300 ausführliche Beiträge zu den
Oracle-Themen wie DBA, SQL, PL/SQL, APEX und vielem mehr.
Hier erhalten Sie Antworten auf Ihre Fragen.