Inhaltsverzeichnis
Oracle Text - Volltext Suche über Text Dokumente
In der DB als Option seit Oracle 7
Oracle Text ist eine der Perlen unter den Optionen der Oracle Datenbank.
Oracle Text, gestartet 1990 als SQL*TextRetrieval™, dann als DB Option mit Oracle Context mit 7.3 verfügbar, eingeführt als Intermedia Text mit der 8i und als Oracle Text Option seit 9i, ist fester Bestandteil des Datenbankkerns und Lizenz-kostenfrei in jeder Oracle Edition verfügbar.
Neben der Möglichkeit den Text in einer Spalte zu indizieren und damit einfach durchsuchbar zumachen, können auch ganze Dokumente, wie MS Word oder PDF, mit mitgelieferten oder eigenen Filtern in Text gewandelt und in den Suchindex aufgenommen werden.
Mit Topic Spotting über Theme Indexes lassen sich Text automatisch nach Themen verschlagworten und kategorisieren.
Dazu können sogar eigene Ontologie hinterlegt werden, um eine eigene sprachliche Begriffswelt abzubilden.
Auf diesen Daten lassen sich dann mit Oracle Text komplexe linguistische Abfragen durchführen, von einfachen like suchen bis zu komplexen Fuzzy Pattern Matchings.
Durch die vollständige Integration in SQL können auch komplexe Rechtevorgaben auf Daten einfach und integriert umgesetzt werden.
Gerade in 12c sind wieder neue spannende Features, wie der „near Realtime Index“ dazugekommen, um Oracle Text noch einfacher einzusetzen.
Die wichtigsten Begriffe rund um Oracle Text
Kurzer Überblick über die wichtigsten Begriffe im Zusammenhang mit Oracle Text
Token
- Durch Tokenizing wird der „rohe“ natürlich-sprachliche Text aus dem Korpus entlang der Wortgrenzen in einzelne Tokens zerlegt, die idealerweise Lexemen entsprechen
- Lexem ⇒ sprachliche Bedeutungseinheit
- Beispiel: Suche nach „Web-site“ findet genau „Website“
- Der Lexer zerlegt den Text in Token
Stemmer bzw. Stemming
- Mittels eines morphologischen Ersatzverfahrens (Stemming) werden die Token normalisiert. Dazu werden die vom Tokenizer ermittelten Lexeme auf Stämme reduziert, die idealerweise morphologisch fundierten Wortstämmen entsprechen
- Beispiel: Suche nach „läuft“ findet auch ⇒ „laufen“, „lief“
Thesaurus
- Wörterbuch aus Relationen zwischen Lexemen
- Beispiel: Suche nach „PKW“ findet auch „Auto“ (Relation Synonym)
Theme
- Kowledge base, hierarchical tree of concepts (Basis für den Theme Index)
- Eine „Begriffswelt aus Werten“ über eine Ontologie kann helfen den Inhalt eines Dokumentes zu beschreiben
- Beispiel: Begriffswelt „SQL Oracle Context Index“ beschreibt alle Dokumente über Oracle Text ⇒ Bei einer Suche nach „Index“ werden alle Dokumente gefunden, auch wenn Index nicht als Wort vorkommt.
- Wird auf der Basis eines vorhandenen Thesaurus erstellt
Fuzzy Suche
- Bedeutet soviel wie „undeutlich“, „verschwommen“ oder „unscharf“
- Erweiterung der gewöhnlichen Mengenlehre
- Beispiel: Suche nach „Kamdurga“ findet auch „Hamburger“
Gist
- Zusammenfassung eines Dokuments
Die Oracle Soundex Funktion für Phonetischer Vergleich hat nichts mit Oracle Text zu tun, hier werden Wörter über einen einfachen Algorithmus verglichen, siehe ⇒ Mit Soundex Wörter in der Datenbank vergleichen, neben Soundex stehen noch die Jaro Winkler Funktion - Strings vergleichen und Ähnlichkeiten in String qualifizieren zur Verfügung.
Ein erster einfacher Einsatz
Oracle Text verwendet einen speziellen Index Typ, im einfachsten Fall den Typ „CTXSYS.CONTEXT“
Beispiel:
Unterstützte Datentypen: VARCHAR2, BLOB, CLOB, CFILE (Historisch LONG, LONG RAW )
Der Text in den Spalten muss allerdings im einfachen Fall immer als Text vorliegen, sollen Binäre Dokumente indiziert werden müssen externe Filter dazu eingebunden werden.
Abgefragt werden die Daten dann mit dem Oracle Text CONTAINS Operator (siehe Abschnitt über Oracle Datenbank Operatoren, mehr dazu unter Oracle Text - In Texten suchen
Der Oracle Context Index wird allerdings NICHT zusammen mit einer DML Operation auf den Text per Default aktualisiert.
Wird der Text einer indizierten Spalte geändert oder gelöscht, merkt sich Oracle Text das nur in einer Pending Tabelle.
Erst beim nächsten Aufruf von „ctx_ddl.sync_index('<index_name>', '<Memory wie 2M>');“ wird die Änderung in den Index aufgenommen.
Die Daten eines gelöschten Dokumentes werden allerdings nicht bereinigt, d.h. nach einer gewissen Zeit bei Tabellen mit hohen Änderungsvolumen ist ein kompletter Neuaufbau sehr sinnvoll.
Oracle Text Index Typen
Folgende Index Typen stehen uns für die Indizierung zur Verfügung:
CONTEXT
- Textrecherche mit CONTAINS Operator
- Umfangreiche Parameter und Features
- Muss nach DML mit CTX_DDL.SYNC_INDEX aktualisiert werden
- Suche mit dem CONTAINS Operator
- Neu mit 12c ⇒ „near Realtime Index“ Feature über storage preference „STAGE_ITAB“ auf „true“
CTXCAT
- Einfachere Version für kleine Mengen von Dokumenten
- In Transaktionslogik eingebunden
- Suche mit dem CATSEARCH Operator
CTXRULE
- Dokumenten Klassifizierung
- Mehr dazu siehe unter ⇒ Einsatz des CTXRULE Indexes zur Dokumenten Klassifizierung
- Suche mit dem MATCHES Operator
CTXXPATH (Desupported in Oracle Text and Oracle XML DB mit der Version 12c!)
- XML Datentypen schneller mit ExistsNode() abfragen
Aufbau des Index Typ CONTEXT
Alle Index Typen von Oracle Text verwenden Datenbank Tabellen um den eigentlichen logischen Index abzubilden. Auf diesen Hilfstabellen (DR$<index_name>$<I|K|N|R|P) können zum Teil wieder normale Indexe (mit einer Eigenschaft beim Erzeugen des Indexes) zur Performance Optimierung angelegt werden
Zum Beispiel werden für einen Index vom Typ CTXSYS.Context und mit dem Namen „IDX_DOCUMENTS_DOCS min. die folgenden 4 Tabellen erstellt:
- DR$IDX_DOCUMENTS_DOCS$I (invertierte Liste aller Wörter)
- DR$IDX_DOCUMENTS_DOCS$K (Key Map)
- DR$IDX_DOCUMENTS_DOCS$N (NEG - Gelöschte Datensätze vermerken)
- DR$IDX_DOCUMENTS_DOCS$R (Denormalisierte Mapping-Tabelle )
- Optional: DR$IDX_DOCUMENTS_DOCS$P (Substrings)
- Optional: DR$IDX_DOCUMENTS_DOCS$O (ab 12c Forward Indexing für Highlightning, Snippet,Markup Function)
- Optional: DR$IDX_DOCUMENTS_DOCS$D (ab 12c Forward Indexing , kompletter Text als PlainText Spalte für Higlighting, Snippet,Markup function für binäre Dokumente)
- Optional: DR$IDX_DOCUMENTS_DOCS$G (ab 12c für das Feature Near Real Time Indexes verwendet)
Ein Pipline Prozess füllt diese Strukturen im Index beim Anlegen bzw. aktualisieren.
Für alle diese Abschnitte können beim Anlegen eines Context Indexes dann entsprechend die Eigenschaften eingestellt werden, siehe dazu in der Dokumentation ⇒ https://docs.oracle.com/database/121/CCREF/cdatadic.htm#CCREF0200
Mehrsprachigkeit mit MULTI_LEXER
Was passiert beim Einfügen eines neuen Textes?
Wörter aus den Index verbannen - Stop Words definieren
Welche Wörter werden per Default nicht indiziert:
SELECT * FROM ctxsys.ctx_stopwords WHERE spw_stoplist LIKE 'DEFAULT_STOPLIST' ORDER BY spw_word;
Auslesen per Package siehe auch http://blog.mclaughlinsoftware.com/oracle-text-programming/reading-a-ctx-index-stoplist/
Eine eigenen StopWord Liste läßt sich auch anlegen:
EXEC ctx_ddl.create_stoplist('GPI_STOPLIST','BASIC_STOPLIST'); EXEC ctx_ddl.add_stopword('GPI_STOPLIST','10'); ...
Im laufenden Betrieb einfügen:
ALTER INDEX idx_doc_files PARAMETERS('ADD STOPWORD gpi');
Stop Word wieder entfernen:
EXEC ctx_ddl.remove_stopword('GPI_STOPLIST', 'gpi');
12c Pattern Stopclass
Entferne alle Zahlen die länger als 4 Zeichen sind:
EXEC ctx_ddl.add_stopclass ('GPI_STOPLIST', 'NUM_GT_4', '[[:digit:]\,\.]{5,}')
Dokumente in der Datenbank speichern
Nur im einfachsten Fall liegen Dokument immer schon bereits als reine Text Dateien vor.
Wir können dann die Dokumente als VARCHAR2 Text Spalte mit 4.000 Zeichen oder in CLOB Spalten (Maximale Größe ist (4 gigabytes - 1) * (database block size)) speichern.
Seit 12c kann auch die Datenbank umgestellt werden, es können dann bis zu 32767 Zeichen in einer Varchar2 Tabellen Spalte abgelegt werden, Dazu muss der Parameter max_string_size aber auf EXTENDED geändert werden, das kann wiederum nicht online durchgeführt werden ⇒ ORA-14694: database must in UPGRADE mode to begin MAX_STRING_SIZE migration.
Liegen die Daten binär vor, steht uns der Dateityp BLOB zur Verfügung, ab 11g sollte diese LOB Spalten als LOB und Oracle Secure Files abgelegt werden. Diese können dann komprimiert und de-dupliziert werden.
Alternativ können die Dateien aber einfach auch im Filesystem verbleiben und werden mit einen BFILE Datentyp über ein Oracle Directory Objekte referenziert.
Wie in diesen Beispiel werden dann nur die File Pointer in der DB gespeichert und indiziert, Siehe ⇒ Mit Python Referenzen für alle Dateien einer Verzeichnisstruktur in der Oracle Datenbank speichern
Binäre Daten indizieren
Mit dem Update auf die Version Oracle Text 11g Release 1 wurde von den Filtern der Firma Inso auf die Filter der Firma Stellent umgestellt. Der Name der Filter Option wurde von INSO_FILTER auf AUTO_FILTER angepasst.
Damit das aber rückwärts kompatibel bleibt, gibt es auch weiterhin die INSO_FILTER Option, allerdings sollte stattdessen immer mit AUTO_FILTER bei neuen Applikationen gearbeitet werden.
In der Version 12c R1 können diese Filter auf diesen Plattformen und diesen Dokumenttypen angewandt werden.
Damit steht uns die Technologie unter Windows und Linux zur Verfügung und es können die wichtigsten MS Office Formate (offiziell bis zur Version 2010) und PDF gelesen werden.
Ein erster Test um den Filter zu testen, wir wandeln eine Powerpoint Datei 2013 in eine HMTL Datei (ohne Bilder) um:
#Windows Powershell Syntax! #Oracle Home setzen & $env:ORACLE_HOME/bin/ctxhx.exe & $env:ORACLE_HOME/bin/ctxhx.exe d:\doag\apex_connect2016.pptx d:\temp\output_data.html
Mehr Informationen dazu siehe Oracle Text für die Indizierung binärer Daten verwenden
Alternativ sollte der Einsatz von PROCEDURE_FILTER angedacht werden.
Einen Theme Index aufbauen
Mit Hilfe eines Theme Indexe lässt sich der Inhalt eines Dokumentes besser verstehen, über ein Regelwerk schließen wir auf die ungefähre Bedeutung des Dokuments.
Allerdings benötigen wir für eine solche Analyse ein entsprechendes Regelwerk, eine Ontologie.
Für die Englisch liegt zwar einiges breits vor, für Deutsch muss aber selber ein Regelwerk aufgestellt werden.
Für den Theme Index wird ein Oracle Context Index mit einer eigen Eigenschaft für den Lexer (INDEX_THEMES) angelegt.
Siehe Oracle Text Theme Indizierung von Dokumenten
Mit einem Thesaurus und Oracle Text arbeiten
Über einen Thesaurus werden Relationen zwischen Wörtern abgebildet.
Eine Typische Relation ist das strikte Synonym (SN) wie „Apfelsine“ „Orange“, das heißt beide Begriffe stehen in der Hauptsache tatsächlich für das gleiche. Die Begriffe können aber im Textkontext durchaus eine andere Bedeutungs-Färbung entfalten.
In der Sprache gibt es im Regelfall selten zwei Wörter für exakt die gleiche Bedeutung.
Allerdings gibt es viele Verwandtschaftsgrade zwischen verschiedenen Wörtern, die eine ähnliche Bedeutung im Text Kontext entfalten können und eine zusätzliche Wertung enthalten.
Alles diese Beziehung können in eine Thesaurus modelliert werden und dann über Oracle Text auch auf den Text zur Suche verwendet werden.
Allerdings stehen diese Thesaurus nur für wenige Sprache wie Englisch zur Verfügung, meist muss ein eigener Thesaurus erstellt werden.
Auch passen allgemeine Thesaurus oft gar nicht so zur eigentlichen Aufgabe, wie das Finden von alternativen Beziehungen in Fachdokumenten.
Ein Thesaurus ist dann wiederum die Voraussetzung das ein Dokument über einen Oracle Theme Index indiziert und gesucht werden kann.
Da die Definition diese Regel doch sehr anspruchsvoll werden kann, ist ein sehr sinnvoller Einsatz in der Klassifizierung von Dokumenten zu finden, z.b. über den CTX Rule Index.
Im Detail siehe Mit einem Thesaurus und Oracle Text arbeiten
Der Oracle Text Contains Operator
Die eigentliche Volltext Suche in SQL wird über den Contains Operator durchgeführt.
Generelle Syntax:
SELECT id , SCORE(1) FROM TEXTE WHERE CONTAINS(COLUMN, 'query_string',1)>0 / -- Beispiel für die fussy Suchen in der ausführlichen Variante SELECT * FROM texte WHERE contains(text, 'fuzzy(Hunt, 50, 50, WEIGHT)') >0;
Über die SCORE Funktion kann die Relevance eines Treffers in der Ergebnismenge mit angezeigt werden.
Im Detail Siehe auch dazu ⇒ Oracle Text - In Texten suchen
Die Ergebnisse der Suchen markieren / hervorheben
Nach dem ein Dokument mit einer Volltext Suche gefunden wurde, stellt sich natürlich die Frage, wo den im Text etwas erkannt wurde.
Für die Aufbereitung der Trefferliste/Dokumentanzeige wird dazu das CTX_DOC Package eingesetzt.
So kann zum Beispiel mit „CTX_DOC.SNIPPET“ der Treffer Text Abschnitt angezeigt werden:
Siehe auch dazu ⇒ Oracle Text - Die Treffer in der Ergebnismenge hervorheben
Oracle Text Funktionen in PL/SQL für binäre Dokumente verwenden
Neben der Hauptfunktion der Volltext Suche können die Oracle Text Feature auch in PL/SQL für das arbeiten mit Binären Dokumente verwendet werden.
Zum Beispiel einen Vorschauansicht eines binären Dokumentes wie MS Word in Apex darzustellen oder Daten auszulesen und zu verarbeiten.
Dazu kann sehr gut das CTX_DOC Package eingesetzt werden.
Siehe auch dazu ⇒ Oracle Text für die Verarbeitung von Binären Daten in PL/SQL verwenden
Mit Oracle Text über mehrere Tabellenspalten oder Tabellen suchen
Für einen Anwender ist es oft sehr praktisch in einer Suchmaske über mehrere Datenbank Felder hinweg zu suchen.
Mit der „DATASTORE“ Eigenschaft des Index lässt sich definieren wo die Daten liegen, wichtig ist es einen eindeutigen Primary Key für den späteren Zugriff auf die Daten zur Verfügung zu haben.
⇒ Mit Oracle Text mehrere Spalten mehrerer Tabellen indizieren
Installation von Oracle Text in der Datenbank ( None CDB!)
Allerdings sollten vor der Verwendung nach der Installation noch die jeweiligen Parameter von Oracle Text optimiert und eingestellt werden!
11g
Am einfachsten ist die Installation gleich zu Beginn bei der Datenbank Installation.
Nachträglich kann unter 11g Oracle Text mit SQL*Plus nach installiert werden (evtl. auch mit 12c ohne Multi/Single Tenant möglich aber nicht mehr supported!):
#set DB enviroment cd $ORACLE_HOME/rdbms/admin sqlplus / AS sysdba spool /tmp/oracle_text_install.log @?/ctx/admin/catctx.sql ctxsys_pwd_changeon_install SYSAUX TEMP NOLOCK exit #load LANGUAGE settings sqlplus ctxsys/ctxsys_pwd_changeon_install @?/ctx/admin/defaults/dr0defin.sql "GERMAN"; exit #Lock the account FOR security sqlplus / AS sysdba ALTER USER ctxsys account LOCK password expire; #check: SELECT comp_name, STATUS, substr(version,1,10) AS version FROM dba_registry WHERE comp_id = 'CONTEXT'; SELECT * FROM ctxsys.ctx_version; SELECT object_name, object_type, STATUS FROM dba_objects WHERE owner='CTXSYS' AND STATUS != 'VALID' ORDER BY object_name;
- Siehe auch dazu Support Note: 11g R2 - ID 970473.1
12c
- Siehe für 12c ID 1666831.1 - nur noch Database Configuration Assistant (DBCA) offizell möglich.
19c
- Siehe Support Node : Oracle Text Installation Steps For New 19c Installs (Doc ID 2591868.1)
#set DB enviroment cd $ORACLE_HOME/rdbms/admin sqlplus / AS sysdba spool /tmp/oracle_text_install.log @?/ctx/admin/catctx.sql ctxsys_pwd_changeon_install SYSAUX TEMP NOLOCK exit #load LANGUAGE settings -- 19c Change To use the CTXSYS schema you must"connect / as sysdba" followed by "alter session set CURRENT_SCHEMA=CTXSYS;" sqlplus / AS sysdba ALTER SESSION SET CURRENT_SCHEMA=CTXSYS; SQL> SELECT sys_context( 'userenv', 'current_schema' ) FROM dual; SYS_CONTEXT('USERENV','CURRENT_SCHEMA') -------------------------------------------------------------------------------- CTXSYS @?/ctx/admin/defaults/dr0defin.sql "GERMAN"; exit -- test SELECT comp_name, STATUS, substr(version,1,10) AS version FROM dba_registry WHERE comp_id = 'CONTEXT'; SELECT * FROM ctxsys.ctx_version;
Eine Schema für Oracle Text aktivieren
Dazu muss die Rolle ctxapp vergeben werden.
GRANT CTXAPP TO MYUSER; GRANT EXECUTE ON CTXSYS.CTX_CLS TO myuser; GRANT EXECUTE ON CTXSYS.CTX_DDL TO myuser; GRANT EXECUTE ON CTXSYS.CTX_DOC TO myuser; GRANT EXECUTE ON CTXSYS.CTX_OUTPUT TO myuser; GRANT EXECUTE ON CTXSYS.CTX_QUERY TO myuser; GRANT EXECUTE ON CTXSYS.CTX_REPORT TO myuser; GRANT EXECUTE ON CTXSYS.CTX_THES TO myuser; GRANT EXECUTE ON CTXSYS.CTX_ULEXER TO myuser;
Überwachung
Analyse Script
Die Oracle Text Eigenschaften in der DB Abfragen und ein SQL für die Anlayse der Oracle Text Indexes erstellen:
- ctx.sql
SET verify off SET linesize 120 pagesize 4000 recsep OFF define USER_NAME = &1 ttitle LEFT "Oracle Text Indexes for the user &&USER_NAME." skip 2 COLUMN idx_owner format a15 heading "Qwner" COLUMN TABLE_NAME format a35 heading "Table/View Name" COLUMN idx_name format a25 heading "Name" COLUMN idx_status format a8 heading "Status" COLUMN idx_type format a12 heading "Index Type" SELECT idx_owner ,idx_name ,idx_table_owner||'.'||idx_table AS TABLE_NAME ,idx_status ,idx_type FROM ctxsys.ctx_indexes WHERE UPPER(idx_owner) IN (UPPER('&&USER_NAME.')) / -- -- create the CTX_REPORT.DESCRIBE_INDEX sql's -- SET long 64000 SET pages 0 SET heading off SET feedback off spool get_ctx_desc_report.sql prompt SET long 64000 prompt SET longchunksize 64000 prompt SET head off prompt SET echo ON prompt spool ctx_desc_report.txt SELECT 'select ctx_report.describe_index('''||idx_owner||'.'||idx_name||''') from dual;' FROM ctxsys.ctx_indexes WHERE UPPER(idx_owner) IN (UPPER('&&USER_NAME.')) / prompt spool off prompt exit spool off -- create the anlyse script spool get_ctx_stat_report.sql prompt SET echo ON prompt SET serveroutput ON prompt CREATE TABLE ctx_report_output (ctx_name varchar2(40), RESULT CLOB) prompt / prompt prompt DECLARE prompt x CLOB := NULL;; prompt BEGIN prompt ctx_output.start_log('ix_search_stats.log');; SELECT ' ctx_report.INDEX_STATS('''||idx_owner||'.'||idx_name||''',x);' ||chr(10) ||' insert into ctx_report_output values ('''||idx_name||''',x);' ||chr(10) ||' commit;' FROM ctxsys.ctx_indexes WHERE UPPER(idx_owner) IN (UPPER('&&USER_NAME.')) / prompt ctx_output.end_log;; prompt dbms_lob.freetemporary(x);; prompt END;; prompt / prompt prompt SET long 64000 prompt SET longchunksize 64000 prompt SET head off prompt SET pagesize 10000 prompt spool ctx_stat_report.txt prompt SELECT RESULT prompt FROM ctx_report_output prompt / prompt spool off prompt exit spool off SET pages 100 SET heading ON SET feedback ON prompt ... TO GET the FULL informations OVER the indexes CALL the generated prompt ... SQL report @get_ctx_desc_report.sql prompt prompt ... TO GET the statistic informations OVER the indexes CALL the generated prompt ... SQL report @get_ctx_stat_report.sql prompt ... prompt ... CHECK FOR the run IF the log directory ORACLE_HOME/ctx/log exits! prompt ... ttitle LEFT "Oracle Text Parameters" skip 2 COLUMN par_name format a25 heading "Parameter" COLUMN par_value format a30 heading "Value" SELECT par_name , par_value FROM ctxsys.ctx_parameters ORDER BY 1 / ttitle LEFT "Oracle Text Preferences" skip 2 COLUMN pre_owner format a15 heading "Owner" COLUMN pre_name format a35 heading "Parameter" COLUMN pre_class format a15 heading "Class" COLUMN pre_object format a35 heading "Object" SELECT pre_owner , pre_name , pre_class , pre_object FROM ctxsys.ctx_preferences WHERE UPPER(pre_owner) IN (UPPER('&&USER_NAME.')) ORDER BY 1,2,3 / ttitle LEFT "Oracle Text Attributes" skip 2 COLUMN prv_owner format a15 heading "Owner" COLUMN prv_preference format a30 heading "Perference" COLUMN prv_attribute format a20 heading "Attribute" COLUMN prv_value format a50 heading "Value" SELECT prv_owner , prv_preference , prv_attribute , prv_value FROM ctxsys.ctx_preference_values WHERE UPPER(prv_owner) IN (UPPER('&&USER_NAME.')) ORDER BY 1,2,3,4 / ttitle off
Aktuellste Version siehe hier https://orapowershell.codeplex.com/SourceControl/latest#sql/ctx.sql
Quellen
Einführung:
Analyse:
Optimierung:
Binäre Daten indizieren:
Theme:
Vorträge:
Themen Sammlung
Thumbnail erstellen für eine Dokumentenvorschau Ansicht
Spracherkennung:
Python Lib:
Mime Type Erkennung
Unter Python ⇒ https://github.com/ahupp/python-magic Hat bei mir nicht geklappt …
File für Windows http://gnuwin32.sourceforge.net/packages/file.htm Zeigt auch die Metadaten für ältere Office Versionen an