cds-104/fuzzy_volltext_mehrdimensionales/postgreSQL_Vertiefung_CDS104_FS26.sql
2026-04-16 14:38:02 +02:00

154 lines
5.0 KiB
SQL

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