fix: unaccent in trigram title search and index

This commit is contained in:
Philipinho
2026-08-26 01:22:10 +01:00
parent 56474e5b70
commit 17ee613b8b
3 changed files with 28 additions and 6 deletions
@@ -48,7 +48,7 @@ export class SearchService {
const rankColumn = browseByFilters const rankColumn = browseByFilters
? sql<number>`0`.as('rank') ? sql<number>`0`.as('rank')
: titleOnly : titleOnly
? sql<number>`word_similarity(lower(${titleQuery}), lower(pages.title))`.as( ? sql<number>`word_similarity(lower(f_unaccent(${titleQuery})), lower(f_unaccent(pages.title)))`.as(
'rank', 'rank',
) )
: sql<number>`ts_rank(tsv, to_tsquery('english', f_unaccent(${searchQuery})))`.as( : sql<number>`ts_rank(tsv, to_tsquery('english', f_unaccent(${searchQuery})))`.as(
@@ -84,9 +84,9 @@ export class SearchService {
.$if(!browseByFilters && titleOnly, (qb) => .$if(!browseByFilters && titleOnly, (qb) =>
qb.where((eb) => qb.where((eb) =>
eb( eb(
sql`lower(pages.title)`, sql`lower(f_unaccent(pages.title))`,
'like', 'like',
sql`lower(${`%${titleLikeQuery}%`})`, sql`lower(f_unaccent(${`%${titleLikeQuery}%`}))`,
), ),
), ),
) )
@@ -1,12 +1,34 @@
import { type Kysely, sql } from 'kysely'; import { type Kysely, sql } from 'kysely';
export async function up(db: Kysely<any>): Promise<void> { export async function up(db: Kysely<any>): Promise<void> {
await sql`CREATE INDEX IF NOT EXISTS pages_title_trgm_idx ON pages USING gin (lower(title) gin_trgm_ops)`.execute( // f_unaccent must be schema-qualified in its body to be usable inside an index
// expression: Postgres 15+ builds indexes under a secured search_path
// (pg_catalog, pg_temp), so an unqualified unaccent() cannot be resolved during
// CREATE INDEX. Redefine f_unaccent in place (in whatever schema it already
// lives) with the unaccent function and dictionary both qualified.
await sql`
DO $migration$
DECLARE ext_schema text;
BEGIN
SELECT n.nspname INTO ext_schema
FROM pg_extension e JOIN pg_namespace n ON n.oid = e.extnamespace
WHERE e.extname = 'unaccent';
EXECUTE format(
'CREATE OR REPLACE FUNCTION f_unaccent(text) RETURNS text '
|| 'LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT '
|| 'AS $f$ SELECT %I.unaccent(%L::regdictionary, $1) $f$',
ext_schema, ext_schema || '.unaccent');
END
$migration$;
`.execute(db);
await sql`CREATE INDEX IF NOT EXISTS pages_title_trgm_idx ON pages USING gin (lower(f_unaccent(title)) gin_trgm_ops)`.execute(
db, db,
); );
// separators normalized to spaces so space-typed queries match How_to_export.pdf // separators normalized to spaces so space-typed queries match How_to_export.pdf
await sql`CREATE INDEX IF NOT EXISTS attachments_file_name_trgm_idx ON attachments USING gin (lower(translate(file_name, '_.-', ' ')) gin_trgm_ops)`.execute( await sql`CREATE INDEX IF NOT EXISTS attachments_file_name_trgm_idx ON attachments USING gin (lower(f_unaccent(translate(file_name, '_.-', ' '))) gin_trgm_ops)`.execute(
db, db,
); );
} }