2010-11-19 15 views
15

Estoy tratando de hacer una búsqueda de texto completo en tres tablas separadas y ordenar los resultados por relevancia. Durante mis búsquedas de la respuesta, descubrí que no puedo usar la búsqueda de texto completo en varias tablas. Así que agregué un índice completo de texto completo para cada columna que quiero buscar. Ahora el problema es que puedo hacer la búsqueda, pero no puedo hacer la clasificación como me gustaría.mysql texto completo en tablas múltiples

Aquí está mi tablas

CREATE TABLE books (
bookID int(11) NOT NULL AUTO_INCREMENT, 
title varchar(300) NOT NULL, 
authorID int(11) NOT NULL, 
FULLTEXT KEY title (title) 
) 

CREATE TABLE IF NOT EXISTS authors (
authorID int(11) NOT NULL AUTO_INCREMENT, 
authorNamevarchar(200) NOT NULL, 
FULLTEXT KEY authorName(authorName) 
); 

CREATE TABLE IF NOT EXISTS chapters (
chapterID int(11) NOT NULL AUTO_INCREMENT, 
bookID int(11) NOT NULL, 
content longtext NOT NULL, 
FULLTEXT KEY content (content) 
); 

Y mi consulta SQL. Aquí es donde estoy atascado.

SELECT *, 
MATCH(books.title) AGAINST('$q') as tscore, 
MATCH(authors.authorName) AGAINST('$q') as ascore 
MATCH(chapters.content) AGAINST('$q') as cscore 
FROM books 
LEFT JOIN authors ON books.authorID = authors.authorID 
LEFT JOIN chapters ON books.bookID = chapters.bookID 
WHERE 
MATCH(books.title) AGAINST('$q') 
OR MATCH(authors.authorName) AGAINST('$q') 
OR MATCH(chapters.content) AGAINST('$q') 
ORDER BY ???? DESC 

Ahora con esta consulta puedo hacer la clasificación por títulos, autores o contenidos. Lo que quiero hacer es obtener la relevancia de las tres columnas juntas y ordenar los resultados por eso.

Y sí, estoy al tanto de otros motores de búsqueda como lucene o sphinx, pero no estoy planeando usarlos ahora.

Gracias de antemano.

Respuesta

30

Debería poder agregar los valores de tscore, ascore y cscore en la cláusula ORDER BY.

Prueba esto:

SELECT *, 
MATCH(books.title) AGAINST('$q') as tscore, 
MATCH(authors.authorName) AGAINST('$q') as ascore, 
MATCH(chapters.content) AGAINST('$q') as cscore 
FROM books 
LEFT JOIN authors ON books.authorID = authors.authorID 
LEFT JOIN chapters ON books.bookID = chapters.bookID 
WHERE 
MATCH(books.title) AGAINST('$q') 
OR MATCH(authors.authorName) AGAINST('$q') 
OR MATCH(chapters.content) AGAINST('$q') 
ORDER BY (tscore + ascore + cscore) DESC 
+1

. Gracias. – keune

+0

me ayudó a cargar. ¡Gracias! – youngcouple10

+1

¡Muy bonito, lo que necesitaba para mi proyecto! – NaturalBornCamper

-1

Depende de lo que desee ordenar. Se podría ordenar por autor, a continuación del título, a continuación, el contenido del capítulo con esta

ORDER BY MATCH(authors.authorName) DESC ,MATCH(books.title) DESC ,MATCH(chapters.content) DESC 

la idea de que cuando encuentre el nombre de los autores, es más relevante que cuando se encuentra en el título, que a su vez es más relevante que encontrándolo en el texto del capítulo. También podría ordenar por la relevancia total, con

ORDER BY MATCH(authors.authorName) + MATCH(books.title) + MATCH(chapters.content) DESC 

pero que podrían dar resultados extraños, como algo que el texto de búsqueda sólo se muestra en el contenido del capítulo podría aparecer antes del título.

+0

no funciona, lo he intentado .... puede hacer ORDEN POR PARTIDO (..) CONTRA() que hace exactamente lo mismo que la segunda consulta – ITECH

0

solución de @Ike Walker es grande, sin embargo, en mi caso quería enrollar los resultados de uno a muchos en una sola fila por cada resultado de búsqueda. Riffing en la solución de @Ike Walker así es como me dieron el trabajo hecho:

esquema:

T1: Articles 
T2: Comments (many comments to one article) 

Índices:

ALTER TABLE articles ADD FULLTEXT title_index (title) 
ALTER TABLE articles ADD FULLTEXT body_index (body) 
ALTER TABLE comments ADD FULLTEXT comment_index (comment) 

SQL:

SELECT 
    articles.title, 
    SUM(MATCH(articles.title) AGAINST('$q') + 
    MATCH(articles.body) AGAINST('$q') + 
    MATCH(comments.comment) AGAINST('$q')) as relevance 
FROM 
    articles 
LEFT JOIN 
    comments ON articles.id = comments.article_id 
WHERE 
    MATCH(articles.title) AGAINST('$q') 
    OR MATCH(articles.body) AGAINST('$q') 
    OR MATCH(comments.comment) AGAINST('$q') 
GROUP BY 
    articles.id 
ORDER BY 
    relevance DESC 

Nota: Si desea para agregar pesos a cada campo, podrías hacer algo como.

SUM((MATCH(articles.title) AGAINST('$q')*3) + 
     (MATCH(articles.body) AGAINST('$q')*2) + 
     MATCH(comments.comment) AGAINST('$q')) as relevance 

En este caso el título tendría 3x, cuerpo 2x el valor de una coincidencia en los comentarios.

Cuestiones relacionadas