Запросы связей между видео с помощью Apache AGE на Postgres

Реляционные базы данных с трудом справляются с глубокими связями.

В TrendVidStream мы управляем каталогом стриминговых проектов в восьми регионах. Изначально мы использовали SQLite с FTS5. Это хорошо подходило для полнотекстового поиска и простых развертываний.

Проблемы начались, когда пользователи стали задавать сложные вопросы. Они хотели знать: «Что еще находится на расстоянии двух или трех связей от этого триллера с этим конкретным режиссером и этими актерами?»

В SQL это требует множества self-join (самосоединений). Каждый дополнительный шаг усложняет поддержку запроса и замедляет его выполнение. Разрастание соединений (join fan-out) превращается в кошмар.

Мы решили эту проблему, добавив графовый слой с помощью расширения Apache AGE для PostgreSQL.

Вот почему такое разделение эффективно:

• Вы сохраняете PostgreSQL. Вы используете те же соединения, транзакции и инструменты резервного копирования. Вам не нужна отдельная база данных, такая как Neo4j. • Вы смешиваете графовые и реляционные данные. Вы можете выполнять запросы Cypher и объединять их результаты со стандартными SQL-таблицами. • Вы легко работаете с переменной глубиной. Поиск связей на расстоянии от одного до трех шагов — это простая команда в Cypher. • Вы сохраняете простоту. Граф является проекцией ваших данных, а не отдельным источником истины.

Наша модель использует четыре метки вершин:

  • Video
  • Person
  • Platform
  • Region

Мы используем специфические типы ребер, такие как SIMILAR_TO, WORKED_ON и AVAILABLE_IN.

Один важный урок: всегда индексируйте точки входа. Мы индексируем свойство ext_id у вершин Video. Без этого каждый обход (traversal) начинается с медленного последовательного сканирования.

Результатом является чистый и читаемый запрос для рекомендаций:

SELECT * FROM cypher('discovery', $$
    MATCH (seed:Video {ext_id: 'vid_8842'})
    MATCH (seed)-[:SIMILAR_TO|WORKED_ON*1..3]-(rec:Video)-[:AVAILABLE_IN]->(:Region {code: 'DE'})
    WHERE rec.ext_id <> 'vid_8842'
    RETURN DISTINCT rec.ext_id, rec.title, rec.year
    LIMIT 24
$$) AS (ext_id agtype, title agtype, year agtype);

Этот запрос находит связанные видео в пределах трех шагов, которые доступны в Германии. В SQL это была бы огромная куча соединений. В Cypher — это простой паттерн.

Мы оставили SQLite для текстового поиска и использовали AGE для связей. Каждый инструмент делает то, что у него получается лучше всего.

Source: https://dev.to/ahmet_gedik778845/querying-video-relationships-with-apache-age-graph-extension-on-postgres-3g54