2011-06-27 15 views
21

Esto es lo que quiero hacer:¿La mejor manera de hacer una búsqueda ponderada en múltiples campos en mysql?

  • partido de una búsqueda sujeto frente a múltiples campos de mi mesa
  • fin los resultados por importancia del campo y la pertinencia del juego (en ese orden)

Ej .: supongamos que tengo un blog. Entonces alguien busca "php". Los resultados aparecerían de esa manera:

  • en primer lugar, los resultados para el campo 'título', ordenadas por relevancia
  • a continuación, los resultados para el campo 'cuerpo', ordenadas por relevancia demasiado
  • y así con los campos especificados ...

De hecho, hice esto con una clase en PHP pero usa muchos SINDICATOS (¡muchos!) y crece con el tamaño del tema de búsqueda. Así que estoy preocupado por el rendimiento y los problemas de DOS. ¿Alguien tiene una pista sobre esto?

Respuesta

29

Probablemente este método de hacer una búsqueda ponderados/resultados es adecuado para usted:

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 

Se utiliza un selecto subconsulta para proporcionar el peso para ordenar los resultados. En este caso, tres campos revisados, puede especificar un peso por campo. Es probable que sea menos costoso que los sindicatos y probablemente una de las formas más rápidas en MySQL simple solamente.

Si tiene más datos y necesita resultados más rápidos, puede considerar usar algo como Sphinx o Lucene.

+0

me gusta este enfoque! ¿Puedes explicarme qué está pasando en las FI antes del FROM? no me utilizan con las querys complejas =/ –

+2

Básicamente es una función IF, si la condición (primer argumento) es verdadera, se usará el segundo argumento (el peso); de lo contrario, se usará un tercer argumento (0-peso). El manual tiene todos los detalles: http://dev.mysql.com/doc/refman/5.0/en/control-flow-functions.html#function_if – hakre

+0

¡eso es muy bueno! entonces, si aparece en el nombre (no al comienzo), la descripción y la URL, obtendrá un peso de 16? (10 + 5 + 1) –

1

Debe usar un indexador dedicado para captar previamente todos los datos en un índice optimizado y con capacidad de búsqueda. Sphinx y productos similares hacen esto muy bien.

8

puede agregar múltiples valores de mysql MATCH() juntos, primero multiplicando cada uno por su peso.

simplificado por supuesto ...

'(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' 

continuación

'ORDER BY relevance' 
+0

si sus pesos están configurados correctamente, los colocará en el orden deseado. – dqhendricks

+0

¿me puede dar un ejemplo de cómo establecer los pesos para esto? –

+0

@hugo_leonardo los pesos dependen de la coincidencia más importante en el título con el cuerpo. entonces si la coincidencia de título es 5 veces más importante que una coincidencia de cuerpo, los pesos serían 5 y 1 respectivamente. ¿Esto tiene sentido? – dqhendricks

1

Tenía esta exacta misma pregunta y se respondió completamente en uno de los foros de MySQL. Here's the thread. Tipo de un hilo largo (porque soy un poco largo) pero la recompensa es justo lo que estás buscando.

+0

muy interesante! +1 (: –

+0

@hugo_leonardo - sí, los dos tipos que respondieron dieron respuestas muy reflexivas. –

+2

@PeteWilson: por favor agregue citas relavantes a su publicación porque los enlaces externos pueden romperse. – jor

Cuestiones relacionadas