Apache AGE를 사용한 Postgres에서의 비디오 관계 쿼리

관계형 데이터베이스는 깊은 관계를 처리하는 데 어려움을 겪습니다.

TrendVidStream에서는 8개 지역에 걸친 스트리밍 타이틀 카탈로그를 관리합니다. 원래는 FTS5를 포함한 SQLite를 사용했습니다. 전체 텍스트 검색과 간단한 배포에는 효과적이었습니다.

문제는 사용자들이 복잡한 질문을 하기 시작하면서 발생했습니다. 그들은 다음과 같은 질문을 원했습니다: "이 특정 감독과 배우들이 출연하는 이 스릴러 영화에서 두 단계 또는 세 단계 떨어진 다른 영상은 무엇인가?"

SQL에서는 이를 위해 많은 셀프 조인(self-join)이 필요합니다. 단계(hop)가 추가될 때마다 쿼리 유지보수가 어려워지고 실행 속도가 느려집니다. 조인 팬아웃(join fan-out) 현상은 악몽과 같습니다.

저희는 PostgreSQL에 Apache AGE 확장을 추가하여 그래프 레이어를 도입함으로써 이 문제를 해결했습니다.

이 방식이 효과적인 이유는 다음과 같습니다:

• PostgreSQL을 그대로 유지할 수 있습니다. 동일한 연결, 트랜잭션, 백업 도구를 사용합니다. Neo4j와 같은 별도의 데이터베이스가 필요하지 않습니다. • 그래프 데이터와 관계형 데이터를 혼합할 수 있습니다. Cypher 쿼리를 실행하고 그 결과를 표준 SQL 테이블과 조인할 수 있습니다. • 가변적인 깊이를 쉽게 처리할 수 있습니다. 1단계에서 3단계 사이의 연결을 찾는 것은 Cypher에서 간단한 명령으로 가능합니다. • 단순함을 유지할 수 있습니다. 그래프는 데이터의 투영(projection)일 뿐, 별도의 진실의 원천(source of truth)이 아닙니다.

저희 모델은 네 가지 정점(vertex) 레이블을 사용합니다:

  • Video
  • Person
  • Platform
  • Region

저희는 SIMILAR_TO, WORKED_ON, AVAILABLE_IN과 같은 특정 엣지(edge) 타입을 사용합니다.

한 가지 중요한 교훈은 항상 진입점(entry point)에 인덱스를 생성해야 한다는 것입니다. 저희는 Video 정점의 ext_id 속성에 인덱스를 생성했습니다. 이것이 없으면 모든 탐색(traversal)이 느린 순차 스캔(sequential scan)으로 시작됩니다.

그 결과, 추천을 위한 깔끔하고 읽기 쉬운 쿼리를 얻을 수 있었습니다:

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);

이 쿼리는 독일에서 시청 가능한, 3단계 이내의 관련 비디오를 찾습니다. SQL이었다면 엄청난 양의 조인이 필요했겠지만, Cypher에서는 단순한 패턴으로 해결됩니다.

저희는 텍스트 검색을 위해 SQLite를 유지하고, 연결성을 위해 AGE를 사용했습니다. 각 도구가 가장 잘하는 역할을 수행하도록 한 것입니다.

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