2014-12-03 7 views
5

Sto usando trigrammi per la ricerca full-text in Postgres come questo:Come eseguire una semplice riduzione della mappa in Postgres?

SELECT * 
FROM "Users" users 
WHERE 'search_text' % ANY(regexp_split_to_array(users.name,E'\\s+')) 

Query sopra controlla se search_text corrisponde a qualsiasi parola (split da whitespace) in User.displayName. Questo funziona, tuttavia, i risultati non sono ordinati in base al "punteggio" effettivo.

Il punteggio può essere calcolato dalla funzione similarity(text,text).

Il problema è che devo ordinare da loro la somma di tutte le somiglianze trovate per ogni parola in User.name. Quindi, se il nome utente è "A B C" quindi il suo punteggio dovrebbe essere:

similarity('search_text','A') + similarity('search_text','B') + similarity('search_text','C') 

quindi ho bisogno di mappare il nome utente parole a punteggi e poi sum (ridurre) loro. Come posso farlo a Postgres?

risposta

1

Nel invece di scissione a un array diviso per un set poi ricompattarsi sommando la somiglianza

with users as (
    select user_id, name 
    from (values (1, 'John Smith')) t(user_id, name) 
) 
select user_id, sum(similarity('smth', name_part)) 
from (
    select user_id, regexp_split_to_table(name, E'\\s+') as name_part 
    from users 
) users 
where 'smth' % name_part 
group by user_id 
order by 2 desc 
; 
user_id | sum 
---------+------- 
     1 | 0.375 

io non sono sicuro di voler eliminare quelle parti nome per il quale la somiglianza è inferiore alla soglia. Se non omettere semplicemente la clausola where

BTW, perché è necessario dividere il nome? Perché non basta confrontare l'intero nome con la stringa di ricerca?

with users as (
    select user_id, name 
    from (values (1, 'John Smith')) t(user_id, name) 
) 
select similarity('jon smth', name), * 
from users 
order by 1 desc 
; 
similarity | user_id | name  
------------+---------+------------ 
    0.333333 |  1 | John Smith 
Problemi correlati