Pergunta

Já ouvi falar de algumas maneiras de implementar marcação;usar uma tabela de mapeamento entre TagID e ItemID (faz sentido para mim, mas é escalonável?), adicionar um número fixo de possíveis colunas TagID a ItemID (parece uma má ideia), manter tags em uma coluna de texto separada por vírgula (parece louco, mas poderia funcionar).Já ouvi alguém recomendar uma matriz esparsa, mas então como os nomes das tags crescem normalmente?

Estou faltando uma prática recomendada para tags?

Foi útil?

Solução

Três tabelas (uma para armazenar todos os itens, uma para todas as tags e uma para a relação entre os dois), devidamente indexadas, com chaves estrangeiras definidas em execução em um banco de dados adequado, devem funcionar bem e escalar adequadamente.

Table: Item
Columns: ItemID, Title, Content

Table: Tag
Columns: TagID, Title

Table: ItemTag
Columns: ItemID, TagID

Outras dicas

Normalmente eu concordaria com Yaakov Ellis mas neste caso especial há outra solução viável:

Utilize duas tabelas:

Table: Item
Columns: ItemID, Title, Content
Indexes: ItemID

Table: Tag
Columns: ItemID, Title
Indexes: ItemId, Title

Isso tem algumas vantagens importantes:

Primeiro, torna o desenvolvimento muito mais simples:na solução de três tabelas para inserção e atualização de item você tem que procurar o Tag tabela para ver se já existem entradas.Então você tem que juntá-los com novos.Esta não é uma tarefa trivial.

Depois, torna as consultas mais simples (e talvez mais rápidas).Existem três consultas principais ao banco de dados que você fará:Saída tudo Tags para um Item, desenhe uma Tag-Cloud e selecione todos os itens para um Tag Title.

Todas as tags para um item:

3-Tabela:

SELECT Tag.Title 
  FROM Tag 
  JOIN ItemTag ON Tag.TagID = ItemTag.TagID
 WHERE ItemTag.ItemID = :id

2-Tabela:

SELECT Tag.Title
FROM Tag
WHERE Tag.ItemID = :id

Nuvem de tags:

3-Tabela:

SELECT Tag.Title, count(*)
  FROM Tag
  JOIN ItemTag ON Tag.TagID = ItemTag.TagID
 GROUP BY Tag.Title

2-Tabela:

SELECT Tag.Title, count(*)
  FROM Tag
 GROUP BY Tag.Title

Itens para uma Tag:

3-Tabela:

SELECT Item.*
  FROM Item
  JOIN ItemTag ON Item.ItemID = ItemTag.ItemID
  JOIN Tag ON ItemTag.TagID = Tag.TagID
 WHERE Tag.Title = :title

2-Tabela:

SELECT Item.*
  FROM Item
  JOIN Tag ON Item.ItemID = Tag.ItemID
 WHERE Tag.Title = :title

Mas também existem algumas desvantagens:Poderia ocupar mais espaço no banco de dados (o que poderia levar a mais operações de disco, o que seria mais lento) e não seria normalizado, o que poderia levar a inconsistências.

O argumento do tamanho não é tão forte porque a própria natureza das tags é que elas normalmente são bem pequenas, então o aumento de tamanho não é grande.Pode-se argumentar que a consulta do título da tag é muito mais rápida em uma tabela pequena que contém cada tag apenas uma vez e isso certamente é verdade.Mas levando em consideração a economia por não ter que aderir e o fato de você poder construir um bom índice sobre eles poderia facilmente compensar isso.É claro que isso depende muito do tamanho do banco de dados que você está usando.

O argumento da inconsistência também é um pouco discutível.Tags são campos de texto livre e não há operação esperada como 'renomear todas as tags "foo" para "bar"'.

Então tldr:Eu escolheria a solução de duas tabelas.(Na verdade eu vou.Encontrei este artigo para ver se há argumentos válidos contra ele.)

Se você estiver usando um banco de dados que suporta redução de mapa, como couchdb, armazenar tags em um campo de texto simples ou campo de lista é de fato a melhor maneira.Exemplo:

tagcloud: {
  map: function(doc){ 
    for(tag in doc.tags){ 
      emit(doc.tags[tag],1) 
    }
  }
  reduce: function(keys,values){
    return values.length
  }
}

Executar isso com group=true agrupará os resultados por nome de tag e até retornará uma contagem do número de vezes que essa tag foi encontrada.É muito parecido com contando as ocorrências de uma palavra no texto.

Use uma única coluna de texto formatada[1] para armazenar as tags e use um mecanismo de pesquisa de texto completo capaz para indexá-las.Caso contrário, você terá problemas de dimensionamento ao tentar implementar consultas booleanas.

Se precisar de detalhes sobre as tags que você possui, você pode acompanhá-las em uma tabela mantida de forma incremental ou executar um trabalho em lote para extrair as informações.

[1] Alguns RDBMS fornecem até um tipo de array nativo que pode ser ainda mais adequado para armazenamento por não precisar de uma etapa de análise, mas pode causar problemas com a pesquisa de texto completo.

Sempre mantive as tags em uma tabela separada e depois tive uma tabela de mapeamento.É claro que também nunca fiz nada em grande escala.

Ter uma tabela de "tags" e uma tabela de mapas torna bastante trivial a geração de nuvens de tags, pois você pode facilmente reunir o SQL para obter uma lista de tags com contagens de quantas vezes cada tag é usada.

Eu sugeriria o seguinte design:Tabela de itens:ID do item, lista de tags1, lista de tags2
isso será rápido e facilitará o salvamento e a recuperação dos dados no nível do item.

Em paralelo, construa outra tabela:Tags tags não produzem identificador exclusivo e se você ficar sem espaço na 2ª coluna que contém, digamos 100 itens, crie outra linha.

Agora, ao procurar itens para uma tag, será super rápido.

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