我是ArangoDB
的核心开发人员之一,尝试优化了您的查询。由于没有您的数据集
,所以我只能谈论我的测试数据集
,如果您可以验证我的结果,我会很高兴。
首先,我正在运行ArangoDB 2.7
,但在这种特殊情况下,我不希望与2.6
相比有太大的性能差异。
在我的数据集
中,我可以按原样执行您的查询,大约需要7秒
。建议采用以下修复方案:
在您的friends
语句中,您使用includeData: true
并且仅返回_id
。通过使用includeData: false
,GRAPH_NEIGHBORS
直接返回_id
,我们也可以在此处摆脱子查询。
LET friends = GRAPH_NEIGHBORS('graph',
@user,
{"direction": "any",
"edgeExamples": {
name: "FRIENDS_WITH"
}})
在我的机器上,这样做可以将时间缩短到约1.1秒。因此,我预计这将接近Neo4J的性能。
为什么会有如此高的影响?我们内部首先查找_id
值,而不实际加载文档JSON。在您的查询中,您不需要任何此类数据,因此我们可以安全地继续不打开它。
但现在是真正的改进时间
您的查询按“逻辑”方式进行,首先获取用户邻居,然后找到他们的邻居,计算foaf
出现的次数并对其进行排序。这必须在内存中构建完整的foaf
网络并将其作为一个整体进行排序。
你也可以用另一种方式做到:
1. 查找用户的所有friends
(只需_ids
)
2. 查找所有foaf
(完整文档)
3. 对于每个foaf
,查找所有foaf_friends
(只需_ids
)
4. 找到friends
和foaf_friends
的交集并统计它们的数量
这个查询应该是这样的:
LET fids = GRAPH_NEIGHBORS("graph",
@user,
{
"direction":"any",
"edgeExamples": {
"name": "FRIENDS_WITH"
}
}
)
FOR foaf IN GRAPH_NEIGHBORS("graph",
@user,
{
"minDepth": 2,
"maxDepth": 2,
"direction": "any",
"includeData": true,
"edgeExamples": {
"name": "FRIENDS_WITH"
}
}
)
LET commonIds = GRAPH_NEIGHBORS("graph",
foaf._id, {
"direction": "any",
"edgeExamples": {
"name": "FRIENDS_WITH"
}
}
)
LET common_friend_count = LENGTH(INTERSECTION(fids, commonIds))
SORT common_friend_count DESC
RETURN {user: foaf, common_friend_count: common_friend_count}
在我的测试图表中,它的执行时间约为0.024秒。
这使得执行速度比您当前在Neo4j中查询的速度快了 250倍 ,但由于我没有您的数据集
,因此无法验证它。如果您可以这样做并告诉我那就太好了。
最后一件事
对于edgeExamples:{name:“FRIENDS_WITH”}
与includeData
相同,在这种情况下,我们必须找到实际的边缘并查看它。如果根据名称将边缘存储在单独的集合中,然后删除edgeExamples,则可以避免这种情况。这将进一步提高性能(特别是如果有很多边缘)。
未来
敬请期待我们的下一个版本,我们正在为AQL添加更多功能,这将使您的查询更加容易,并应该提供另一个性能提升。