Inhaltsverzeichnis
Oracle Text - Die Treffer einer Oracle Volltext Abfrage in der Ergebnismenge optisch hervorheben
Ab 10g/11g/12c
Einführung in Oracle Text ⇒ Oracle Text - Volltext Suche über Text Dokumente
Nach dem ein Dokument mit einer Volltext Suche gefunden wurde, stellt sich natürlich die Frage, wo denn im Text etwas erkannt wurde.
Für die Aufbereitung der Trefferliste/Dokumentanzeige wird dazu das CTX_DOC Package eingesetzt.
Für einzelne Textabschnitt kann mit „CTX_DOC.HIGHLIGHT“ die Offset Position dazu bestimmt werden, oder mit CTX_DOC.SNIPPET ein Teil ausgeschnitten werden.
Ab 12c kann mit Forward Indexing das ganze auch noch beschleunigt werden, allerdings wird dann auch mehr Speicherplatz in der Datenbank benötigt.
Teilbereiche aus dem Dokument mit dem gefundenen Wort hervorheben
So kann zum Beispiel mit „CTX_DOC.SNIPPET“ der Treffer Text Abschnitt angezeigt werden:
--Session so setzen wie die Spalte in der Tabelle gefunden werden soll --Fehlt das, siehe folgender Fehler EXEC ctx_doc.set_key_type('ROWID'); -- Abfragen und Ergebniss mit ermitteln SELECT CTX_DOC.SNIPPET( index_name => 'IDX_DOC_FILES' ,textkey => rowid ,text_query => '?Hunt' ,starttag => '<span style="color:#034F84; background-color:#F7CAC9">' ,endtag => '</span>' ,separator => '<b>...</b>') AS textfragment FROM texte WHERE contains(text, '?Hunt') >0 /
Leider klappt das dann nicht, weil im ersten Test das setzen von „ctx_doc.set_key_type('ROWID') “ vergessen wurde! Der Fehler:
ERROR at line 1: ORA-29903: error in executing ODCIIndexFetch() routine ORA-20000: Oracle Text error: DRG-50857: oracle error in drvdoc.get_rowid ORA-01410: invalid ROWID ORA-06512: at "CTXSYS.DRUE", line 160 ORA-06512: at "CTXSYS.CTX_DOC", line 2606 ORA-06512: at line 1
Wird nur mit ID auf die PK Spalte verwiesen erhalten wir den folgenden Fehler:
ERROR at line 1: ORA-20000: Oracle Text error: DRG-10826: no document WITH the specified textkey IS found ORA-06512: at "CTXSYS.DRUE", line 160 ORA-06512: at "CTXSYS.CTX_DOC", line 2606 ORA-06512: at line 1
Hier lag der Fehler im falschen CTX Index Namen, gab mehrere davon .-(.
Wie muss das nun ohne Fehler aufgerufen werden?
Der Parameter „textkey“ kann entweder auf der RowID oder auf den Primary Key der Tabelle arbeiten.
Ist der PK aus mehreren Werten zusammengesetzt, muss mit CTX_DOC.PKENCODE der entsprechende Schlüssel aufgebaut werden.
Warum aber funktioniert das in den obigen Beispiel erst mal einfach nicht?
Lösungsmöglichkeiten:
- Überprüfen, ob auch der richtige Index referenziert wird, bei einem falschen Index wird dieser durchsucht aber der Key kann ja nicht passen (na hoffentlich!)
- Überprüfen, ob die richtige Methode für den Key Zugriff zuvor ausgewählt wurde
- exec ctx_doc.set_key_type('PRIMARY_KEY') (Default!) bei textkey ⇒ <PK_SPALTE>
- exec ctx_doc.set_key_type('ROWID') bei textkey ⇒ rowid
Das ganze Dokument als Text mit Markierung anzeigen
Hilfsfunktion zum Anzeigen eines ganzen Dokumentes:
CREATE OR REPLACE FUNCTION ctx_apex_markup ( p_pk varchar2 , p_queryString varchar2 , p_index_name varchar2 ) RETURN CLOB IS -- temporären Lob für das Ergebnis v_storage CLOB; BEGIN -- Wie soll der Parameter Text Key ausgewertet werden! ctx_doc.set_key_type('PRIMARY_KEY'); -- Markup Funktion in Memory nützen ctx_doc.markup (index_name => UPPER(p_index_name) ,textkey => p_pk ,text_query => p_queryString ,restab => v_storage ,starttag => '<span style="color:#034F84; background-color:#F7CAC9">' ,endtag => '</span>'); RETURN v_storage; END ctx_apex_markup; /
Das Clob Dokument muss natürlich von der rufenden Umgebung auch verarbeitete werden können, ab 32K muss hier also noch etwas mehr getan werden.
Möchte man die Starttag/endtag Parameter nicht angeben, kann auch mit dem Parameter „tagset ⇒ 'HTML_NAVIGATE'“ gearbeitet werden.
Bei kurzen Texten klappt das aber so ganz gut:
SELECT ctx_apex_markup( p_index_name => 'IDX_TEXTE' , p_pk => to_char(ID) , p_queryString => '?Hunt' ) AS text FROM texte WHERE contains(text, '?Hunt') >0 /
Oracle 12c New Feature - Forward Indexing
Um das Higlighting, Snippet und das Markup zu beschleunigen wird beim Anlegen des Oracle Text Domain Indexes eine neue zusätzliche Tabelle eingeführt, die $O, ein Mapping auf die $I.
Parameter setzen:
EXEC ctx_ddl.create_preference('GPI_STORAGE ', 'BASIC_STORAGE' ) EXEC ctx_ddl.set_attribute ('GPI_STORAGE ', 'FORWARD_INDEX', 'TRUE' ) EXEC ctx_ddl.set_attribute ('GPI_STORAGE ', 'SAVE_COPY', 'PLAINTEXT' )
siehe auch Oracle Text für die Indizierung binärer Daten verwenden
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
Kein FIX öffentlich – Falls gleicher Fehler Auftritt erneuten Bug mit Prio eröffnen und Druck machen!
Quellen
Oracle Doku:
- CTX_DOC Package ⇒ https://docs.oracle.com/database/121/CCREF/cdocpkg.htm