2010-11-19 7 views
15

J'essaie de faire une recherche de texte intégral dans trois tableaux séparés et de trier les résultats par pertinence. Au cours de mes recherches, j'ai découvert que je ne pouvais pas utiliser la recherche fulltext dans plusieurs tables. J'ai donc ajouté un index de texte intégral séparé pour chaque colonne que je veux rechercher. Maintenant le problème est que je peux faire la recherche mais je ne peux pas faire le tri comme je voudrais.mysql fulltext sur plusieurs tables

Voilà mes tables

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) 
); 

et ma requête SQL. C'est là que je suis coincé.

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 

Maintenant, avec cette requête, je peux faire le tri par les titres, les auteurs ou les contenus. Ce que je veux faire est, obtenir la pertinence pour les trois colonnes ensemble et ordonner les résultats par cela. Et, oui, je suis au courant d'autres moteurs de recherche comme lucene ou sphinx, mais je ne prévois pas de les utiliser maintenant.

Merci d'avance.

Répondre

30

Vous devriez pouvoir ajouter les valeurs tscore, ascore et cscore dans la clause ORDER BY.

Essayez ceci:

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

exactement. Merci. – keune

+0

m'a aidé charges. Merci! – youngcouple10

+1

Très bien, ce dont j'avais besoin pour mon projet! – NaturalBornCamper

-1

Cela dépend de ce que vous voulez trier. Vous pouvez trier par auteur, puis titre, puis le contenu du chapitre avec cette

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

l'idée étant que lorsque vous trouvez le nom des auteurs, il est plus pertinent que quand il se trouve dans le titre, ce qui est plus que le trouver dans le texte du chapitre. Vous pouvez également trier par la pertinence totale avec

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

mais qui pourrait donner des résultats bizarres, comme quelque chose où le texte de recherche affiche dans le contenu du chapitre pourrait apparaître avant le titre.

+0

ne fonctionne pas je l'ai essayé .... vous pouvez faire COMMANDE PAR MATCH (..) CONTRE() qui fait la même chose que la deuxième requête – ITECH

0

solution de @Ike Walker est grande, mais dans mon cas, je voulais rouler les one-to-many résultats sur une seule ligne par résultat de recherche. Riffing sur la solution de @Ike Walker est ici que je suis le travail:

schéma:

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

Index:

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 

Note: Si vous voulez pour ajouter des poids à chaque champ, vous pourriez faire quelque chose comme.

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

Dans ce cas, le titre aurait 3x, le corps 2x la valeur d'une correspondance dans les commentaires.