Pergunta

Eu tenho artigos no meu site e gostaria de adicionar tags que descreveriam cada artigo, mas estou tendo problemas com o design da tabela MySQL para tags. Eu tenho duas idéias:

  1. Cada artigo teria "tags" de campo, e as tags estariam no formato: "Tag1, Tag2, Tag3"
  2. Crie outra tabela chamada tags com campos: tag_name, artigo_id

Então, quando eu quero tags para o artigo com ID 1, eu corria

SELECT ... FROM tags WHERE `article_id`=1;

Mas, também gostaria de saber três artigos mais semelhantes comparando tags; portanto, se eu tiver um artigo que tenha tags "PHP, MySQL, Erlang" e 5 artigos com tags: "php, mysql", "erlang, ruby", "PHP Erlang", "MySQL, Erlang, JavaScript", eu escolheria 1., 3. e 4., já que esses 3 têm a maioria das mesmas tags com o artigo principal.

Além disso, outra pergunta: qual é a melhor maneira de obter 10 "tags mais usadas"?

Foi útil?

Solução

Geralmente, para esse tipo de relacionamento muitos para muitos, existem três mesas:

  • O "article" tabela
    • chave primária = id
  • O "tag" tabela
    • chave primária = id
    • Contém os dados de cada tag:
      • nome, por exemplo
  • UMA "tags_articles"Tabela, que atua como uma tabela de junção, e contém apenas:
    • id_article : Chave estrangeira que aponta para um artigo
    • id_tag : Chave estrangeira que aponta para uma tag


Dessa forma, não há duplicação dos dados de qualquer tag: para cada tag, existe um e apenas um, linha no tag tabela.

E, para cada artigo, você pode ter várias tags (ou seja, várias linhas no tags_articles tabela) ; E, é claro, para cada tags, você pode ter vários artigos.

Obter uma lista de tags para um artigo, com essa ideia, é uma questão de uma consulta adicional, como:

select tag.*
from tag
    inner join tags_articles on tag.id = tags_articles.id_tag
where tags_articles.id_article = 123


Obter os três artigos "mais semelhantes" significariam:

  • Selecione artigos com tags que o primeiro artigo tenha
  • Use apenas aqueles que têm o número mais importante de tags idênticas

Não testado, mas uma ideia pode ser algo que seria assim:

select article.id, count(*) as nb_identical_tags
from article
    inner join tags_articles on tags_articles.id_article = article.id
    inner join tag on tag.id = tags_articles.id_tag
where tag.name in ('php', 'mysql', 'erlang')
      and article.id <> 123
group by article.id
order by count(*) desc
limit 3

Basicamente, você:

  • Selecione os IDs de artigos para cada tag que está presente em seu artigo inicial
    • Como há uma junção interna, se um artigo no banco de dados tiver 2 tags que correspondam ao where Cláusula, sem o group by Cláusula, haveria duas linhas para esse artigo
    • Obviamente, você não deseja selecionar novamente o artigo que já teve-o que significa que ele deve ser excluído.
  • Mas, como você usa group by article.id, haverá apenas uma linha por artigo
    • Mas você poderá usar count, para descobrir quantas tags cada artigo tem em comum com o inicial
  • Então, é apenas uma questão de classificar por número de tags e obter apenas as três linhas das três linhas.

Outras dicas

Primeiro, você deseja usar a sugestão de Pascal Martin sobre o design da mesa.

Quanto a encontrar artigos semelhantes, aqui está algo para começar. Dado que @article_id é o artigo para o qual você deseja encontrar correspondências e @tag1, @tag2, @tag3 são as tags para esse artigo:

SELECT article_id, count(*)
FROM tags_articles
WHERE article_id <> @article_id
AND tag_id IN (@tag1, @tag2, @tag3)
GROUP BY article_id
ORDER BY count(*) DESC
LIMIT 3

Sim, mas você não respondeu minha pergunta principal, como obter três artigos mais semelhantes?

Resposta: Basta procurar os mesmos IDs de tags na tabela mesclada (tags_articles). Reúna -os e crie um padrão.

Por exemplo: Artigo 1 tem tags: 1,2 Artigo 2 tem tags: 2,3,4 O artigo 5 tem tags: 6,7,2 Artigo 7 tem tags: 7,1,2,3

Se você deseja os três artigos mais semelhantes para o artigo 1, deve procurar as tags 1,2. Você encontrará o artigo 7 mais semelhante e 2 e 5 têm algumas semelhanças.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top