Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ordering items with matching tags by number of tags that match

I'm trying to figure out how to order items with matching tags by the number of tags that match.

Let's say you have three MySQL tables:

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

Now let's say you have four articles where:

article_id = 1 has tags "humor," "funny," and "hilarious."

article_id = 2 has tags "funny," "silly," and "goofy."

article_id = 3 has tags "funny," "silly," and "goofy."

article_id = 4 has the tag "completely serious."

You need to find all articles related to article_id = 2 by at least one matching tag, and return the results in order of the best matches. In other words, article_id = 3 should come first, with article_id = 1 second, and article_id = 4 should not show up at all.

Is this something that's doable in SQL queries or alone, or is this better suited for something like Sphinx? If the former, what kind of query should be done, and what sort of indexes should be created for the most performant results? If the latter, please do expand.

like image 529
Josh Smith Avatar asked Sep 24 '10 02:09

Josh Smith


1 Answers

Try something like this:

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;

Syntax may need a little tweaking for MySQL.

or this one that actually works: ;-)

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;
like image 154
Andrew Cooper Avatar answered Oct 29 '22 07:10

Andrew Cooper