PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Come indicizzare una tabella postgres per nome, quando il nome può essere in qualsiasi lingua?

Se desideri ottimizzare le corrispondenze arbitrarie di sottostringhe, un'opzione consiste nell'usare il pg_tgrm modulo . Aggiungi un indice:

CREATE INDEX table_location_name_trigrams_key ON table
  USING gin (location_name gin_trgm_ops);

Questo suddividerà "Simple Cafe" in "sim", "imp", "mpl", ecc. e aggiungerà una voce all'indice per ogni trigam in ogni riga. Il pianificatore di query può quindi utilizzare automaticamente questo indice per le corrispondenze del modello di sottostringa, tra cui:

SELECT * FROM table WHERE location_name ILIKE '%cafe%';

Questa query cercherà "caf" e "afe" nell'indice, troverà l'intersezione, recupererà quelle righe, quindi verificherà ogni riga rispetto al tuo modello. (Quell'ultimo controllo è necessario poiché l'intersezione di "caf" e "afe" corrisponde sia a "cafè semplice" che a "impalcatura non sicura", mentre "%cafe%" dovrebbe corrispondere solo a uno). L'indice diventa più efficace man mano che il pattern di input si allunga poiché può escludere più righe, ma non è ancora efficiente quanto l'indicizzazione di intere parole, quindi non aspettarti un miglioramento delle prestazioni rispetto a to_tsvector .

Il problema è che i trigrammi non funzionano affatto per i modelli con meno di tre caratteri. Questo potrebbe essere o meno un problema per la tua applicazione.

Modifica: Inizialmente l'ho aggiunto come commento.

Ho avuto un altro pensiero la scorsa notte, quando ero per lo più addormentato. Crea un cjk_chars funzione che accetta una stringa di input, regexp_matches l'intero intervallo CJK Unicode e restituisce un array di tali caratteri o NULL se nessuno. Aggiungi un indice GIN su cjk_chars(location_name) . Quindi eseguire una query per:

WHERE CASE
  WHEN cjk_chars('query') IS NOT NULL THEN
    cjk_chars(location_name) @> cjk_chars('query')
    AND location_name LIKE '%query%'
  ELSE
    <tsvector/trigrams>
  END

Ta-da, unigram!