Benutzer-Werkzeuge

Webseiten-Werkzeuge


dba:oracle_text_index_binary_data

Oracle Text für die Indizierung binärer Daten verwenden

Einführung in Oracle Text ⇒ Oracle Text - Volltext Suche über Text Dokumente

Für die Verarbeitung von binären Daten, wie Word Dokumenten oder PDF stehen uns zwei Optionen mit Oracle Text zur Verfügung.

Wir können die „eingebaute“ Filterfunktion „AUTO_FILTER“ verwenden oder unseren eigenen Filter „USER_FILTER“ implementieren.

Unter Filter verstehen wir hier das Wandeln einer Binären Datei, wie PDF, MS World oder auch ein TIF Bild, in den reinen enthaltenen Text. Dieser Text wird dann in den Suchindex aufgenommen.

 Oracle Text - Binäre Daten filtern

Das Filterprogramm ctxhx

Das Programm ctxhx führt den eigentlichen Filtervorgang auch im Betriebssystem durch.

Für einen ersten Test wandeln wir eine PowerPoint Datei 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.p d:\temp\output_data.html

Nett, da fallen einen gleich ein paar Ideen ein, wie das auch außerhalb von Oracle benützt werden kann.


Der AUTO_FILTER Parameter

Mit dem Update auf die Version Oracle Text 11g Release 1 (Oracle Text 11.1.0.7 ) wurde von den Filtern vom Verity Keyview (Inso) auf die Filter von Outside In Technology (OIT) (ehemals Stellent) umgestellt. Die Firma Stellent wiederum wurde von Oracle schon 2006 gekauft.

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 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.

Liegen die zu filternden Daten als Lob oder BFILE im Zugriff der Datenbank, ist es ausreichende den AUTO_FILTER Parameter zu setzen, der Filter erkennt automatisch das richtige Dateiformat.

Beispiel:

CREATE INDEX idx_documents_docs ON documents(docs) 
                                   indextype IS ctxsys.context
                                   parameters ('filter ctxsys.auto_filter');

Der Filter ermittelt den Zeichensatz vom Dokument und wandelt die Zeichen entsprechend dem Datenbank Zeichensatz um.

Werden binäre und reine Text Daten gemischt in einer Tabellenspalte abgelegt, kann über eine eigene Spalte der Filter gesteuert werden, in der Spalte muss der Wert „binary“ für das Wandeln in Text oder „text“ für „Filter nicht ausführen“ stehen.

Beispiel inkl. Angabe des Zeichensatzes:

CREATE TABLE documents ( id NUMBER(11)
                       , txt_type varchar2(10)
                       ,  charset_name varchar2(20)
                       , docs  BLOB
                       );
 
CREATE INDEX idx_documents_docs ON documents(docs)  
             INDEXTYPE IS CTXSYS.CONTEXT 
             PARAMETERS ('filter ctxsys.AUTO_FILTER format column txt_type charset column charset_name');

Die Angabe des Zeichensatzes des Dokuments ist optional, der Zeichensatz eines TEXT Dokuments kann in einer Spalte hinterlegt werden, Angabe mit „filter ctxsys.AUTO_FILTER charset column charset_name'.

Der Zeichensatzname muss aber eine Oracle Zeichensatz Bezeichnung sein, siehe für den DB Zeichensatz „SELECT value$ FROM sys.props$ WHERE name = 'NLS_CHARACTERSET';“ und für alle möglichen Zeichensätze die View „V$NLS_VALID_VALUES“;

Internals

Wie ruft aber Oracle in 12c das Auto Filter Programm nun aber auf?

Test, ob der xtproc Mechanismus zum Aufruf externer DLL's in der 12c Datenbank für Oracle Text noch verwendet wird

  • Listener stoppen und Index droppen
  • Trace auf Autofilter anlegen
  • Index anlegen – Klappt ⇒ Laut Trace im Log File alles ok ⇒ Daten sind da
  • Listener wieder einschalten

