Рекомендуемый дизайн базы данных SQL для тегов или тегов [закрыто]

Я слышал о нескольких способах реализации тегов; использование таблицы сопоставления между TagID и ItemID (имеет смысл, но масштабируется ли это?), добавление фиксированного количества возможных столбцов TagID к ItemID (кажется плохой идеей), сохранение тегов в текстовом столбце, разделенном запятыми (звучит сумасшедший, но может работать). Я даже слышал, что кто-то рекомендует разреженную матрицу, но тогда как имена тегов растут изящно?

Я пропускаю лучшую практику для тегов?

21.08.2008 19:18:05
Хорошо, это вопрос № 20856, (почти) тот же вопрос # 48475 задавался по крайней мере через две недели после того, как был задан этот вопрос.
dlamblin 7.10.2008 16:02:38
Еще один интересный вопрос: «Как SO реализует теги?»
Mostafa 28.11.2011 19:19:35
Другой интересный вопрос: «Вы бы их интернационализировали, и если да, то как?»
DanMan 3.12.2013 11:14:51
Интересное сравнение (специфично для Postgres): databaseoup.com/2015/01/tag-all-things.html
a_horse_with_no_name 11.05.2015 10:10:34
Ian Ringrose 22.12.2015 11:50:13
6 ОТВЕТОВ
РЕШЕНИЕ

Три таблицы (одна для хранения всех элементов, одна для всех тегов и одна для отношения между ними), должным образом проиндексированные, с установленными внешними ключами, работающими в соответствующей базе данных, должны работать хорошо и масштабироваться должным образом.

Table: Item
Columns: ItemID, Title, Content

Table: Tag
Columns: TagID, Title

Table: ItemTag
Columns: ItemID, TagID
402
21.08.2008 19:22:44
Это решение называется «Toxi», дополнительную информацию о нем вы можете найти здесь: howto.philippkeller.com/2005/04/24/Tags-Database-schemas
The Pixel Developer 28.06.2009 12:41:38
Единственное, что здесь не показано, это иерархические «теги» или категории в таблице «Теги». Это обычно требуется на сайтах, которые имеют категории и подкатегории, но нуждаются в гибкости тегов. Например, сайты рецептов, сайты автозапчастей, бизнес-каталоги и т. Д. Эти типы данных обычно не вписываются только в одну категорию, поэтому тегирование - это ответ, но вам нужно использовать что-то вроде модели вложенного набора или модели списка смежности. в вашей таблице тегов.
HK1 21.01.2011 20:50:35
Я согласен с HK1, возможно ли это с приведенной выше структурой + Таблица: столбцы TagGroup: TagGropuId, таблица заголовков: столбцы тегов: TagID, Title, TagGroupId
Thunder 11.02.2011 08:35:28
Когда я хочу добавить столбец CSS в таблицу, я добавлю столбец CSS в таблицу тегов?
Amitābha 11.08.2015 09:19:26
@ftvs: ссылка снова не работает, новая ссылка - howto.philippkeller.com/2005/04/24/Tags-Database-schemas
hansaplast 12.11.2017 07:02:55

Я всегда держал теги в отдельной таблице, а затем имел таблицу сопоставления. Конечно, я никогда ничего не делал в действительно больших масштабах.

Наличие таблицы «тегов» и таблицы карт позволяет довольно просто генерировать облака тегов и т. Д., Поскольку вы можете легко собрать SQL, чтобы получить список тегов со счетчиком частоты использования каждого тега.

9
21.08.2008 19:23:32
Это еще проще, если вы не используете таблицу сопоставления :)
Scheintod 27.09.2013 19:11:33

Используйте один отформатированный текстовый столбец [1] для хранения тегов и используйте способную полнотекстовую поисковую систему для индексации этого. В противном случае вы столкнетесь с проблемами масштабирования при попытке реализовать логические запросы.

Если вам нужны подробности о имеющихся у вас тегах, вы можете либо отслеживать их в пошаговой таблице, либо запускать пакетное задание для извлечения информации.

[1] Некоторые СУБД даже предоставляют собственный тип массива, который может даже лучше подходить для хранения, не требуя шага синтаксического анализа, но может вызвать проблемы с полнотекстовым поиском.

13
7.09.2008 11:47:34
Вам известна какая-либо полнотекстовая поисковая система, которая не находит вариации в слове? Например, поиск книг возвращает книги? Кроме того, что вы делаете с тегами типа "c ++"? SQL Server, например, лишил бы знаки плюс в индексе. Спасибо.
Jonathan Wood 18.01.2011 01:41:42
Попробуйте Сфинкса - sphinxsearch.com
Roman 9.02.2011 13:45:29
Этот учебник из трех частей может быть полезен для тех, кто идет по этому пути (полнотекстовый поиск). Он использует встроенные средства PostgreSQL: shisaa.jp/postset/postgresql-full-text-search-part-1.html
Will 14.05.2014 21:42:15
это лучше, чем выбранный ответ с точки зрения производительности?
AMB 22.10.2017 07:49:24
как насчет хранения в varchar 255 тегов, разделенных запятыми, и добавления к ним текстового индекса kfull?
AMB 22.10.2017 07:50:34

