Как лучше организовать хранение и релевантный поиск по нескольким тегам?
Есть база хранения сущностей (документов, изображение - не суть), у каждой сущности есть некий набор тегов. Например,
doc1 - tag1
doc2 - tag2
doc3 - tag3, tag4
doc4 - tag1, tag2, tag3
Ожидается, что сущностей будет несколько миллионов, уникальных тегов - предположительно, несколько сотен (возможно, тысячи).
Нужно организовать хранение и поиск по тегам так с учетом следующих условий:
- выдавать в результатах поиска, если совпал хотя бы 1 тег
- чем больше тегов совпало, тем выше в результатах поиска должна быть сущность
- нужна разбивка результата на страницы
Например, если задан поиск "tag1 tag3 tag5", то результат должен быть
doc4
doc1
doc3
Разумеется, первое, что напрашивается - это организация хранения many-to-many с промежуточной таблицей. Но не соображу, как с минимальными затратами получить нужный результат. Возможно, стоит посмотреть в сторону Sphinx или Elasticsearch, но не очень хочется поднимать дополнительный софт.
Перечень значений в SET предопределен, список допустимых значений задается при создании таблицы, и, насколько помню, этих допустимых значений может быть не больше 64.
Новые теги будут добавляться в процессе работы, их будут сотни
Akina, вот не надо вот этого вот. Каким местом здесь сет-то? Чтобы новый тег добавить, делать alter table, серьёзно?
Здесь-то однозначно именно что маны-туманы.
Чтобы новый тег добавить, делать alter table, серьёзно?
Нафига на каждый-то? SET маппится на BIGINT, так что только на каждый 64-й. А если программно маппить его на блоб - то вообще никаких проблем с расширением. И по сути это ну ничем не отличатся от дополнительных таблиц - просто вместо двух таблиц (метаданных и связующей) появляется одна таблица метаданных. С той лишь разницей, что для SET tcnm специально прикормленные инструменты, а классический M:N - это постоянные группировки или динамический SQL.
Akina, тогда я видимо, что-то не знаю про SET
Но честно говоря вот это "BIGINT, так что только на каждый 64-й" звучит как китайская грамота.
это все про mysql?
FanatPHP, да, он про MySQL. Он предлагает для работы с 60 тегами заводить один столбец типа ENUM, а для 200 - 4 столбца.
Справочник тегов получится вида «тег, столбец в котором его искать», а фильтрация такой: FIND_IN_SET('тег 1', tags1) or FIND_IN_SET('тег 200', tags4).
Как будет выглядеть ранжирование и можно ли эту портянку ускорить индексами сходу не скажу.