Sehr viel früher ( min < 11g R1) war das meiner Meinung noch anders, sehen wir mal ob man sieht wie das heute funktioniert.

Die aktuellen Filter stammen wohl aus folgenden Produkt ⇒ Oracle Outside In Technology:

Die genannten DLL's lassen sich auch im Oracle Datenbank Home finden, wie das die „Identification Module“ sccfi.dll und der Export Filter für HTML Files exihtml.dll.

Die einzelnen Filter heißen im Filesystem vs*.dll wie vsword.dll.

Über die DDL Eigenschaften z.B. auf der vsword.dll ( den OIT Stream Filter) , kann die Version 8.3.7 von Outside In Technology erkannt werden.

Das ganze scheint als LIBRARY eingebunden zu sein:

SELECT owner,LIBRARY_NAME FROM dba_libraries WHERE owner ='CTXSYS';
 
OWNER      LIBRARY_NAME
---------  ------------
CTXSYS     DR$LIB

Der USER_FILTER Parameter

Über den USER_FILTER Parameter können auch weitere/eigene Programme zum Filtern oder bearbeiten/extrahieren der Daten verwendet werden.

Nachteil: Der Aufruf erfolgt aus der Datenbank über ein Script und muss vom Entwickler eigenständig auch vollständig gegen Missbrauch abgesichert werden!

Früher war das Problem noch ernster, auf meine Hinweis hin wurde mit dem Critical Patch Update Advisory - April 2009 das Verhalten soweit geändert, dass nun das Scriptt/Programm immer unter „$ORACLE_HOME/ctx/bin“ liegen muss.

In der Datenbank wird eine Preference hinterlegt, welches Programm bei Aufruf des Filters aufgerufen werden soll.

BEGIN
ctx_ddl.create_preference
   (
    preference_name => 'USER_FILTER_GPI_PREF',
    object_name     => 'USER_FILTER'
    );
 
ctx_ddl.set_attribute ('USER_FILTER_GPI_PREF', 'COMMAND', 'readDocument.cmd');
END;
/

Beim Aufruf des Programme werden zwei Parameter übergeben, der Input Dateiname und das Output Verzeichnis.

Test mit folgender CMD Datei:

echo PARAM 1: %1 >> d:\temp\ctx_test.log
echo PARAM 2: %2 >> d:\temp\ctx_test.log
echo PARAM 3: %3 >> d:\temp\ctx_test.log

Index anlegen:

CREATE INDEX idx_documents_docs ON documents(docs)  
             INDEXTYPE IS CTXSYS.CONTEXT 
             PARAMETERS ('filter USER_FILTER_GPI_PREF format column txt_type charset column charset_name');

Auch hier kann optional der Typ und der Zeichensatz angeben werden, um beim Typ „text“ den Filter Prozess zu überspringen.

Nun können wir testen was übergeben wurde.

Ausgabe unseres Test Programms, wenn Typ auf „binary“

PARAM 1: "C:\Users\ORACLE~1\AppData\Local\Temp\drgub19" 
PARAM 2: "C:\Users\ORACLE~1\AppData\Local\Temp\drgut20" 
PARAM 3:  

Wenn Typ auf „text“ dann wird das Programm nicht aufgerufen!

Wenn alles richtig läuft bleiben die Dateien nicht im Temp Bereich liegen.


Beispiel 1 - Datei wird in der Datenbank in einem Secure File in einer Tabelle gespeichert und mit AUTO_FILTER indiziert

Bzgl. Secure File siehe LOB und Oracle Secure Files

Zuvor die Rolle „grant CTXAPP to <user>“ vergeben.

Im einfachsten Fall wird der Filter als „FILTER CTXSYS.AUTO_FILTER“ definiert, ohne weitere Parameter, dann erfolgt alles automatisch mit dem Default Werten.

Beispiel:

#Tabelle anlegen, Secure File Lob Optionen angeben
 
