-- postgreSQL Volltext und Mehrdimensionales -- Volltext --------Intro ergänzen --------- -- Als eine Übung zum Spielen mit Multidimensionalität sehen wir uns die cube extension (https://www.postgresql.org/docs/current/cube.html) in postgreSQL an. -- Als Grundlage dient uns das Buch "7 Wochen, 7 Datenbanken" auf den Seiten 39 bis 41 (Vorbereitung), 41-51 (Volltext) und 51-53 (Mehrdimensionales). ------------------------------------------------- -- Zunächst in PostgeSQL eine neue Datenbank mit dem Namen "7Wochen" anlegen. -- dort zunächst die notwendigen Extensions einbinden. -- Sollten bestimmte extensions in der Installation nicht vorhanden sein müssen diese zunächst in folgendes Verzeichnis kopiert werden: ...\PostgreSQL\17\share\extension -- Der Befehle zum Hinterlegen der extensions lauten (Query Tool benutzen): CREATE EXTENSION IF NOT EXISTS tablefunc; CREATE EXTENSION IF NOT EXISTS dict_xsyn; CREATE EXTENSION IF NOT EXISTS fuzzystrmatch; CREATE EXTENSION IF NOT EXISTS pg_trgm; CREATE EXTENSION IF NOT EXISTS cube; ------------------------------------------------- -- Anlegen der nötigen Tabellen: -- Hierzu verwenden wir die Datei create_movies.sql, die in Moodle zu finden ist. ------------------------------------------------- -- Als nächstes müssen die Tabellen befüllt werden. -- Hierzu verwenden wir die Datei movies_data.sql, die in Moodle zu finden ist. -- Nun ist alles bereit und wir können die Aufgaben durchgehen. ------------------------------------------------- -- Volltext -- Genauere Beschreibungen im Buch Seiten 41-51 -- UNSCHARFE SUCHE -- LIKE und ILIKE SELECT title FROM movies WHERE title ILIKE 'stardust%'; SELECT title FROM movies WHERE title ILIKE 'stardust_%'; -- Reguläre Ausdrücke -- ~ Regulärer Ausdruck, hier 'the', ^ steht für am Anfang und .* entspricht dem % aus LIKE, also eine beliebige Kette von Zeichen. -- ! steht für "nicht" und * für "schreibungsunabhängig, also nicht case sensitive. SELECT COUNT(*) FROM movies WHERE title !~* '^the.*'; -- oder SELECT title FROM movies WHERE title !~* '^the.*'; -- Levenshtein (extension: fuzzystrmatch) SELECT levenshtein('bat', 'fads'); SELECT levenshtein('bat', 'fad') fad, levenshtein('bat', 'fat') fat, levenshtein('bat', 'bat') bat; SELECT movie_id, title FROM movies WHERE levenshtein(lower(title), lower('a hard day nght')) <= 3; -- Trigramm (extension: pg_trgm) SELECT show_trgm('Avatar'); CREATE INDEX movies_title_trigram ON movies USING gist (title gist_trgm_ops); SELECT title FROM movies WHERE title % 'Avatre'; -- VOLLTEXTSUCHE -- TSVector, TSQuery SELECT title FROM movies WHERE title @@ 'night & day'; -- Beispiel für Aufteilung in Vectoren und Queries: SELECT to_tsvector('A Hard Day''s Night'), to_tsquery('english', 'night & day'); -- Beispiel für Anpassungen der Wörterbücher SELECT to_tsvector('english','A Hard Day''s Night'); SELECT to_tsvector('simple','A Hard Day''s Night'); -- METAPHONE -- Erster Versuch SELECT * FROM actors WHERE name = 'Broos Wils'; -- Mit Hilfe von Triagramm SELECT * FROM actors WHERE name % 'Broos Wils'; -- Mit Metaphone, 6 ist hier die Länge des Ausgabestrings in Lautsprache SELECT title FROM movies NATURAL JOIN movies_actors NATURAL JOIN actors WHERE metaphone(name, 6) = metaphone('Broos Wils', 6); -- Beispiel für verschiedene Umwandlungen SELECT name, dmetaphone(name), dmetaphone_alt(name), metaphone (name, 8), soundex(name) FROM actors; -- STRING-MATCHES KOMBINIEREN -- Beispiel: SELECT * FROM actors WHERE metaphone(name, 8) % metaphone('Robin Williams', 8) ORDER BY levenshtein(lower('Robin Williams'), lower(name)); ------------------------------------------------- -- Mehrdimensionales -- Genauere Beschreibungen im Buch Seiten 51-53 -- cube_ur_coord ist ein Befehl aus der cube-extension (https://www.postgresql.org/docs/current/cube.html) -- Jeder movie hat also einen Wert bei insgesamt 18 genres SELECT name, cube_ur_coord('(0,7,0,0,0,0,0,0,0,7,0,0,0,0,10,0,0,0)', position) as score FROM genres g WHERE cube_ur_coord('(0,7,0,0,0,0,0,0,0,7,0,0,0,0,10,0,0,0)', position) >0; -- Hier werden Distanzen berechnet und danach sortiert SELECT *, cube_distance(genre, '(0,7,0,0,0,0,0,0,0,7,0,0,0,0,10,0,0,0)') dist FROM movies ORDER BY dist; -- Beispiel cube_enlarge: -- Ausgangspunkt ist (1,1), es wird um 1 erweitert und das für 2 Dimensionen SELECT cube_enlarge('(1,1)', 1, 2); -- Nun wird das ganze um die 18 genres aufgebaut mit einer Erweiterung um 5 in 18 dimensionen SELECT title, cube_distance(genre, '(0,7,0,0,0,0,0,0,0,7,0,0,0,0,10,0,0,0)') dist FROM movies WHERE cube_enlarge('(0,7,0,0,0,0,0,0,0,7,0,0,0,0,10,0,0,0)'::cube, 6,18) @> genre ORDER BY dist; -- Hier wird nun noch eine Unterabfrage integriert, die es erlaubt über den Filmnamen zu suchen SELECT m.movie_id, m.title FROM movies m, (SELECT genre, title FROM movies WHERE title = 'Mad Max') s WHERE cube_enlarge(s.genre, 5, 18) @> m.genre AND s.title <> m.title ORDER BY cube_distance(m.genre, s.genre) LIMIT 10; -- The end