Как бы вы разработали базу данных для поддержки следующих функций тегирования:
- элементы могут иметь большое количество тегов
- поиск всех элементов, помеченных данным набором тегов, должен быть быстрым (элементы должны иметь ВСЕ теги, так что это поиск AND, а не OR)
- создание / запись элементов может быть медленнее, чтобы обеспечить быстрый поиск / чтение
В идеале поиск всех элементов, помеченных (как минимум) набором из n заданных тегов, должен выполняться с использованием одного оператора SQL. Поскольку количество тегов для поиска, а также количество тегов для любого элемента неизвестны и могут быть большими, использование JOIN нецелесообразно.
Любые идеи?
Спасибо за все ответы до сих пор.
Однако, если я не ошибаюсь, приведенные ответы показывают, как выполнять ИЛИ-поиск по тегам. (Выберите все элементы, которые имеют один или несколько тегов n). Я ищу эффективный И-поиск. (Выберите все элементы, которые имеют ВСЕ n тегов - и, возможно, больше.)
источник
select * from question q inner join question_has_tag qt where tag_id in (select tag_id from tags where (what we want) minus select tag_id from tags where (what we don't)
должен быть в порядке и масштабироваться, если в средней таблице есть правильные индексы b-дереваВот хорошая статья о маркировке схем базы данных:
http://howto.philippkeller.com/2005/04/24/Tags-Database-schemas/
наряду с тестами производительности:
http://howto.philippkeller.com/2005/06/19/Tagsystems-performance-tests/
Обратите внимание, что выводы очень специфичны для MySQL, который (по крайней мере, в 2005 году на момент написания) имел очень плохие характеристики полнотекстовой индексации.
источник
Я не вижу проблемы с простым решением: таблица для элементов, таблица для тегов, перекрестная таблица для «тегирования»
Индексы на перекрестной таблице должны быть достаточно оптимизационными. Выбор соответствующих предметов будет
И пометка будет
что, правда, не так эффективно для большого количества сравниваемых тегов. Если вы хотите сохранить количество тегов в памяти, вы можете начать запрос с тегов, которые встречаются не часто, поэтому последовательность AND будет оценена быстрее. В зависимости от ожидаемого количества сравниваемых тегов и ожидаемого совпадения с любым из них, это может быть хорошим решением, если вы хотите сопоставить 20 тегов и ожидать, что некоторый случайный элемент будет соответствовать 15 из них, тогда это все равно будет тяжелым в базе данных.
источник
Я просто хотел подчеркнуть, что статья, на которую ссылается @Jeff Atwood ( http://howto.philippkeller.com/2005/04/24/Tags-Database-schemas/ ), очень тщательна (в ней рассматриваются достоинства трех различных схем). подходов) и имеет хорошее решение для запросов AND, которые обычно будут работать лучше, чем те, что были упомянуты здесь до сих пор (т.е. он не использует коррелированный подзапрос для каждого термина). Также много хороших вещей в комментариях.
PS - подход, о котором все говорят здесь, упоминается как решение "Toxi" в статье.
источник
Возможно, вы захотите поэкспериментировать с решением не строго в базе данных, таким как реализация Java Content Repository (например, Apache Jackrabbit ), и использовать поисковую систему, построенную на основе этого, например, Apache Lucene .
Это решение с соответствующими механизмами кэширования может дать лучшую производительность, чем собственное решение.
Однако я не думаю, что в приложениях малого или среднего размера вам потребуется более сложная реализация, чем нормализованная база данных, упомянутая в предыдущих статьях.
РЕДАКТИРОВАТЬ: с вашим разъяснением кажется более убедительным использовать JCR-подобное решение с поисковой системой. Это значительно упростит ваши программы в долгосрочной перспективе.
источник
Самый простой способ - создать таблицу тегов .
Target_Type
- если вы помечаете несколько таблицTarget
- ключ к помечаемой записиTag
- текст тегаЗапрос данных будет что-то вроде:
ОБНОВЛЕНИЕ В
зависимости от ваших требований и условий, приведенный выше запрос может превратиться в нечто подобное
источник
Второе предложение @Zizzencs, которое вы могли бы пожелать, что-то, что не полностью (R) ориентировано на DB
Почему-то я считаю, что использование простых полей nvarchar для хранения этих тегов с надлежащим кэшированием / индексацией может привести к более быстрым результатам. Но это только я.
Я реализовал системы тегов с использованием 3 таблиц для представления взаимосвязи «многие ко многим» (Item Tag ItemTags), но я предполагаю, что вы будете иметь дело с тегами во многих местах, я могу вам сказать, что с 3 таблицами нужно манипуляции / запросы одновременно все время определенно сделает ваш код более сложным.
Вы можете подумать, стоит ли дополнительная сложность.
источник
Вы не сможете избежать объединений и все же будете несколько нормализованы.
Мой подход заключается в том, чтобы иметь таблицу тегов.
Затем у вас есть столбец TagXREFID в вашей таблице предметов.
Этот столбец TagXREFID представляет собой FK для третьей таблицы, я назову его TagXREF:
Таким образом, получить все теги для элемента было бы что-то вроде:
И чтобы получить все элементы для тега, я бы использовал что-то вроде этого:
Чтобы AND связать вместе несколько тегов, вы должны немного изменить вышеприведенный оператор, чтобы добавить AND Tags.TagName = @ TagName1 AND Tags.TagName = @ TagName2 и т. Д. ... и динамически построить запрос.
источник
Что мне нравится делать, так это иметь несколько таблиц, которые представляют необработанные данные, так что в этом случае у вас будет
Это работает быстро для времени записи и сохраняет все нормализованным, но вы также можете заметить, что для каждого тега вам нужно будет объединять таблицы дважды для каждого последующего тега, который вы хотите добавить в AND, так что чтение будет медленным.
Решением для улучшения чтения является создание кеширующей таблицы по команде путем настройки хранимой процедуры, которая по существу создает новую таблицу, которая представляет данные в плоском формате ...
Затем вы можете подумать, как часто необходимо обновлять таблицу Tagged Item, если она присутствует при каждой вставке, а затем вызвать хранимую процедуру в событии вставки курсора. Если это почасовая задача, то настройте почасовую работу для ее запуска.
Теперь, чтобы быть действительно умным в поиске данных, вам нужно создать хранимую процедуру для получения данных из тегов. Вместо того, чтобы использовать вложенные запросы в массивном выражении case, вы хотите передать один параметр, содержащий список тегов, которые вы хотите выбрать из базы данных, и вернуть набор записей Items. Это было бы лучше в двоичном формате, используя побитовые операторы.
В двоичном формате это легко объяснить. Скажем, есть четыре тега, которые должны быть назначены элементу, в двоичном виде мы могли бы представить, что
Если все четыре тега назначены объекту, объект будет выглядеть следующим образом ...
Если только первые два ...
Тогда это просто случай поиска двоичных значений с единицами и нулями в столбце, который вы хотите. Используя побитовые операторы SQL Server, вы можете проверить наличие 1 в первом столбце, используя очень простые запросы.
Проверьте эту ссылку, чтобы узнать больше .
источник
Перефразируя то, что сказали другие: уловка не в схеме , а в запросе .
Наивная схема Entities / Labels / Tags - правильный путь. Но, как вы видели, не сразу понятно, как выполнить запрос AND с большим количеством тегов.
Лучший способ оптимизировать этот запрос будет зависеть от платформы, поэтому я бы порекомендовал повторно пометить ваш вопрос вашей RDBS и изменить заголовок на что-то вроде «Оптимальный способ выполнить запрос И для базы данных тегов».
У меня есть несколько предложений по MS SQL, но я воздержусь, если это не та платформа, которую вы используете.
источник
Вариант к ответу выше - взять идентификаторы тегов, отсортировать их, объединить в виде ^ разделенной строки и хешировать их. Затем просто свяжите хеш с элементом. Каждая комбинация тегов создает новый ключ. Чтобы выполнить поиск AND, просто заново создайте хеш с указанными идентификаторами тегов и выполните поиск. Изменение тегов на элементе приведет к воссозданию хеша. Элементы с одинаковым набором тегов имеют одинаковый хэш-ключ.
источник
Если у вас тип массива, вы можете предварительно агрегировать необходимые данные. Смотрите этот ответ в отдельной теме:
в чем полезность типа массива?
источник