CREATE TABLE documents ( id NUMBER(11)
                       , docs  BLOB
                       )
                       lob(docs) STORE AS SECUREFILE (CHUNK 4096 
                                      CACHE 
                                      DISABLE STORAGE IN ROW 
                                      COMPRESS  HIGH
                                      TABLESPACE USERS
                                      KEEP_DUPLICATES
                                      )
 
/
 
--
-- Daten einfügen z.B. mit dem SQL Loader
-- Oder einfach mit dem SQL*Developer für einen ersten Test
--
 
--Index anlegen mit dem Parameter FILTER CTXSYS.AUTO_FILTER
 
CREATE INDEX idx_documents_docs ON documents(docs)  
             INDEXTYPE IS CTXSYS.CONTEXT 
             PARAMETERS ('FILTER CTXSYS.AUTO_FILTER')
/
 
 
--
--Auf Fehler prüfen
SELECT * FROM ctx_user_index_errors;
 
 
--
--Index tabellen anzeigen lassen
 
SELECT TABLE_NAME FROM user_tables WHERE TABLE_NAME LIKE '%IDX_DO%';
 
Tablename
------------------------------
DR$IDX_DOCUMENTS_DOCS$I
DR$IDX_DOCUMENTS_DOCS$K
DR$IDX_DOCUMENTS_DOCS$N
DR$IDX_DOCUMENTS_DOCS$R
 
--
--Index Tabellen analysieren ob Daten vorhanden sind
 
SELECT token_text FROM DR$IDX_DOCUMENTS_DOCS$I;
TOKEN_TEXT
----------------------------------------------------------------
pfile
pipperr
pool
post
processes
...
 
--Daten wurden geparst und in den Index aufgenommen
 
--Abfrage mit contains und score für die Relevanz
 
SELECT id,score(10) FROM documents  WHERE contains(docs ,'pfile',10) > 0;
 
          ID    SCORE(10)
------------ ------------
           1           12


Beispiel 2 - Nur eine Referenz auf die Datei als BFILE Datei Pointer wird in der Datenbank referenziert und mit dann mit mit dem USER_FILTER indiziert

Zuvor die Rolle „grant CTXAPP to <user>“ vergeben, falls noch nicht durchgeführt.

Sollen die Dateien im Dateisystem verbleiben, bietet es sich an nur eine Referenz auf die Datei vom Datentyp BFILE in der Datenbank zu speichern und auf diese Referenz den Index aufzubauen.

Directory Objekt anlegen und Rechte vergeben

Über ein Directory Object wird der Einstieg in die Verzeichnisstruktur auf der Festplatte definiert.

In unseren Test Fall liegen die Daten unter „d:\data\info-archiv“ in einer Verzeichnisstruktur.

Anlegen als SYS und Rechte vergeben:

sqlplus / AS sysdba
#Directory anlegen
CREATE directory INFO_ARCHIVE AS 'D:\data\info-archiv';
#Rechte vergeben
GRANT READ,WRITE ON directory INFO_ARCHIVE TO GPI;

Tabelle mit der Medien Information ablegen

Tabelle anlegen und mit Hilfe der BFILENAME Funktion den File Pointer anlegen

CREATE TABLE documents ( id NUMBER(11)					
                       , docs  BFILE
                       )
/					   
 
INSERT INTO documents VALUES  (1,  BFILENAME('INFO_ARCHIVE', 'Oracle8i._salzburg.pdf'));
commit;

Oracle Context Index auf den auf die BFile Spalte anlegen

Im ersten Schritt verwenden wir die Oracle Filter um das Script zu testen:

Script readDocument.cmd:

echo PARAM 1: %1 >> d:\temp\ctx_test.log
echo PARAM 2: %2 >> d:\temp\ctx_test.log
 
set ORACLE_HOME=D:\oracle\products\12.1.0.2\dbhome_1

rem Oracle defaut Filter aufrufen
%ORACLE_HOME%/bin/ctxhx.exe %1 %2 >> d:\temp\ctx_test.log

USER_FILTER testen:

CREATE INDEX idx_documents_docs ON documents(docs)  
             INDEXTYPE IS CTXSYS.CONTEXT 
             PARAMETERS ('FILTER USER_FILTER_GPI_PREF')