Если вы используете базу данных, которая поддерживает map-Reduce, например, couchdb, хранение тегов в текстовом поле или поле списка действительно является лучшим способом. Пример:

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

Выполнение этого с group = true сгруппирует результаты по имени тега и даже вернет счетчик количества раз, когда этот тег встречался. Это очень похоже на подсчет вхождений слова в тексте .

38
20.02.2012 04:47:45
+1 Приятно также видеть некоторые реализации NoSQL.
Xeoncross 18.03.2011 16:24:17
@NickRetallack Ссылка не работает. Если вы могли бы, пожалуйста, обновите этот ответ.
xralf 18.02.2012 10:21:31
Хорошо, я заменил ссылку на один на archive.org
Nick Retallack 20.02.2012 04:47:57

Обычно я согласен с Яаковом Эллисом, но в этом особом случае есть другое жизнеспособное решение:

Используйте две таблицы:

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

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

Это имеет несколько основных преимуществ:

Во-первых, это значительно упрощает разработку: в решении с тремя таблицами для вставки и обновления itemвы должны просмотреть Tagтаблицу, чтобы увидеть, есть ли уже записи. Тогда вы должны присоединиться к ним с новыми. Это не тривиальная задача.

Тогда это делает запросы проще (и, возможно, быстрее). Вам нужно выполнить три основных запроса к базе данных: вывести все Tagsдля одного Item, нарисовать облако тегов и выбрать все элементы для одного заголовка тега.

Все теги для одного элемента:

3-таблица:

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

2-Таблица:

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

Облако тегов:

3-таблица:

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

2-Таблица:

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

Предметы для одного тега:

3-таблица:

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

2-Таблица:

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

Но есть и некоторые недостатки: это может занять больше места в базе данных (что может привести к увеличению количества операций на диске, что медленнее), и это не нормализуется, что может привести к несоответствиям.

Аргумент размера не так силен, потому что сама природа тегов заключается в том, что они обычно довольно малы, поэтому увеличение размера невелико. Можно утверждать, что запрос для заголовка тега намного быстрее в небольшой таблице, которая содержит каждый тег только один раз, и это, безусловно, верно. Но если принять во внимание экономию, связанную с отсутствием необходимости присоединения, и тот факт, что вы можете построить для них хороший индекс, это может легко компенсировать это. Это, конечно, сильно зависит от размера базы данных, которую вы используете.

Аргумент о несостоятельности тоже немного спорный. Теги являются свободными текстовыми полями, и нет ожидаемой операции, такой как «переименовать все теги« foo »в« bar »».

Итак tldr: я бы пошел на решение двух столов. (На самом деле я собираюсь. Я нашел эту статью, чтобы увидеть, есть ли веские аргументы против этого.)

83
4.12.2013 16:49:34
Означает ли «Index: ItemId, Title» индекс для каждого или один индекс, содержащий оба?
DanMan 3.12.2013 11:23:32
Обычно два индекса. Может зависеть от базы данных, которую вы используете.
Scheintod 4.12.2013 16:50:54
В таблице тегов есть ItemId и Tag составной ключ? или у тебя тоже есть ПК?
Rippo 21.03.2014 18:41:08
таким образом, вы не можете создавать «неиспользуемые» теги, поэтому для элемента необходимо выполнить функцию «добавить тег». По другому методу функцию «добавить тег» можно выполнить независимо
Gianluca Ghettini 22.04.2017 11:42:50
@Quilang. Я все еще верю, что это зависит от того, чем вы занимаетесь :) Я реализовал это обоими способами в разных проектах. В моем последнем случае я получил решение с тремя таблицами, потому что мне требовался «тип тега» (или некоторая другая метаинформация о теге), и я мог повторно использовать некоторый код от близкого родственника тегов: параметров. Но в том же проекте я использовал именно этот метод для еще более близкого родственника: флаги (например, «продано», «новый», «горячий»)
Scheintod 24.10.2018 06:56:29

Я бы предложил следующий дизайн: Item Table: Itemid, taglist1, taglist2
это будет быстро и позволит легко сохранять и извлекать данные на уровне элемента.

Параллельно создайте другую таблицу: тег Tag не делает тег уникальным идентификатором, и если во 2-м столбце, в котором содержится свободное место, допустим, 100 элементов создают еще одну строку.

Теперь при поиске предметов по тегу это будет супер быстро.

0
28.11.2015 09:51:15
ru.wikipedia.org/wiki/First_normal_form, хотя есть исключения из этого, вы можете денормализовать, но не здесь
Dheeraj 24.12.2015 06:27:09