Neo4j - 不合适的比赛计数

时间:2017-02-14 07:07:06

标签: neo4j cypher query-performance

我正在以两种不同的方式进行一些x操作。但是在第二种方法中,匹配查询的计数是不合适的,这是不可接受的。请告知我遗失的地方。

第一种方式:

profile
WITH [1234] AS sellers_list,
[12345] AS buyers_list

MATCH (buyer:Person) WHERE buyer.person_guid IN buyers_list
MATCH (seller:Person) WHERE seller.person_guid IN sellers_list

RETURN count(buyer),size(buyers_list),count(seller),size(sellers_list)

结果如下: enter image description here

第二种方式

profile
WITH [1234] AS sellers_list,
[12345] AS buyers_list

MATCH (seller_member:Person)-[r:TEAM_MEMBER]-(seller_teammate:Person) 
    WHERE seller_member.person_guid IN sellers_list

WITH FILTER(x IN COLLECT(seller_teammate.person_guid) WHERE NOT(x in sellers_list)) AS sellerteam, sellers_list, buyers_list

MATCH (seller_member:Person)-[r:EMPLOYED_BY]->(b:Organization)
MATCH (b)<-[s:EMPLOYED_BY]-(org_member:Person) 
    WHERE seller_member.person_guid=sellers[0]

WITH FILTER(x IN COLLECT(org_member.person_guid) WHERE NOT(x IN sellerteam)) AS org_members,sellers_list,sellerteam,buyers_list 

WITH sellers+sellerteam+org_members AS all_org_members,sellers_list,sellerteam,org_members,buyers_list


MATCH (buyer:Person) WHERE buyer.person_guid IN buyers_list
MATCH (seller:Person) WHERE seller.person_guid IN all_org_members

RETURN count(buyer),size(buyers_list),count(seller),size(sellers_list)

结果如下: enter image description here

在第二种方法中,我没有在任何地方更改buyer_list,我只计算卖家团队成员和卖家组织成员。但买家的数量正在发生变化。为什么呢?

分析上述查询显示: enter image description here

看看这张图片,买家的数量只有1,但为什么计数会返回45k。

并且,为什么90k db命中45k节点?任何具体原因以及如何在此处减少db命中。

1 个答案:

答案 0 :(得分:1)

要记住的一个关键事项是Neo4j中的查询会构建行和列。当您在断开连接的模式之间执行匹配时,您倾向于获得针对当前行的笛卡尔积(并且您可以在查询计划中看到它)。也就是说,笛卡尔产品不一定是错误或坏事。如果没有笛卡尔产品,那么您的指南列表中的所有卖家都无法匹配,而且它只是针对您的单行的笛卡尔产品。

如果您在卖家匹配后立即返回所有值,您会看到每一行都有不同的卖家,但所有其他字段(包括买家)都是相同的。

您希望获得一系列不同的值count(distinct buyer),这样可以为您提供预期的买家数量1.

对于90k命中,NodeUniqueIndexSeek每次查找需要2 db命中,并且您对45k值执行了查找,因此数学运算完成。

修改

如果你仍然怀疑,你可以单独尝试一个大的独特查找(或尽可能多的隔离,同时必须首先查找45k guid)。

MATCH (p:Person)
WITH p LIMIT 45000
WITH COLLECT(p.person_guid) as guids
// you can always take the above subquery, returning 1, to see the timing of just collecting guids
MATCH (p:Person)
WHERE p.person_guid in guids
RETURN COUNT(p) as count