/
 
--prüfen ob ein Fehler bei Indizieren aufgetreten ist:
 
SELECT * FROM CTX_USER_INDEX_ERRORS;
 
--Tritt ein Fehler auf wird hier auch auf die Datei mit dem Fehler verwiesen
 
--Testen ob Daten vorhanden sind
SELECT token_text FROM DR$IDX_DOCUMENTS_DOCS$I;
 
SELECT id,score(10) FROM documents  WHERE contains(docs ,'Oracle',10) > 0;
 
          ID    SCORE(10)
------------ ------------
           1          100
Im nächsten Schritt eigene Filter in USER_FILTER

Was können wir dann mehr mit dem USER_FILTER erreichen?

Welche Filter könnten bei den >500 Formaten des AUTO_FILTERS fehlen?

Zum Beispiel, Filter die Text erzeugen, die aus eigenen Regeln Text erzeugen sollen, oder alternative PDF Filter.

PDF Filter / PDF to TEXT Converter:

In dem Filterscript wird PDF dann mit einem „eigene“ Filter gewandelt, alles anderes mit dem ctxhx Filter von Oracle als Alternative.

Vorteil: Fehlerbehandlung gleich beim Indizieren des Dokuments.

Problem beim Aufbau des Index

Beim ersten Test schlägt der Aufbau fehl, ein ORA-07445 beendet die Session, Ursache ist noch unklar.

Nun läßt sich der Index aber nicht mehr löschen, ORA-29868: cannot issue DDL on a domain index marked as LOADING

Lösung:

DROP INDEX idx_doc_files
*
ERROR at line 1:
ORA-29868: cannot issue DDL ON a DOMAIN INDEX marked AS LOADING
 
-- als sys anmelden
-- Index 
ALTER INDEX GPI.idx_doc_files unusable;
 
-- mark as failed
EXEC ctxsys.ctx_adm.mark_failed( 'GPI', 'IDX_DOC_FILES');
 
DROP INDEX GPI.idx_doc_files;
 
INDEX dropped.

Nach dem Absturz bleibt

Auch ein erneuter Neuaufbau schlägt fehl, interessanterweise beim gleichen Dokument! Im Log File vom USER_FILTER Script läßt sich der Speicherort und die letzte Datei ermitteln, ein Test in der Console funktioniert allerdings.

BUG?

Das ist der Fehler:

Exception [type: ACCESS_VIOLATION, UNABLE_TO_READ] [ADDR:0x17AC0000] [PC:0x7FF79E737A80, __intel_memcpy()+5376]

ORA-07445: exception encountered: core dump [_intel_memcpy()+5376] [ACCESS_VIOLATION] [ADDR:0x17AC0000] [PC:0x7FF79E737A80] [UNABLE_TO_READ] []

Im nächsten Versuch das Tracing auf Oracle Text (siehe Ende des Artikels) aktivieren um den Fehler einzugrenzen.

Kein Erfolg ….

Dann mal ohne einen eigentlichen Filter testen, um das Problem einzugrenzen d.h. wir schreiben in die Out Datei einfach immer das gleiche.

Keine Besserung!

Allerdings taucht der Text nun im Trace vom Fehler auf, es hat wohl etwas mit der Rückgabe der Werte zu tun.

Das ist dann wohl ein Fall für den Oracle Support ……



Oracle 12c New STORAGE Feature - Plain Text in $D speichern - Forward Indexing in $O ablegen

Um später besser/schneller mit den Higlighting, Snippet und Markup Funktionen arbeiten zu können (siehe Oracle Text - Die Treffer einer Oracle Volltext Abfrage in der Ergebnismenge optisch hervorheben) kann der Text der Binären Dokument auch als PlainText in einer optionalen Tabelle des Oracle Text Domain Indexes gespeichert werden.

Zusätzlich kann dann noch für die Optimierung der Vorschau das Forward Indexing aktiviert werden, es wird eine zusätzliche Tabelle $O angelegt.

