Які реалізації можуть швидко шукати перетин множин (система тегів)

  • MySQL
  • SQL

Хотілося б запитати, хто як вирішує завдання з пошуком за тегами. Яким ПО.

Два основні умови:
1) Завдання - система повинна швидко (

1-50 мс) відповісти на питання в дусі "знайти всі документи в яких є (Тег-1 або Тег-30 або Тег-100500 або.) І (Тег-50 або Тег-1000 або.) І.". У АБО може бути до двох десятків тегів, І умов може бути під десяток.
2) Оскільки дані можуть часто оновлюватися, то потрібно досягти мінімального часу актуалізації внесених змін.

Пробував робити на Redis використовуючи типи SET і BITMAP (приблизно як тут "Швидкий фільтр каталогу для інтернет-магазинів на."). SET не підійшов (в set-а зберігалися ID документів), тому що в разі перетину навіть двох множин по 100к думає довше, ніж потрібно. BITMAP не підійшов через сильну розрядженого по ID документів, як наслідок зайва витрата пам'яті на "дірки". Загалом якщо безлічі великі, то Redis з коробки підходить погано.

Зараз працює варіант на Sphinx. ID тегів пишуться в sql_attr_multi. Це забезпечує заданий вимога по швидкості пошуку документів. Вимога оновлень вирішується побудовою головного і delta індексу. Основний індекс (за яким ведемо пошук) оголошений як distributed. Це в принципі непогано працює, але часом буває багато нових змін і дельта індекс починає гальмувати. Перестроювання головного індексу займає кілька хвилин (зараз щось близько 3.5м id документів в ньому). Начебто не довго, але планується збільшення кількості документів в десятки разів. Час актуалізації даних теж почне збільшуватися.

Хотів би дізнатися, чи є якісь інші варіанти вирішення (С? Tarantool? Elasticsearch?) І хто що використовує.

sim3x. З усім сміттям база займає щось близько 4 Гб. Тобто да, вся в пам'ять заходить. Але це не принципово як мені здається, тому що для поточного завдання є тупо безліч ID представляють собою unsigned 32-ий int. Якщо заганяти їх в Redis (за схемою: ключ "tagId.ID_тега" (наприклад "tagId.100"), значення SET в якому ID документів пов'язаних з цим тегом, тобто ID документа дублюється багато разів), то виходить щось то близько 2,5Гб.

Олексій Сундуков.
Тоді варто покрутити налаштування своєї СУБД
Подивися таблиці-індекси-повільні запити, як працюють твої запити

Не будемо поки про редис думати - тут є багато накладних витрат і деталей
Поки СУБД цілком поміщається в пам'ять - потрібно оптимізувати її

sim3x. Ні, не так. IN по суті і є OR. Крім того початкова задача зовсім інша. Потрібно "знайти ID всіх документів у яких є (тег-1 або тег-500 або тег-N.) І (тег-20 або тег-30) І.". Інших варіантів крім як join я не бачу. Загалом в рамках РСУБД це погано працює.

sim3x. Не має, я в курсі. Про сішное розширення під постгрі я звичайно думав, але якщо чисто сішний код не може зробити перетин N множин (що представляють собою int) швидше, ніж сфінкс, то значить курити в сторону сішного розширення під Побудуй рано. Я звичайно розумію, що напевно код не дуже оптимальний і є над чим подумати, але я не сішнік тому самотужки не допив. А оскільки завдання в принципі не унікальна, я якось сподіваюся, що хто-то вже щось подібне створив у вигляді готової бібліотеки. Ось і ищю.

Олексій Сундуков. в постгресе є нативний intersection
Сішное розширення знадобиться вже коли вичерпаються можливості кешування для клієнтів

По заданих параметрах вибирається будь-який документ менше ніж за секунду
група документів в межах двох тижнів (неважливо скільки документів) вибирається не більше 10 секунд
максимальний час вибірки всіх документів по всім тегам 20 хвилин

сервер майже дно - 1 проц 8 ядер, 58 Гб оперативки, при цьому на це сервері ще 32 бази активно використовуються (тільки диски хороші)

Вивчайте мат частина
- секціонування
- індекси
- файлові групи
- Інмеморі

База 4 гіга :))))) у мене ця база 700 ГБ і таблиці понад 100 Гб нічого так нормальненько, дуже навіть швидко вибирається :)

Упевнений на інших платформах теж можна оптимізувати

Млинець!
База 4 Гіга - Карл. ти чуєш 4 Гіга Карл.
(При вашій задачі одні індекси повинні були звістку хз скільки, у мене індекси важать більше ніж дані в 1,5 рази)

igruschkafox для мене секунда це ДУЖЕ довго. (А ще у мене MySQL). Фільтр повинен відпрацьовувати максимум за 50 мс. У примітивній таблиці в 2 поля (які int-и) tagId, docId накосячіть досить складно. І записів там всього лише на 4М. Начебто все просто. І працює. Тільки в потрібне мені контексті занадто повільно. Скільки часу у вас в базі йде на відповідь на питання "знайти id документів в яких є (тег-1 або тег-2 або тег-10) і (тег-100 або тег-200 або тег-300.) І.", тобто по суті банальний IN () and IN () and IN (). при цьому в такій вибірці мінімум пару тегів пов'язані більш ніж з 100к документів. Нехай в IN буде до 10 тегів, і таких умов максимум теж 10. Як виглядає запит і скільки він виконується?

Про секціонування я в курсі. Ось хочу зробити на Postgresql через успадкування таблиць.

Вёбних справ майстер

Залишу як ремарку для історії. На даний момент схема в sphinx виходить найшвидшою. Питання з дельта індексом зважився просто більш частим його перерахунком. Тепер додаток стежить за його розмірів і як тільки в ньому більше 20к документів, запускається ротирование. Виходить необхідна швидкість вибірки навіть на складних запитах.

А обов'язково отримувати ВСЕ? Все ж все одно відразу користувач не прочитає. Можна отримувати кожен тег окремо, а після AJAX-ом підтягувати і. якщо треба, сортувати на клієнті.