2011-06-27 8 views
21

Ecco quello che voglio fare:Il modo migliore per effettuare una ricerca ponderata su più campi in mysql?

  • partita una ricerca soggetto contro molteplici campi della mia tavola
  • fine i risultati per importanza del settore e la rilevanza del corrispondente (in questo ordine)

Es: supponiamo di avere un blog. Quindi qualcuno cerca "php". I risultati sembrerebbero in questo modo:

  • prima, le partite per il campo 'title', in ordine di rilevanza
  • poi, le partite per il campo 'corpo', in ordine di rilevanza troppo
  • e così on con i campi specificati ...

In realtà l'ho fatto con una classe in PHP ma utilizza un sacco di UNION (molto!) e cresce con le dimensioni dell'oggetto di ricerca. Quindi sono preoccupato per problemi di prestazioni e DOS. Qualcuno ha un indizio su questo?

risposta

29

Probabilmente questo approccio di fare una ponderata ricerca/risultati è adatto a te:

SELECT *, 
    IF(
      `name` LIKE "searchterm%", 20, 
     IF(`name` LIKE "%searchterm%", 10, 0) 
    ) 
     + IF(`description` LIKE "%searchterm%", 5, 0) 
     + IF(`url`   LIKE "%searchterm%", 1, 0) 
    AS `weight` 
FROM `myTable` 
WHERE (
    `name` LIKE "%searchterm%" 
    OR `description` LIKE "%searchterm%" 
    OR `url`   LIKE "%searchterm%" 
) 
ORDER BY `weight` DESC 
LIMIT 20 

Esso utilizza una select subquery per fornire il peso per ordinare i risultati. In questo caso, sono stati cercati tre campi, è possibile specificare un peso per campo. Probabilmente è meno costoso dei sindacati e probabilmente uno dei modi più veloci solo in MySQL.

Se hai più dati e hai bisogno di risultati più velocemente, puoi considerare l'utilizzo di qualcosa come Sfinge o Lucene.

+0

mi piace questo approccio! mi puoi spiegare cosa sta succedendo negli IF prima del FROM? non sono usato con le query complesse =/ –

+2

Fondamentalmente è una funzione IF, se la condizione (primo argomento) è vera, verrà usato il secondo argomento (il peso) altrimenti verrà usato il terzo argomento (peso 0). Il manuale ha tutti i dettagli: http://dev.mysql.com/doc/refman/5.0/en/control-flow-functions.html#function_if – hakre

+0

questo è molto bello! quindi se appare in nome (non all'inizio), descrizione e url, avrà un peso di 16? (10 + 5 + 1) –

1

È necessario utilizzare un indicizzatore dedicato per precaricare tutti i dati in un indice ricercabile ottimizzato. Sphinx e prodotti simili lo fanno molto bene.

8

è possibile aggiungere più valori mysql MATCH() insieme, prima di moltiplicare ciascuno per il loro peso.

semplificata ovviamente ...

'(MATCH(column1) AGAINST(\''.$_GET['search_string'].'\') * '.$column1_weight.') 
+ (MATCH(column2) AGAINST(\''.$_GET['search_string'].'\') * '.$column2_weight.') 
+ (MATCH(column3) AGAINST(\''.$_GET['search_string'].'\') * '.$column3_weight.') 
AS relevance' 

poi

'ORDER BY relevance' 
+0

se i pesi sono impostati correttamente, li posizionerà nell'ordine desiderato. – dqhendricks

+0

puoi darmi un esempio di come impostare i pesi per questo? –

+0

@hugo_leonardo i pesi dipendono da quanto più importante una corrispondenza nel titolo viene confrontata con il corpo. quindi se la corrispondenza del titolo è 5 volte più importante di una partita del corpo, i pesi sarebbero rispettivamente 5 e 1. Ha senso ciò? – dqhendricks

1

Ho avuto questa stessa identica domanda ed è stato pienamente risposto su uno dei forum di MySQL. Here's the thread. Tipo di thread lungo (perché sono un po 'prolisso) ma il payoff è proprio quello che stai cercando.

+0

molto interessante! +1 (:. –

+0

@hugo_leonardo - sì, i due ragazzi che hanno risposto ha dato risposte molto riflessivo –

+2

@PeteWilson: si prega di aggiungere citazioni relavant al tuo post perchè link esterni possono rompersi. – jor

Problemi correlati