Gerade bei Binären Daten sollten beide Features eingesetzt werden, falls eine Vorschau auf die Dokumente eingesetzt werden soll.

Parameter für die STORAGE Eigenschaft des Index setzen:

BEGIN
ctx_ddl.create_preference (
    preference_name => 'GPI_BASIC_STORAGE',
    object_name     => 'BASIC_STORAGE'
    );
END;
/   
 
-- Forward Indexing
EXEC ctx_ddl.set_attribute('GPI_BASIC_STORAGE','forward_index','TRUE');
 
-- Plain Text
EXEC ctx_ddl.set_attribute('GPI_BASIC_STORAGE','save_copy','PLAINTEXT');
 
 
-- Index anlegen
DROP INDEX idx_doc_files;
 
CREATE INDEX idx_doc_files ON documents(FilePointer)  
             INDEXTYPE IS CTXSYS.CONTEXT 
             PARAMETERS ('FILTER CTXSYS.AUTO_FILTER  
                          LEXER gpi_lexer
                          STORAGE GPI_BASIC_STORAGE')
/

Leider gleich mal auf eine Bug gelaufen

Cursor von CTX_DOC.SNIPPET werden nicht geschlossen!

ORA-01000: maximum OPEN cursors exceeded

Bug 20892798 : MANY CURSORS OPENED WHEN USING FORWARD INDEXING LEADING TO ORA-01000 ERROR ⇒ Product Version 12.1.0.2

Kein FIX öffentlich – Falls gleicher Fehler Auftritt erneuten Bug mit Prio eröffnen und Druck machen!


Oracle Text Log und Trace anlegen

Um besser zu verstehen wie das Ganze funktioniert einen Trace anlegen mit CTX_OUTPUT.

Dazu:

  • Log einschalten mit CTX_OUTPUT.START_LOG(logfile in varchar2, overwrite in default true)
    • Logfile liegt unter %ORACLE_HOME%ctx\log\
  • Trace für Auto Filter aktivieren mit CTX_OUTPUT.ADD_TRACE(trace_id BINARY_INTEGER)
  • Operationen durchführen
  • Trace wieder ausschalten
  • Log wieder ausschalten mit ctx_output.end_log

Beispiel:

sqlplus / AS sysdba
 
GRANT CTXAPP TO gpi;
 
CONNECT gpi/gpi
 
#Log einschalten 
 
BEGIN
  CTX_OUTPUT.START_LOG('gpi_log_07_01_2016.log');
END;
/
 
 
#2=TRACE_IDX_AUTO_FILTER
 
BEGIN
 ctxsys.CTX_OUTPUT.ADD_TRACE(trace_id => CTX_OUTPUT.TRACE_IDX_AUTO_FILTER);
END;
/
 
#Was ist gesetzt überprüfen mit:
SELECT * FROM ctx_trace_values;
 
 
# Was tun
DROP INDEX idx_documents_docs;
#neu anlegen
CREATE INDEX ....
 
 
 
#Trace Event wieder entfernen
BEGIN
 ctxsys.CTX_OUTPUT.REMOVE_TRACE(trace_id => CTX_OUTPUT.TRACE_IDX_AUTO_FILTER);
END;
/
 
#Log wieder ausschalten
 
EXEC ctx_output.end_log

Das Logfile liegt dann unter %ORACLE_HOME%ctx\log\

Siehe auch für die Fehlersuche:

  • MOS Node: Oracle Text Product Info Center Diagnostics Master Note (Doc ID 1087143.1)

Quellen

Diese Website verwendet Cookies. Durch die Nutzung der Website stimmen Sie dem Speichern von Cookies auf Ihrem Computer zu. Außerdem bestätigen Sie, dass Sie unsere Datenschutzbestimmungen gelesen und verstanden haben. Wenn Sie nicht einverstanden sind, verlassen Sie die Website.Weitere Information
"Autor: Gunther Pipperr"
dba/oracle_text_index_binary_data.txt · Zuletzt geändert: 2016/05/11 19:41 von gpipperr