Inhaltsverzeichnis
Oracle Text - In Texten suchen
Einführung in Oracle Text ⇒ Oracle Text - Volltext Suche über Text Dokumente
Nach der Indizierung der Daten kann nun in den Daten gesucht werden. Für die Suche steht der CONTAINS Operator zur Verfügung.
Syntax:
SELECT id , SCORE(1) FROM TEXTE WHERE CONTAINS(COLUMN, 'query_string',1)>0 /
Mit der SCORE Funktion (die Nummer 1 ist hier die gleiche Nummer wie der dritte CONTAINS Parameter) kann die Relevanz eines Treffers angezeigt werden.
Hier wurde das von Oracle auch mal beschrieben ⇒ (Salton's formula) Scoring Algorithm for Word Queries Oracle 12c
Der Score ist die term frequency–inverse document frequency im Verhältnis von 1 bis 100.
Ab Oracle 11 kann das Scoring verhalten beeinflusst werden:
DISCRETE Term vorhanden 100, falls nicht 0 OCCURRENCE Anzahl der Vorkommen RELEVANCE Standard-Relevanz-Ranking COMPLETION Ratio für SECTION Suche: Anzahl der der Treffer zu Anzahl aller Ausdrücke IGNORE Scoring des Terms ignorieren LOG,ABS und Rechenoperationen () für Gruppierung wie: SELECT id , SCORE(1) FROM TEXTE WHERE CONTAINS(COLUMN, 'DEFINESCORE(query_string, DISCRETE)',1)>0 /
siehe auch ⇒ https://docs.oracle.com/en/database/oracle/oracle-database/23/ccref/oracle-text-CONTAINS-query-operators.html
Test Daten anlegen
Im ersten Schritt legen wir einen Beispiel Text an um die wichtigsten Suchfunktionen zu erklären:
Anlegen der Beispieldaten und indizieren:
-- as sys -- grant rights to create the index CONNECT sys AS sysdba GRANT CTXAPP TO gpi CONNECT gpi/gpi CREATE TABLE texte ( id NUMBER(11) PRIMARY KEY, text varchar2(4000)); INSERT INTO texte VALUES (1,'Ein Hund steht neben der Hütte'); INSERT INTO texte VALUES (2,'Die liebsten Haustiere sind Katze und Hund'); INSERT INTO texte VALUES (3,'Die Katze auf dem Dach'); commit; -- Index Properties for the lexer -- exec ctx_ddl.drop_preference( 'gpi_lexer'); BEGIN ctx_ddl.create_preference( 'gpi_lexer', 'BASIC_LEXER' ); ctx_ddl.set_attribute ('gpi_lexer', 'INDEX_THEMES', 'YES'); -- nur 12c? ctx_ddl.set_attribute ('gpi_lexer', 'INDEX_STEMS', 'GERMAN_NEW'); -- 10/11 --ctx_ddl.set_attribute ('gpi_lexer', 'INDEX_STEMS', 'GERMAN'); END; / --Section group -- exec CTX_DDL.DROP_SECTION_GROUP('gpi_section'); BEGIN ctx_ddl.create_section_group ('gpi_section', 'NULL_SECTION_GROUP'); ctx_ddl.add_special_section ('gpi_section', 'SENTENCE'); ctx_ddl.add_special_section ('gpi_section', 'PARAGRAPH'); END; / -- create the index -- drop index idx_texte ; CREATE INDEX idx_texte ON texte(text) INDEXTYPE IS CTXSYS.CONTEXT PARAMETERS ('LEXER gpi_lexer SECTION GROUP gpi_section') / ------------------ -- check for errors SELECT COUNT(*) FROM ctx_user_index_errors /
Unsere Daten sehen dann so aus:
Exakte Wort-/Phrasensuche
Suche nach dem Wort in allen Texten:
SELECT id,text FROM texte WHERE contains(text, 'Hund')>0
Ergebnis:
- 1 Ein Hund steht neben der Hütte
- 2 Die liebsten Haustiere sind Katze und Hund
Logische Kombinationen “AND &”, “OR | ”, “NOT
Über die logischen Operatoren können Kombinationen von Wörtern gesucht werden.
SELECT * FROM texte WHERE contains(text,'Hund AND Katze')>0; SELECT * FROM texte WHERE contains(text,'Hund & Katze')>0;
Ergebnis:
- 2 Die liebsten Haustiere sind Katze und Hund
Die Suche nach dem Wort „AND“ ist dann allerdings nicht mehr möglich, ist quasi ein reserviertes Wort ( Fehler : DRG-50901: text query parser syntax error ).
Wildcard-Suche
Mit _ nach einem beliebigen Zeichen, mit % nach beliebig vielen Zeichen suchen:
SELECT * FROM texte WHERE contains(text, ‘Hu%d AND Hüt_e’) >0;
Ergebnis:
- 1 Ein Hund steht neben der Hütte
Wird viel am Anfang oder am Ende eines einzelnen Wortes mit einem Wildcard gesucht, lohnt es sich den Index um die Eigenschaft „prefix index“ (eine eigene Index Tabelle mit allen möglichen Wortfragmenten bis zu einer definierten Anzahl von Buchstaben) zu erweitern um die Performance bei der Suche zu verbessern.
Soundex - !
Nach einer ähnlichen Aussprache eines Wortes suchen, funktioniert am besten mit US Englisch in 7 Bit Darstellung, kann aber auch recht gute Ergebnisse mit europäischen Sprachen in 8Bit Darstellung erreichen.
SELECT * FROM texte WHERE contains(text, '!Haustire’ )>0;
Ergebnis:
- 2 Die liebsten Haustiere sind Katze und Hund
Vermutlich wird hier auf den klassischen Mit Soundex Wörter in der Datenbank vergleichen Algorithmus zurückgegriffen.
Fuzzy matching - ?
Der Fuzzy matching Algorithmus ist deutlich mächtiger als der statische Soundex Algorithmus, wertet aber auch die ähnliche Aussprache von Wörtern aus.
Es kann der ? Operator oder für mehr Parameter fuzzy(term, score, numresults, weight) verwendet werden.
-- Short Version SELECT * FROM texte WHERE contains(text, '?Hunt') >0; -- Details Version SELECT * FROM texte WHERE contains(text, 'fuzzy(Hunt, 50, 50, WEIGHT)') >0;
Ergebnis:
- 1 Ein Hund steht neben der Hütte
- 2 Die liebsten Haustiere sind Katze und Hund
Multilinguale Stammsuche - $
Mit der stem ($) Suche wird nach Wörtern mit der gleichen linguistischen Wurzel gesucht, in unsere Beispiel suchen wir nach „stehen“ der Basis von „steht“.
Der Oracle Text Stemmer basiert auf der Lösung von XSoft Division of Xerox Corporation und unterstütze mit dem BASIC_LEXER: Englisch, Französisch, Spanisch, Italienisch, Deutsch und Dänisch.
Aufruf:
SELECT * FROM texte WHERE contains(text, '$stehen' )>0
Das erwartete Ergebnis:
- 1 Ein Hund steht neben der Hütte
Damit das funkioniert muss aber diese Eigenschaft vor dem anlegen des Indexes definiert werden: EXEC ctx_ddl.set_attribute ('gpi_lexer', 'INDEX_STEMS', 'GERMAN');
Das Dicitonary für zum Beispiel Deutsch liegt hier: $ORACLE_HOME/ctx/data/delx/drde.dct und fehlt unter der Oracle XE Edition .-), daher funktioniert das auf Deutsch bei der Oracle XE auch nicht….
Near – Operator
Mit Near wird ein Score bzgl. des Abstands von zwei Wörtern in einen Text ermittelt.
Suche in der Nähe der Begriffe mit einem Radius von 2:
SELECT * FROM tab WHERE contains(text, 'near((Hund, Katze), 2)' )>0
Ergebnis:
- 2 Die liebsten Haustiere sind Katze und Hund
Suche in Sektionen, Sätzen und Paragraphen - WITHIN
Suche in Abschnitten wie ein Satz:
SELECT * FROM texte WHERE contains(text,'(Hund, Katze) WITHIN SENTENCE') >0
Ergebnis: Alle 3 Zeilen
Fehler: DRG-10837: section SENTENCE does not exist
Der Index muss natürlich auch entsprechend so aufgebaut werden, das Abschnitte erkannt werden können. Stichwort Section Group, siehe die beim Indexaufbau verwendeten Einstellungen.
Themen bezogene (Themes) Suche - about
SELECT * FROM texte WHERE contains(text, 'about(Hund)' )>0
Ergebnis:
- 1 Ein Hund steht neben der Hütte
- 2 Die liebsten Haustiere sind Katze und Hund
Auch hier verläßt einen die XE Edition mit Deutsch, Fehler DRG-11422: linguistic initialization failed DRG-11432: file error while accessing knowledge base, die passenden Dateien sind auf der Platte im Oracle Home nicht vorhanden.
Bzgl. theme Index siehe auch: Einen Oracle Theme Index aufbauen und Mit einem Thesaurus und Oracle Text arbeiten
Score bezogene Funktionen: accumulate, minus, weight
SELECT * FROM texte WHERE contains(text, 'Hund MINUS Katze') >0;
Ergebnis:
- 1 Ein Hund steht neben der Hütte
SELECT * FROM texte WHERE contains(text, 'Hund OR Katze *2') >0;
Ergebniss: Alle Zeilen in der Tabelle werden gefunden
Operationen auf Ergebnislisten: threshold (nur ab dem Score
SELECT * FROM texte WHERE contains(text, 'Hund > 3,5')>0
Ergebnis:
- 1 Ein Hund steht neben der Hütte
- 2 Die liebsten Haustiere sind Katze und Hund
ISO 2788 konformer Thesaurus - SYN, NT, BT
SELECT * FROM texte WHERE contains(text, 'SYN(Hund,TIERE)') >0
Der Thesaurus muss zuvor definiert werden, ansonsten wird die Fehlermeldung „DRG-11702: thesaurus TIERE does not exist“ aufgerufen.
Ein Thesaurus kann auch direkt abgefragt werden mit CTX_THES.<REGEL> wie :
SELECT CTX_THES.SYN('automobile','t_fahrzeuge') AS SYN FROM dual;
siehe dazu Mit einem Thesaurus und Oracle Text arbeiten