=====Oracle Text - Die Treffer einer Oracle Volltext Abfrage in der Ergebnismenge optisch hervorheben====
**Ab 10g/11g/12c**
Einführung in Oracle Text => [[dba: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 [[https://docs.oracle.com/database/121/CCREF/cdocpkg.htm#CCREF0700|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 => ''
,endtag => ''
,separator => '...') 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 =>
* 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 => ''
,endtag => '');
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 [[dba:oracle_text_index_binary_data#oracle_12c_new_storage_feature_-_plain_text_in_d_speichern_-_forward_indexing_in_o_ablegen|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