Neo4j - 如何匹配仅前n个关系?

6

有没有一种默认的方法只匹配前n个关系,而不是稍后在LIMIT n过滤呢?

我有这个查询:

START n=node({id})
MATCH n--u--n2
RETURN u, count(*) as cnt order by cnt desc limit 10;

假设n--u关系的数量非常高,我想放宽此查询,并随机选择前100个关系,然后继续使用u--n2...
这是为协同过滤任务而设计的,假设用户之间相似度较高,我不想匹配所有用户u,而是一个随机子集。这种方法应该具有更快的性能 - 现在我的查询时间约为500毫秒,但希望将其降低到50毫秒以下。
我知道我可以将上述查询分为两个单独的查询,但仍然在第一个查询中遍历所有用户,然后在稍后限制输出。我想在match阶段限制最大关系数。
2个回答

4

您可以使用WITH将当前查询结果进行流水线处理,然后限制初始结果的数量,并继续在同一个查询中进行:

START n=node({id})
MATCH n--u
WITH u
LIMIT 10
MATCH u--n2
RETURN u, count(*) as cnt 
ORDER BY cnt desc 
LIMIT 10;

以上查询将给您返回前10个找到的 u,然后继续查找前十个匹配的 n2

可选地,您可以省略第二个 LIMIT,这样您将得到第一个十个 u 的所有匹配的 n2(这意味着如果它们匹配了前10个 u,则可能返回超过10行)。


没错,但我担心第一个 limit 10 会限制所有找到的 u,因此仍在处理我不想要的 u。或者有什么变化,Cypher 解析器现在不再遍历所有关系,而是只解析前10个吗? - ulkas
2
第一个 limit 10 应该使遍历器在找到前10个 u 后停止。它不应该处理所有可能的 u。如果您怀疑它正在处理超过它应该处理的内容,您应该向neo4j提交错误报告。 - ean5533

1

这不是你问题的直接解决方案,但由于我遇到了类似的问题,我的解决方法可能对你有用。

我需要做的是:通过索引获取关系(可能会有成千上万个),并获取它们的起始节点。由于起始节点始终与该索引查询相同,因此我只需要第一个关系的起始节点。

由于我无法使用Cypher实现这一点(ean5533提出的查询也没有任何改善),我正在使用一个简单的未管理的扩展好模板)。

@GET
@Path("/address/{address}")
public Response getUniqueIDofSenderAddress(@PathParam("address") String addr, @Context GraphDatabaseService graphDB) throws IOException
{
    try {
        RelationshipIndex index = graphDB.index().forRelationships("transactions");
        IndexHits<Relationship> rels = index.get("sender_address", addr);

        int unique_id = -1;
        for (Relationship rel : rels) {
            Node sender = rel.getStartNode();
            unique_id = (Integer) sender.getProperty("unique_id");
            rels.close();
            break;
        }

        return Response.ok().entity("Unique ID: " + unique_id).build();
    } catch (Exception e) {
        return Response.serverError().entity("Could not get unique ID.").build();
    }
}

对于这个案例来说,加速非常好。
我不知道您的具体用例,但由于我认为Neo4j甚至支持HTTP流式传输,因此您应该能够将查询转换为未托管扩展并仍然获得完整的性能。 例如,"java-querying"您所有符合条件的节点并将部分结果发射到HTTP流中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接