Apache AGE on Postgres を使用したビデオのリレーションシップのクエリ

リレーショナルデータベースは、深いリレーションシップ(関係性)の扱いに苦労します。

TrendVidStream では、8つの地域にわたるストリーミングタイトルのカタログを管理しています。当初は FTS5 を備えた SQLite を使用していました。全文検索やシンプルなデプロイメントには適していました。

問題は、ユーザーが複雑な質問をし始めたときに発生しました。彼らは次のようなことを知りたがったのです。「この特定の監督と俳優が出演しているこのスリラー映画から、2ホップまたは3ホップ離れた場所には他に何があるだろうか?」

SQL では、これには多くの自己結合(self-join)が必要です。ホップが増えるたびに、クエリのメンテナンスは困難になり、実行速度も低下します。結合のファンアウト(fan-out)は悪夢のような状態になります。

私たちは、PostgreSQL 上で Apache AGE 拡張機能を使用してグラフレイヤーを追加することで、この問題を解決しました。

この分割がうまくいく理由は以下の通りです:

• PostgreSQL をそのまま使い続けられます。同じ接続、トランザクション、バックアップツールを使用できます。Neo4j のような別のデータベースを用意する必要はありません。 • グラフデータとリレーショナルデータを混在させることができます。Cypher クエリを実行し、その結果を標準的な SQL テーブルと結合できます。 • 可変的な深さを簡単に扱えます。1〜3 ホップにわたる接続を見つけることは、Cypher では単純なコマンドです。 • シンプルさを維持できます。グラフはデータの投影(projection)であり、別の「信頼できる唯一の情報源(source of truth)」ではありません。

私たちのモデルでは、4つの頂点ラベル(vertex labels)を使用しています:

  • Video
  • Person
  • Platform
  • Region

SIMILAR_TO、WORKED_ON、AVAILABLE_IN といった特定の型のエッジ(edge types)を使用しています。

重要な教訓が一つあります。エントリーポイント(開始点)には必ずインデックスを貼ることです。私たちは Video 頂点の ext_id プロパティにインデックスを貼っています。これがないと、すべてのトラバーサル(探索)が低速なシーケンシャルスキャンから始まってしまいます。

その結果、レコメンデーションのためのクリーンで読みやすいクエリが得られました:

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