У DailyWatch наша панель «схожі відео» починалася зі скромного запиту SQLite. Він об'єднував три таблиці, підраховував перетин тегів і повертав ранжований список. Для невеликого каталогу цього було достатньо. Відео з приготуванням їжі з тегами «italian» та «pasta» виводило інші відео з такими ж тегами, і користувачі клікали. Результат виглядав релевантним, оскільки метадані були чистими, а бібліотека — невеликою.
Потім каталог виріс, а очікування аудиторії змінилися. Люди не просто хотіли більше відео з ідентичними тегами. Вони хотіли кліп, який сорок відсотків глядачів дивилися одразу після поточного. Вони хотіли нішевий канал, який постійно з'являвся в тих самих нічних сесіях перегляду, навіть якщо в його описі не було нічого про початкове відео, а теги були мінімальними. Це поведінкові патерни, а не збіги метаданих. SQLite не міг виразити їх, не перетворюючись на непідтримуване гніздо self-join та рекурсивних спільних табличних виразів (CTE). Кожен новий сигнал, який ми намагалися моделювати, будь то спільний перегляд або суміжність сесій, додавав затримку та когнітивне навантаження. Ми мали графову задачу, втиснуту в реляційну оболонку.
Я переніс шар рекомендацій на Apache AGE.
Apache AGE — це розширення PostgreSQL, яке додає графові запити openCypher до бази даних, яку ви вже використовуєте. Це не окремий сервер. Це не sidecar. Він працює всередині Postgres, що означало, що ми могли побудувати мережу спільного перегляду, не розгортаючи виділений кластер Neo4j і не вивчаючи абсолютно новий операційний регламент. Для невеликої команди без інженера з надійності баз даних ця відмінність мала величезне значення.
Чому розширення краще за нову базу даних
Додавання графової бази даних до вашого стека легко на білій дошці, але дорого в продакшені. Вам потрібні нові дашборди моніторингу, нові процедури резервного копіювання, нові пули з'єднань і нова логіка відмови (failover). AGE дозволяє уникнути всього цього, оскільки він живе всередині вашого існуючого екземпляра Postgres.
Є чотири практичні причини, чому це спрацювало для нас.
- Жодної нової інфраструктури. Оскільки AGE — це розширення, ваш поточний графік
pg_dump, ваші існуючі репліки та стандартні перевірки стану Postgres продовжують працювати. Вам не потрібно переконувати операційну команду піклуватися про ще одне сховище даних. - Змішані навантаження в одному запиті. AGE дозволяє писати Cypher всередині SQL. Ви можете виконати обхід графа, щоб знайти відео-кандидати, а потім об'єднати цей набір результатів з вашою реляційною таблицею
usersдля дотримання регіональних обмежень контенту або з реляційною таблицеюsponsorships, щоб знизити пріоритет певних каналів. Один round-trip. Дві мови запитів, що співпрацюють. - Портативність. Cypher — це відкрита, добре задокументована мова графових запитів. Якщо DailyWatch переросте AGE і пізніше знадобиться міграція на Neo4j або Memgraph, логіка запитів перенесеться з мінімальним переписуванням. Ви не прив'язані до пропрієтарного діалекту.
- Сумісність. Оскільки дані зрештою зберігаються в PostgreSQL, ваш існуючий інструментарій PHP або Python не змінюється. Ви підключаєтеся за допомогою того ж драйвера, використовуєте ті ж рядки підключення та отримуєте рядки так само. Графова логіка знаходиться на рівні запитів, а не на рівні додатка.
Моделювання спільного перегляду
Реалізація є простою. Ми визначили вузли для сутностей, які нас цікавили: Video та Channel. Потім ми визначили ребра для зв'язків між ними. Ребро PUBLISHED пов'язує Channel з Video. Ребро CO_VIEWED пов'язує одне Video з іншим, несучи властивість weight, яка представляє, як часто два відео з'являлися в одній сесії перегляду.
Ця модель фіксує те, чого не може зробити SQL на основі тегів: неявну структуру
