2010-09-24 6 views
7

Estoy tratando de averiguar cómo pedir elementos con etiquetas que coincidan con el número de etiquetas que coinciden.Ordenar elementos con etiquetas que coincidan por número de etiquetas que coinciden con

Digamos que usted tiene tres tablas de MySQL:

  • tags(tag_id, title)
  • articles(article_id, some_text)
  • articles_tags(tag_id, article_id)

Ahora digamos que usted tiene cuatro artículos donde:

article_id = 1 tiene etiquetas " humor, "" f unny, "y" hilarante ".

article_id = 2 tiene las etiquetas "gracioso", "tonto" y "ridículo".

article_id = 3 tiene las etiquetas "gracioso", "tonto" y "ridículo".

article_id = 4 tiene la etiqueta "completely serious."

Necesita encontrar todos los artículos relacionados con article_id = 2 por al menos una etiqueta que coincida, y devolver los resultados en el orden de las mejores coincidencias. En otras palabras, article_id = 3 debe ser lo primero, con article_id = 1 en segundo lugar, y article_id = 4 no debe aparecer en absoluto.

¿Es esto algo que se puede hacer en consultas SQL o solo, o es más adecuado para algo como Sphinx? En el primer caso, ¿qué tipo de consulta se debe hacer y qué tipo de índices se deben crear para obtener los mejores resultados? Si es este último, por favor expande.

Respuesta

10

intentar algo como esto:

select article_id, count(tag_id) as common_tag_count 
from articles_tags 
group by tag_id 
where tag_id in (
    select tag_id from articles_tags where article_id = 2 
) and article_id != 2 
order by common_tag_count desc; 

Sintaxis puede necesitar un poco de ajuste para MySQL.

o éste que realmente funciona: ;-)

SELECT at1.article_id, Count(at1.tag_id) AS common_tag_count 
FROM articles_tags AS at1 INNER JOIN articles_tags AS at2 ON at1.tag_id = at2.tag_id 
WHERE at2.article_id = 2 
GROUP BY at1.article_id 
HAVING at1.article_id != 2 
ORDER BY Count(at1.tag_id) DESC; 
+0

La segunda sintaxis es fantástica y funcionó exactamente de la manera que necesitaba. ¡Muchas gracias! –

2

algo parecido a:

SELECT a.* 
FROM articles AS a 
INNER JOIN articles_tags AS at ON a.id=at.article_id 
INNER JOIN tags AS t ON at.tag_id = t.id 
WHERE t.title = 'funny' OR t.title = 'goofy' OR t.title = 'silly' AND a.id != <article_id> 
GROUP BY a.id 
ORDER BY COUNT(a.id) DESC 

Con sólo los índices habituales, asumiendo articles_tags tiene PK de (article_id, tag_id), y una index on tags.title

Cuestiones relacionadas