Pregunta

He oído hablar de algunas formas de implementar el etiquetado;usar una tabla de mapeo entre TagID y ItemID (tiene sentido para mí, pero ¿se escala?), agregar un número fijo de posibles columnas TagID a ItemID (parece una mala idea), mantener etiquetas en una columna de texto separada por comas (suena loco pero podría funcionar).Incluso escuché a alguien recomendar una matriz dispersa, pero entonces, ¿cómo crecen con gracia los nombres de las etiquetas?

¿Me estoy perdiendo una de las mejores prácticas para las etiquetas?

¿Fue útil?

Solución

Tres tablas (una para almacenar todos los elementos, una para todas las etiquetas y otra para la relación entre las dos), correctamente indexadas, con claves externas configuradas ejecutándose en una base de datos adecuada, deberían funcionar bien y escalar correctamente.

Table: Item
Columns: ItemID, Title, Content

Table: Tag
Columns: TagID, Title

Table: ItemTag
Columns: ItemID, TagID

Otros consejos

Normalmente estaría de acuerdo con Yaakov Ellis pero en este caso especial hay otra solución viable:

Utilice dos tablas:

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

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

Esto tiene algunas ventajas importantes:

Primero, simplifica mucho el desarrollo:en la solución de tres tablas para insertar y actualizar item tienes que buscar el Tag tabla para ver si ya hay entradas.Luego hay que unirlos con otros nuevos.Ésta no es una tarea trivial.

Luego simplifica las consultas (y quizás más rápido).Hay tres consultas principales a la base de datos que deberá realizar:Salida todo Tags para uno Item, dibuje una nube de etiquetas y seleccione todos los elementos para un título de etiqueta.

Todas las etiquetas para un artículo:

3-Tabla:

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

2-Tabla:

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

Nube de etiquetas:

3-Tabla:

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

2-Tabla:

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

Artículos para una etiqueta:

3-Tabla:

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

2-Tabla:

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

Pero también hay algunos inconvenientes:Podría ocupar más espacio en la base de datos (lo que podría generar más operaciones en el disco, lo que es más lento) y no está normalizado, lo que podría generar inconsistencias.

El argumento del tamaño no es tan fuerte porque la naturaleza misma de las etiquetas es que normalmente son bastante pequeñas, por lo que el aumento de tamaño no es grande.Se podría argumentar que la consulta del título de la etiqueta es mucho más rápida en una tabla pequeña que contiene cada etiqueta solo una vez y esto ciertamente es cierto.Pero teniendo en cuenta los ahorros que supone no tener que inscribirse y el hecho de que se puede crear un buen índice sobre ellos, esto podría compensarse fácilmente.Por supuesto, esto depende en gran medida del tamaño de la base de datos que esté utilizando.

El argumento de la inconsistencia también es un poco discutible.Las etiquetas son campos de texto libre y no se espera ninguna operación como 'cambiar el nombre de todas las etiquetas "foo" a "bar"'.

Entonces tldr:Yo optaría por la solución de dos mesas.(De hecho, voy a hacerlo.Encontré este artículo para ver si hay argumentos válidos en contra).

Si está utilizando una base de datos que admite reducción de mapas, como CouchDB, almacenar etiquetas en un campo de texto sin formato o en un campo de lista es, de hecho, la mejor manera.Ejemplo:

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

Ejecutar esto con group=true agrupará los resultados por nombre de etiqueta e incluso devolverá un recuento del número de veces que se encontró esa etiqueta.Es muy similar a contar las apariciones de una palabra en el texto.

Utilice una única columna de texto formateado[1] para almacenar las etiquetas y utilice un motor de búsqueda de texto completo capaz para indexarlas.De lo contrario, se encontrará con problemas de escala al intentar implementar consultas booleanas.

Si necesita detalles sobre las etiquetas que tiene, puede realizar un seguimiento en una tabla mantenida de forma incremental o ejecutar un trabajo por lotes para extraer la información.

[1] Algunos RDBMS incluso proporcionan un tipo de matriz nativo que podría ser incluso más adecuado para el almacenamiento al no necesitar un paso de análisis, pero podría causar problemas con la búsqueda de texto completo.

Siempre mantuve las etiquetas en una tabla separada y luego tuve una tabla de mapeo.Por supuesto, tampoco he hecho nunca nada a gran escala.

Tener una tabla de "etiquetas" y una tabla de mapas hace que sea bastante trivial generar nubes de etiquetas y demás, ya que puede crear SQL fácilmente para obtener una lista de etiquetas con recuentos de la frecuencia con la que se usa cada etiqueta.

Sugeriría el siguiente diseño:Tabla de artículos:Itemid, lista de etiquetas1, lista de etiquetas2
Esto será rápido y facilitará guardar y recuperar los datos a nivel de elemento.

En paralelo construye otra tabla:La etiqueta Tags no hace que el identificador único de la etiqueta y si se queda sin espacio en la segunda columna que contiene, digamos 100 elementos, cree otra fila.

Ahora, mientras busca elementos para una etiqueta, será súper rápido.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top