使用 Postgres 上的 Apache AGE 查询视频关系
关系型数据库在处理深层关系时往往力不从心。
在 TrendVidStream,我们管理着分布在八个地区的流媒体内容目录。最初我们使用的是带有 FTS5 的 SQLite。它在全文搜索和简单部署方面表现良好。
当用户提出复杂问题时,问题出现了。他们想知道:“除了这部由特定导演和演员出演的惊悚片,还有哪些与之相隔两到三步(hops)的内容?”
在 SQL 中,这需要进行多次自连接(self-joins)。每增加一步,查询就会变得更难维护且运行更慢。连接扇出(join fan-out)会变成一场噩梦。
我们通过在 PostgreSQL 上使用 Apache AGE 扩展添加了一个图层来解决这个问题。
以下是这种方案奏效的原因:
• 你可以保留 PostgreSQL。使用相同的连接、事务和备份工具。你不需要像 Neo4j 那样的独立数据库。 • 你可以混合图数据和关系数据。你可以运行 Cypher 查询,并将结果与标准 SQL 表进行连接。 • 你可以轻松处理可变深度。在 Cypher 中,查找一到三步之间的连接只需一个简单的命令。 • 你可以保持简单性。图是数据的投影,而不是一个独立的事实来源(source of truth)。
我们的模型使用四个顶点标签:
- Video
- Person
- Platform
- Region
我们使用特定的边类型,如 SIMILAR_TO、WORKED_ON 和 AVAILABLE_IN。
一个关键教训:务必为你的入口点建立索引。我们为 Video 顶点的 ext_id 属性建立了索引。如果没有这个索引,每次遍历都会从缓慢的顺序扫描(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);
该查询可以找到在德国可用且在三步范围内的相关视频。在 SQL 中,这将是一堆庞大的连接操作。而在 Cypher 中,它只是一个简单的模式(pattern)。
我们保留 SQLite 用于文本搜索,并使用 AGE 处理连接性。每种工具都发挥其所长。
