perf(db): set-based rank 4 and filters in search_catalog_games, harden tests (KAT-01, 3a)
Rank 4 and the genre/mechanic filters ran a correlated subplan per game (13 s at 10 000 games). Now: one set-based word coverage, filters as one hashed IN set, 'like all' patterns, similarity only for hits. Adds pgTAP cases found by mutation testing (paging by relevance, alt title choice, duplicate words, mechanic duplicates) and a Deno case for mark characters. Refs #3 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
976fbe9fe1
commit
683b5c830e
3 changed files with 123 additions and 45 deletions
|
|
@ -305,6 +305,7 @@ Deno.test("alt_titles: Fehler anderer Art nennen die Zeilennummer", async () =>
|
|||
|
||||
Deno.test("approxNormalize: Marken- und Schutzzeichen, Akzente, ß, Æ, Sonderzeichen", () => {
|
||||
assert.equal(approxNormalize("CATAN®"), "catan");
|
||||
assert.equal(approxNormalize("Spiel™Ding"), "spielding"); // Schutzzeichen werden entfernt, nicht zum Trenner (wie search_normalize)
|
||||
assert.equal(approxNormalize("Café Größe"), "cafe grosse");
|
||||
assert.equal(approxNormalize("Æon’s End"), "aeon s end");
|
||||
assert.equal(approxNormalize("7 Wonders: Duel"), "7 wonders duel");
|
||||
|
|
|
|||
|
|
@ -152,7 +152,8 @@ declare
|
|||
v_offset integer := coalesce(p_offset, 0);
|
||||
v_q text;
|
||||
v_qc text;
|
||||
v_words text[] := '{}';
|
||||
v_words text[] := '{}'::text[];
|
||||
v_patterns text[] := '{}'::text[]; -- '%wort%' je Suchwort, für like all
|
||||
v_has_query boolean := false;
|
||||
v_genres uuid[];
|
||||
v_mechanics uuid[];
|
||||
|
|
@ -189,6 +190,7 @@ begin
|
|||
v_qc := replace(v_q, ' ', '');
|
||||
v_words := coalesce(
|
||||
array(select distinct w from unnest(string_to_array(v_q, ' ')) as w where char_length(w) >= 2), '{}');
|
||||
v_patterns := array(select '%' || w || '%' from unnest(v_words) as w);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
|
|
@ -215,10 +217,10 @@ begin
|
|||
where (p_players is null or (c.min_players <= p_players and p_players <= c.max_players))
|
||||
and (p_max_minutes is null or coalesce(c.max_minutes, c.min_minutes) <= p_max_minutes)
|
||||
and (p_age is null or c.min_age <= p_age)
|
||||
and (v_genre_n = 0 or (select count(*) from public.game_genres gg
|
||||
where gg.game_id = c.id and gg.genre_id = any (v_genres)) = v_genre_n)
|
||||
and (v_mech_n = 0 or (select count(*) from public.game_mechanics gm
|
||||
where gm.game_id = c.id and gm.mechanic_id = any (v_mechanics)) = v_mech_n)
|
||||
and (v_genre_n = 0 or c.id in (select gg.game_id from public.game_genres gg where gg.genre_id = any (v_genres)
|
||||
group by gg.game_id having count(*) = v_genre_n))
|
||||
and (v_mech_n = 0 or c.id in (select gm.game_id from public.game_mechanics gm where gm.mechanic_id = any (v_mechanics)
|
||||
group by gm.game_id having count(*) = v_mech_n))
|
||||
order by g.title_search collate "C", c.id
|
||||
limit v_limit offset v_offset
|
||||
) s
|
||||
|
|
@ -235,10 +237,10 @@ begin
|
|||
where (p_players is null or (c.min_players <= p_players and p_players <= c.max_players))
|
||||
and (p_max_minutes is null or coalesce(c.max_minutes, c.min_minutes) <= p_max_minutes)
|
||||
and (p_age is null or c.min_age <= p_age)
|
||||
and (v_genre_n = 0 or (select count(*) from public.game_genres gg
|
||||
where gg.game_id = c.id and gg.genre_id = any (v_genres)) = v_genre_n)
|
||||
and (v_mech_n = 0 or (select count(*) from public.game_mechanics gm
|
||||
where gm.game_id = c.id and gm.mechanic_id = any (v_mechanics)) = v_mech_n)
|
||||
and (v_genre_n = 0 or c.id in (select gg.game_id from public.game_genres gg where gg.genre_id = any (v_genres)
|
||||
group by gg.game_id having count(*) = v_genre_n))
|
||||
and (v_mech_n = 0 or c.id in (select gm.game_id from public.game_mechanics gm where gm.mechanic_id = any (v_mechanics)
|
||||
group by gm.game_id having count(*) = v_mech_n))
|
||||
),
|
||||
-- Kandidaten-Titel: Haupttitel (alt_title null) und alle alternativen Titel
|
||||
cand as (
|
||||
|
|
@ -247,50 +249,72 @@ begin
|
|||
select b.id, a.title_search, a.title
|
||||
from base b join public.game_alt_titles a on a.game_id = b.id
|
||||
),
|
||||
-- Relevanzstufe je Kandidaten-Titel (null = kein Titeltreffer)
|
||||
-- Relevanzstufe je Kandidaten-Titel (null = kein Titeltreffer). Nur günstige Vergleiche; die teure
|
||||
-- Trigramm-Ähnlichkeit wird erst für die Treffer berechnet (sims, alt_pick).
|
||||
ranked as (
|
||||
select t.id, t.ts, t.alt_title,
|
||||
case
|
||||
when t.ts = v_q or replace(t.ts, ' ', '') = v_qc then 0
|
||||
-- Stufe 0: gleich dem Suchbegriff (auch ohne Leerzeichen gleich; das schließt ts = v_q ein)
|
||||
when replace(t.ts, ' ', '') = v_qc then 0
|
||||
when t.ts like v_q || '%' then 1
|
||||
when t.ts like '% ' || v_q || '%' then 2
|
||||
when replace(t.ts, ' ', '') like '%' || v_qc || '%'
|
||||
or (cardinality(v_words) > 0
|
||||
and not exists (select 1 from unnest(v_words) as w where t.ts not like '%' || w || '%'))
|
||||
or (cardinality(v_patterns) > 0 and t.ts like all (v_patterns))
|
||||
then 3
|
||||
end as rk,
|
||||
extensions.similarity(t.ts, v_q) as sim
|
||||
end as rk
|
||||
from cand t
|
||||
),
|
||||
agg as (
|
||||
select r.id,
|
||||
min(r.rk) as best_rk,
|
||||
min(r.rk) filter (where r.alt_title is null) as main_rk,
|
||||
min(r.rk) filter (where r.alt_title is not null) as alt_rk,
|
||||
(array_agg(r.alt_title order by r.rk, r.sim desc nulls last, r.ts, r.alt_title)
|
||||
filter (where r.alt_title is not null and r.rk is not null))[1] as alt_title,
|
||||
max(r.sim) as sim
|
||||
min(r.rk) filter (where r.alt_title is not null) as alt_rk
|
||||
from ranked r
|
||||
group by r.id
|
||||
),
|
||||
-- der alternative Titel mit der besten Stufe (bei Gleichstand: größte Ähnlichkeit, dann Schreibweise)
|
||||
alt_pick as (
|
||||
select distinct on (r.id) r.id, r.alt_title
|
||||
from ranked r
|
||||
where r.alt_title is not null and r.rk is not null
|
||||
order by r.id, r.rk, extensions.similarity(r.ts, v_q) desc, r.ts, r.alt_title
|
||||
),
|
||||
-- Rang 4: welches Suchwort kommt in welchem Spiel in einem Titel oder einem Verlagsnamen vor?
|
||||
-- (als Mengenoperation statt korrelierter Unterabfrage je Spiel: sonst wächst die Zeit quadratisch)
|
||||
word_hits as (
|
||||
select r.id, w.w from ranked r cross join unnest(v_words) as w(w) where r.ts like '%' || w.w || '%'
|
||||
union
|
||||
select gp.game_id, w.w
|
||||
from public.publishers p
|
||||
join public.game_publishers gp on gp.publisher_id = p.id
|
||||
cross join unnest(v_words) as w(w)
|
||||
where p.name_search like '%' || w.w || '%'
|
||||
),
|
||||
word_cover as (
|
||||
select wh.id, count(*) as n from word_hits wh group by wh.id
|
||||
),
|
||||
hit as (
|
||||
select b.*, a.best_rk, a.main_rk, a.alt_rk, a.alt_title, a.sim
|
||||
select b.*, a.best_rk, a.main_rk, a.alt_rk, ap.alt_title
|
||||
from base b
|
||||
join agg a on a.id = b.id
|
||||
left join alt_pick ap on ap.id = b.id
|
||||
left join word_cover wc on wc.id = b.id
|
||||
where a.best_rk is not null
|
||||
-- Rang 4: jedes Wort kommt in einem Titel oder einem Verlagsnamen des Spiels vor
|
||||
or (cardinality(v_words) > 0
|
||||
and not exists (
|
||||
select 1 from unnest(v_words) as w
|
||||
where not (exists (select 1 from ranked r2 where r2.id = b.id and r2.ts like '%' || w || '%')
|
||||
or exists (select 1 from public.game_publishers gp
|
||||
join public.publishers p on p.id = gp.publisher_id
|
||||
where gp.game_id = b.id and p.name_search like '%' || w || '%'))))
|
||||
or (cardinality(v_words) > 0 and wc.n = cardinality(v_words))
|
||||
),
|
||||
-- Ähnlichkeit (zweites Sortierkriterium): die höchste über Haupttitel und alle alternativen Titel
|
||||
sims as (
|
||||
select r.id, max(extensions.similarity(r.ts, v_q)) as sim
|
||||
from ranked r
|
||||
join hit h on h.id = r.id
|
||||
group by r.id
|
||||
),
|
||||
paged as (
|
||||
select h.*, coalesce(h.best_rk, 4) as rk, count(*) over () as total
|
||||
select h.*, sm.sim, coalesce(h.best_rk, 4) as rk, count(*) over () as total
|
||||
from hit h
|
||||
order by coalesce(h.best_rk, 4), h.sim desc nulls last, h.title_search collate "C", h.id
|
||||
join sims sm on sm.id = h.id
|
||||
order by coalesce(h.best_rk, 4), sm.sim desc nulls last, h.title_search collate "C", h.id
|
||||
limit v_limit offset v_offset
|
||||
)
|
||||
select s.id, s.title, s.year, s.min_players, s.max_players, s.min_minutes, s.max_minutes, s.min_age,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
-- Ohne Suchbegriff wird nur auf Fixture-IDs geprüft (Hilfsfunktion pg_temp.hits blättert durch).
|
||||
-- Die Include-Dateien in ../support/ (\ir) erzeugt supabase/catalog/build_startbestand.ts.
|
||||
begin;
|
||||
select plan(201);
|
||||
select plan(211);
|
||||
|
||||
insert into auth.users (id, email, raw_user_meta_data) values
|
||||
('11111111-1111-1111-1111-111111111111', 'anna@example.com', '{"age_confirmed":"true","terms_accepted":"true","terms_version":"test","display_name":"Anna"}'),
|
||||
|
|
@ -116,13 +116,14 @@ select results_eq($$select polcmd::text, array(select rolname from pg_roles wher
|
|||
insert into public.genres (id, name_de, name_en) values
|
||||
('f9000000-0000-0000-0000-0000000000e1', 'Qxz Genre A', 'Qxz genre A'),
|
||||
('f9000000-0000-0000-0000-0000000000e2', 'Qxz Genre B', 'Qxz genre B'),
|
||||
('f9000000-0000-0000-0000-0000000000e3', 'Qxz Genre Q', 'Qxz genre Q');
|
||||
('f9000000-0000-0000-0000-0000000000e3', 'Qxz Genre Q', 'Qxz genre Q'),
|
||||
('f9000000-0000-0000-0000-0000000000e4', 'Qxz Genre R', 'Qxz genre R');
|
||||
insert into public.mechanics (id, name_de, name_en) values
|
||||
('f9000000-0000-0000-0000-0000000000d1', 'Qxz Mechanik A', 'Qxz mechanic A'),
|
||||
('f9000000-0000-0000-0000-0000000000d2', 'Qxz Mechanik B', 'Qxz mechanic B');
|
||||
insert into public.publishers (id, name) values
|
||||
('f9000000-0000-0000-0000-0000000000b1', 'Qxz Hersteller Eins'),
|
||||
('f9000000-0000-0000-0000-0000000000b2', 'Qxz Hersteller Zwei'),
|
||||
('f9000000-0000-0000-0000-0000000000b2', 'Qxz Hersteller Eins'),
|
||||
('f9000000-0000-0000-0000-0000000000b1', 'Qxz Hersteller Zwei'),
|
||||
('f9000000-0000-0000-0000-0000000000b3', 'Qxz Zorb Verlag');
|
||||
|
||||
insert into public.games (id, title, visibility) values
|
||||
|
|
@ -144,7 +145,18 @@ insert into public.games (id, title, visibility) values
|
|||
('f9000000-0000-0000-0000-000000000016', 'QXZ CATAN®', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000040', 'Qxz Doppelspiel', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000041', 'Qxz Einzelspiel', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000060', 'Qxz Cabin', 'catalog');
|
||||
('f9000000-0000-0000-0000-000000000060', 'Qxz Cabin', 'catalog'),
|
||||
-- Sortierung ist binär (collate "C"): "qxz b" kommt vor "qxzab". Hinweis: Mit ICU-Sortierung (wie lokal) gilt das auch
|
||||
-- ohne collate "C"; der Test ist dort nicht mutationsempfindlich und schützt vor libc-Sortierungen, die Leerzeichen ignorieren.
|
||||
('f9000000-0000-0000-0000-000000000081', 'Qxzab', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000095', 'Qxz Zwilling', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000093', 'Qxz Zwilling', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000091', 'Qxz Zwilling', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000094', 'Qxz Zwilling', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000092', 'Qxz Zwilling', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000090', 'Qxz Zwilling', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000017', 'Qxz Wanderer', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000080', 'Qxz B', 'catalog');
|
||||
|
||||
-- Filter-Fixtures (20-25); 22 ohne jede Angabe, 23 nur max_minutes, 24 nur min_minutes
|
||||
insert into public.games (id, title, visibility, min_players, max_players, min_minutes, max_minutes, min_age) values
|
||||
|
|
@ -161,7 +173,9 @@ insert into public.game_genres (game_id, genre_id) values
|
|||
('f9000000-0000-0000-0000-000000000022', 'f9000000-0000-0000-0000-0000000000e1'),
|
||||
('f9000000-0000-0000-0000-000000000025', 'f9000000-0000-0000-0000-0000000000e2'),
|
||||
('f9000000-0000-0000-0000-000000000005', 'f9000000-0000-0000-0000-0000000000e3'),
|
||||
('f9000000-0000-0000-0000-000000000060', 'f9000000-0000-0000-0000-0000000000e3');
|
||||
('f9000000-0000-0000-0000-000000000060', 'f9000000-0000-0000-0000-0000000000e3'),
|
||||
('f9000000-0000-0000-0000-000000000080', 'f9000000-0000-0000-0000-0000000000e4'),
|
||||
('f9000000-0000-0000-0000-000000000081', 'f9000000-0000-0000-0000-0000000000e4');
|
||||
insert into public.game_mechanics (game_id, mechanic_id) values
|
||||
('f9000000-0000-0000-0000-000000000020', 'f9000000-0000-0000-0000-0000000000d1'),
|
||||
('f9000000-0000-0000-0000-000000000021', 'f9000000-0000-0000-0000-0000000000d1'),
|
||||
|
|
@ -170,10 +184,10 @@ insert into public.game_mechanics (game_id, mechanic_id) values
|
|||
|
||||
-- Verlage: 01 und 30 bei Eins; 40 bei Eins und Zwei; 41 bei Zwei; 06 bei "Qxz Zorb Verlag"
|
||||
insert into public.game_publishers (game_id, publisher_id) values
|
||||
('f9000000-0000-0000-0000-000000000001', 'f9000000-0000-0000-0000-0000000000b1'),
|
||||
('f9000000-0000-0000-0000-000000000040', 'f9000000-0000-0000-0000-0000000000b2'),
|
||||
('f9000000-0000-0000-0000-000000000001', 'f9000000-0000-0000-0000-0000000000b2'),
|
||||
('f9000000-0000-0000-0000-000000000040', 'f9000000-0000-0000-0000-0000000000b1'),
|
||||
('f9000000-0000-0000-0000-000000000041', 'f9000000-0000-0000-0000-0000000000b2'),
|
||||
('f9000000-0000-0000-0000-000000000040', 'f9000000-0000-0000-0000-0000000000b2'),
|
||||
('f9000000-0000-0000-0000-000000000041', 'f9000000-0000-0000-0000-0000000000b1'),
|
||||
('f9000000-0000-0000-0000-000000000006', 'f9000000-0000-0000-0000-0000000000b3');
|
||||
|
||||
-- Ausgeblendet, zusammengeführt, privat
|
||||
|
|
@ -185,8 +199,8 @@ insert into public.games (id, title, visibility, owner_id) values
|
|||
('f9000000-0000-0000-0000-000000000032', 'Qxz Privat', 'private', '11111111-1111-1111-1111-111111111111'),
|
||||
('f9000000-0000-0000-0000-000000000033', 'QXZ ZORB', 'private', '22222222-2222-2222-2222-222222222222');
|
||||
insert into public.game_publishers (game_id, publisher_id) values
|
||||
('f9000000-0000-0000-0000-000000000030', 'f9000000-0000-0000-0000-0000000000b1'),
|
||||
('f9000000-0000-0000-0000-000000000033', 'f9000000-0000-0000-0000-0000000000b1');
|
||||
('f9000000-0000-0000-0000-000000000030', 'f9000000-0000-0000-0000-0000000000b2'),
|
||||
('f9000000-0000-0000-0000-000000000033', 'f9000000-0000-0000-0000-0000000000b2');
|
||||
|
||||
-- Bilder: 50 mit Quelle ohne Erlaubnis (maskiert), 51 manuell gepflegt, 52 ohne Quelle
|
||||
insert into public.games (id, title, visibility, image_path, catalog_source_id, source_ref) values
|
||||
|
|
@ -211,18 +225,22 @@ insert into public.game_alt_titles (id, game_id, locale, title) values
|
|||
('f9000000-0000-0000-0000-0000000000a6', 'f9000000-0000-0000-0000-000000000030', 'de', 'Qxz Verborgen Alt'),
|
||||
('f9000000-0000-0000-0000-0000000000a7', 'f9000000-0000-0000-0000-000000000031', 'de', 'Qxz Verschmolzen Alt'),
|
||||
('f9000000-0000-0000-0000-0000000000a8', 'f9000000-0000-0000-0000-000000000032', 'de', 'Qxz Privat Alt'),
|
||||
('f9000000-0000-0000-0000-0000000000a9', 'f9000000-0000-0000-0000-000000000033', 'en', 'Qxz Bens Alt');
|
||||
('f9000000-0000-0000-0000-0000000000a9', 'f9000000-0000-0000-0000-000000000033', 'en', 'Qxz Bens Alt'),
|
||||
-- drei Treffer-Titel für "qxz nomad": Stufe 2, Stufe 1 (länger, weniger ähnlich), Stufe 1 (kürzer, ähnlicher)
|
||||
('f9000000-0000-0000-0000-0000000000c1', 'f9000000-0000-0000-0000-000000000017', 'de', 'Stern Qxz Nomad'),
|
||||
('f9000000-0000-0000-0000-0000000000c2', 'f9000000-0000-0000-0000-000000000017', 'en', 'Qxz Nomad Sternenwanderer'),
|
||||
('f9000000-0000-0000-0000-0000000000c3', 'f9000000-0000-0000-0000-000000000017', 'de', 'Qxz Nomadisch');
|
||||
|
||||
select is((select title_search from public.games where id = 'f9000000-0000-0000-0000-000000000014'), 'qxz aeon s end',
|
||||
'KAT-01 Kriterium 1: games.title_search wird beim Anlegen gefüllt');
|
||||
select is((select title_search from public.game_alt_titles where id = 'f9000000-0000-0000-0000-0000000000a5'), 'qxz einzigartig alt',
|
||||
'KAT-01 Kriterium 2: game_alt_titles.title_search wird gefüllt');
|
||||
select is((select name_search from public.publishers where id = 'f9000000-0000-0000-0000-0000000000b2'), 'qxz hersteller zwei',
|
||||
select is((select name_search from public.publishers where id = 'f9000000-0000-0000-0000-0000000000b1'), 'qxz hersteller zwei',
|
||||
'KAT-01 Kriterium 3: publishers.name_search wird gefüllt');
|
||||
update public.publishers set name = 'Qxz Hersteller Zwei & Söhne' where id = 'f9000000-0000-0000-0000-0000000000b2';
|
||||
select is((select name_search from public.publishers where id = 'f9000000-0000-0000-0000-0000000000b2'), 'qxz hersteller zwei sohne',
|
||||
update public.publishers set name = 'Qxz Hersteller Zwei & Söhne' where id = 'f9000000-0000-0000-0000-0000000000b1';
|
||||
select is((select name_search from public.publishers where id = 'f9000000-0000-0000-0000-0000000000b1'), 'qxz hersteller zwei sohne',
|
||||
'KAT-01: publishers.name_search folgt einer Namensänderung');
|
||||
update public.publishers set name = 'Qxz Hersteller Zwei' where id = 'f9000000-0000-0000-0000-0000000000b2';
|
||||
update public.publishers set name = 'Qxz Hersteller Zwei' where id = 'f9000000-0000-0000-0000-0000000000b1';
|
||||
|
||||
-- Hilfsfunktion: alle Fixture-Treffer durchblättern (nur als postgres, für Abfragen ohne Suchbegriff)
|
||||
create function pg_temp.hits(p_query text default null, p_players smallint default null, p_max_minutes smallint default null,
|
||||
|
|
@ -257,6 +275,28 @@ select results_eq($$select id, match_rank::int from public.search_catalog_games(
|
|||
select results_eq($$select id from public.search_catalog_games('qxz twin')$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000007'::uuid), ('f9000000-0000-0000-0000-000000000008')$$,
|
||||
'KAT-01 Kriterium 5: bei völligem Gleichstand entscheidet die ID (stabile Reihenfolge)');
|
||||
select results_eq($$select id from public.search_catalog_games('qxz zorb', null, null, null, null, null, 4, 0)$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000001'::uuid), ('f9000000-0000-0000-0000-000000000002'), ('f9000000-0000-0000-0000-000000000003'), ('f9000000-0000-0000-0000-000000000004')$$,
|
||||
'KAT-01 Kriterium 5: die erste Seite enthält die relevantesten Treffer (Stufe, dann Ähnlichkeit), nicht die ersten nach Titel');
|
||||
select results_eq($$select id from public.search_catalog_games('qxz zorb', null, null, null, null, null, 2, 0)
|
||||
union all select id from public.search_catalog_games('qxz zorb', null, null, null, null, null, 2, 2)
|
||||
union all select id from public.search_catalog_games('qxz zorb', null, null, null, null, null, 2, 4)$$,
|
||||
$$select id from public.search_catalog_games('qxz zorb')$$,
|
||||
'KAT-01 Kriterium 5: Seiten zu je zwei ergeben dieselbe Reihenfolge wie die ganze Liste');
|
||||
select results_eq($$select id from public.search_catalog_games('qxz twin', null, null, null, null, null, 1, 0)
|
||||
union all select id from public.search_catalog_games('qxz twin', null, null, null, null, null, 1, 1)$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000007'::uuid), ('f9000000-0000-0000-0000-000000000008')$$,
|
||||
'KAT-01 Kriterium 5: bei völligem Gleichstand entscheidet die ID auch über die Seitengrenze hinweg');
|
||||
select results_eq($$select id from public.search_catalog_games('qxz zwilling', null, null, null, null, null, 3, 0)
|
||||
union all select id from public.search_catalog_games('qxz zwilling', null, null, null, null, null, 3, 3)$$,
|
||||
$$select id from public.games where title = 'Qxz Zwilling' order by id$$,
|
||||
'KAT-01 Kriterium 5: sechs gleich gute Treffer erscheinen seitenübergreifend in ID-Reihenfolge');
|
||||
select results_eq($$select id, match_rank::int, matched_alt_title from public.search_catalog_games('qxz nomad')$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000017'::uuid, 1, 'Qxz Nomadisch'::text)$$,
|
||||
'KAT-01 Kriterium 2: von mehreren treffenden alternativen Titeln gewinnt die beste Stufe, dann die größte Ähnlichkeit');
|
||||
select results_eq($$select id, match_rank::int, matched_alt_title from public.search_catalog_games('qxz einzig')$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000012'::uuid, 1, null::text)$$,
|
||||
'KAT-01 Kriterium 2: bei gleicher Stufe von Haupttitel und alternativem Titel gilt der Haupttitel (matched_alt_title null)');
|
||||
select is((select count(*) from public.search_catalog_games('qxz käse')), 1::bigint, 'KAT-01 Kriterium 1: Umlaut im Suchbegriff findet den Umlaut-Titel');
|
||||
select is((select count(*) from public.search_catalog_games('QXZ KASE GROSSE')), 1::bigint, 'KAT-01 Kriterium 1: ohne Umlaut und ß wird derselbe Titel gefunden');
|
||||
select is((select count(*) from public.search_catalog_games('qxz grösse')), 1::bigint, 'KAT-01 Kriterium 1: ö und ß in der Eingabe');
|
||||
|
|
@ -324,6 +364,9 @@ select results_eq($$select id, match_rank::int, publisher_names from public.sear
|
|||
select results_eq($$select id from public.search_catalog_games('qxz hersteller eins') order by id$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000001'::uuid), ('f9000000-0000-0000-0000-000000000040')$$,
|
||||
'KAT-01 Kriterium 3: der andere Verlag des Spiels findet es ebenfalls; ausgeblendete Spiele des Verlags fehlen');
|
||||
select results_eq($$select id, match_rank::int from public.search_catalog_games('qxz zorb zorb eins')$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000001'::uuid, 4)$$,
|
||||
'KAT-01 Kriterium 3: ein doppelt eingegebenes Wort zählt einfach (Verlagstreffer bleibt auffindbar)');
|
||||
select results_eq($$select id, match_rank::int from public.search_catalog_games('qxz zorb eins')$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000001'::uuid, 4)$$,
|
||||
'KAT-01 Kriterium 3: ein Wort aus dem Titel plus ein Wort aus dem Verlag (UND)');
|
||||
|
|
@ -367,6 +410,9 @@ select results_eq($$select h from pg_temp.hits(p_genre_ids := array['f9000000-00
|
|||
select results_eq($$select h from pg_temp.hits(p_mechanic_ids := array['f9000000-0000-0000-0000-0000000000d2']::uuid[]) h order by 1$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000021'::uuid), ('f9000000-0000-0000-0000-000000000025')$$,
|
||||
'KAT-01 Kriterium 4: Mechanik allein');
|
||||
select results_eq($$select h from pg_temp.hits(p_mechanic_ids := array['f9000000-0000-0000-0000-0000000000d2', 'f9000000-0000-0000-0000-0000000000d2']::uuid[]) h order by 1$$,
|
||||
$$select h from pg_temp.hits(p_mechanic_ids := array['f9000000-0000-0000-0000-0000000000d2']::uuid[]) h order by 1$$,
|
||||
'KAT-01 Kriterium 4: Duplikate im Mechanik-Array zählen einfach');
|
||||
select results_eq($$select h from pg_temp.hits(p_mechanic_ids := array['f9000000-0000-0000-0000-0000000000d1', 'f9000000-0000-0000-0000-0000000000d2']::uuid[]) h$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000021'::uuid)$$,
|
||||
'KAT-01 Spec-F1: zwei Mechaniken: nur Spiele mit beiden');
|
||||
|
|
@ -386,6 +432,13 @@ select results_eq($$select id, match_rank::int, matched_alt_title, total_count::
|
|||
$$values ('f9000000-0000-0000-0000-000000000060'::uuid, null::int, null::text, 2),
|
||||
('f9000000-0000-0000-0000-000000000005', null, null, 2)$$,
|
||||
'KAT-01 Kriterium 8: ohne Suchbegriff nach Titel sortiert, match_rank und matched_alt_title null');
|
||||
select results_eq($$select id from public.search_catalog_games(null, null, null, null, array['f9000000-0000-0000-0000-0000000000e3']::uuid[], null, 1, 0)
|
||||
union all select id from public.search_catalog_games(null, null, null, null, array['f9000000-0000-0000-0000-0000000000e3']::uuid[], null, 1, 1)$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000060'::uuid), ('f9000000-0000-0000-0000-000000000005')$$,
|
||||
'KAT-01 Kriterium 5: ohne Suchbegriff bestimmt der Titel (nicht die ID) auch die Seitengrenze');
|
||||
select results_eq($$select id from public.search_catalog_games(null, null, null, null, array['f9000000-0000-0000-0000-0000000000e4']::uuid[])$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000080'::uuid), ('f9000000-0000-0000-0000-000000000081')$$,
|
||||
'KAT-01 Kriterium 8: ohne Suchbegriff wird binär nach dem normalisierten Titel sortiert (Leerzeichen vor Buchstaben)');
|
||||
select results_eq($$select h from pg_temp.hits() h order by 1$$,
|
||||
$$select id from public.games where id::text like 'f9000000%' and visibility = 'catalog' and hidden_at is null and merged_into_id is null order by id$$,
|
||||
'KAT-01 Kriterium 8: ohne Suchbegriff und ohne Filter erscheinen alle sichtbaren Fixture-Spiele (ohne ausgeblendete, zusammengeführte, private)');
|
||||
|
|
|
|||
Loading…
Reference in a new issue