带有多个过滤器的Neo4J查询不会返回预期结果

时间:2014-04-22 19:26:03

标签: neo4j cypher neo4jclient

我使用以下Neo4JClient代码查询在一小时内,一周到21天内以及超过21天内到期的所有货件计数。

    var query = GraphClient.Cypher
        .Merge("(user:Person{InternalId:{userId}})")
        .WithParam("userId", userId)
        .With("user")
        .Match("(veh:Vehicle)<-[:HAS_VEHICLE_TYPE]-(load:ActiveShipment)-[:SHIPPED_BY]->(shipper:Shipper), (user)-[:WORKS_FOR_COMPANY]->(transporter:Transporter)")
        .Where("((load.RestrictedBidding = false) OR (user)-[:WORKS_FOR_COMPANY]->(transporter)<-[:HAS_TRANSPORTER]-(shipper)<-[:SHIPPED_BY]-(load))")
        .AndWhere("(load)-[:HAS_VEHICLE_TYPE]->(veh)<-[:HAS_VEHICLE]-(transporter)")
        .With("load, transporter, shipper, user")
        .Match("p=(shipFrom:City)<-[:SHIP_FROM_CITY]-(load)-[:SHIP_TO_CITY]->(shipTo:City)")
        .With("load,  collect(shipFrom) as FromCities, collect(shipTo) as ToCities, COUNT(filter(x IN Nodes(p) WHERE x:Shipment and x.PickupDate <= {withinWeek})) as LessThanWeek , COUNT(filter(x IN Nodes(p) WHERE x:Shipment and (x.PickupDate > {withinWeek}) and (x.PickupDate <= {within3Week}))) as NextWeekToFortnight, COUNT(filter(x IN Nodes(p) WHERE x:Shipment and x.PickupDate > {within3Week})) as LaterThan3Week")
        .WithParams(new { withinWeek = next7Days, within3Week = next3Weeks })
        .Return((load,FromCities, ToCities, LessThanWeek , NextWeekToFortnight, LaterThan3Week )=>new 
        { 
            OneWeek = Return.As<long>("LessThanWeek"),
            SevenToTwentyOneDays = Return.As<long>("NextWeekToFortnight"),
            Later = Return.As<long>("LaterThan3Week")

        });

这将生成以下Cypher查询

MERGE (user:Person{InternalId:2})   
WITH user   
MATCH (veh:Vehicle)<-[:HAS_VEHICLE_TYPE]-(load:ActiveShipment)-[:SHIPPED_BY]->(shipper:Shipper), 
      (user)-[:WORKS_FOR_COMPANY]->(transporter:Transporter)   WHERE ((load.RestrictedBidding = false) OR (user)-[:WORKS_FOR_COMPANY]->(transporter)<-[:HAS_TRANSPORTER]-(shipper)<-[:SHIPPED_BY]-(load))   AND (load)-[:HAS_VEHICLE_TYPE]->(veh)<-[:HAS_VEHICLE]-(transporter)   
WITH load, transporter, shipper, user   
MATCH p=(shipFrom:City)<-[:SHIP_FROM_CITY]-(load)-[:SHIP_TO_CITY]->(shipTo:City)   
WITH load,  collect(shipFrom) as FromCities, collect(shipTo) as ToCities, 
     COUNT(filter(x IN Nodes(p) WHERE x:Shipment and x.PickupDate <= 4/30/2014 12:00:00 AM +05:30)) as LessThanWeek , 
     COUNT(filter(x IN Nodes(p) WHERE x:Shipment and (x.PickupDate > 4/30/2014 12:00:00 AM +05:30) and (x.PickupDate <= 5/14/2014 12:00:00 AM +05:30))) as NextWeekToFortnight, 
     COUNT(filter(x IN Nodes(p) WHERE x:Shipment and x.PickupDate > 5/14/2014 12:00:00 AM +05:30)) as LaterThan3Week   
RETURN LessThanWeek AS OneWeek , NextWeekToFortnight AS SevenToTwentyOneDays , LaterThan3Week AS Later 

但结果并不是我所期望的,因为我得到OneWeek,SevenToTwentyOneDays&amp;后来全部为1。

澄清我在做什么:我想要做的是首先根据我的选择标准获得所有负载,然后想要根据它们在交货日期的位置获得这些负载的计数并且仅返回计数。因此在此查询中确实需要WITH。

Q1:这甚至是一个有效的查询吗?以及如何解决它。

Q2:使用上述过滤器是否会影响我的查询性能,如果是,是否有更简单的方法可以做到这一点?

修改 BTW上面粘贴的Cypher查询来自neo4jClient的调试文本,这意味着实际查询已参数化,但调试文本正在写出参数值以便于理解,因此日期编写不正确。

此致 基兰

3 个答案:

答案 0 :(得分:0)

Q1:Cypher不支持日期/时间字符串(例如&#34; 4/30/2014 12:00:00 AM +05:30&#34;)。我建议使用纪元时间(以毫秒为单位) - 大概是你的节点&#39;日期/时间属性正在使用它?

Q2:这是一个稍微简单(可能更快)的查询。你有很多重复的模式,已被删除。我能够提出一个统一的MATCH模式。另外,我建议使用参数iddate1date2,这将允许neo4j引擎缓存执行计划并在每个查询中重复使用它:

MERGE (user:Person{InternalId:{id}})   
WITH user   
MATCH (user)-[:WORKS_FOR_COMPANY]->(transporter:Transporter)-[:HAS_VEHICLE]->(veh:Vehicle)<-[:HAS_VEHICLE_TYPE]-(load:ActiveShipment)-[:SHIPPED_BY]->(shipper:Shipper)
WHERE ((load.RestrictedBidding = false) OR (transporter)<-[:HAS_TRANSPORTER]-(shipper)<-[:SHIPPED_BY]-(load))   
WITH load, transporter, shipper, user   
MATCH p=(shipFrom:City)<-[:SHIP_FROM_CITY]-(load)-[:SHIP_TO_CITY]->(shipTo:City)   
WITH load,  collect(shipFrom) as FromCities, collect(shipTo) as ToCities, 
     COUNT(filter(x IN Nodes(p) WHERE x:Shipment and x.PickupDate <= {date1})) as LessThanWeek , 
     COUNT(filter(x IN Nodes(p) WHERE x:Shipment and (x.PickupDate > {date1}) and (x.PickupDate <= {date2}))) as NextWeekToFortnight, 
     COUNT(filter(x IN Nodes(p) WHERE x:Shipment and x.PickupDate > {date2})) as LaterThan3Week   
RETURN LessThanWeek AS OneWeek , NextWeekToFortnight AS SevenToTwentyOneDays , LaterThan3Week AS Later;

答案 1 :(得分:0)

过滤器可以减小集合的大小,可能减少到零,但它仍然是一个集合。计算集合将返回集合的数量,而不是集合中的项目数。无论过滤器做什么,集合的数量都是相同的(在您的情况下为1)。

WITH [1,2] AS nn
RETURN COUNT (FILTER (n IN nn WHERE n > 0)) AS cnt;
==> +-----+
==> | cnt |
==> +-----+
==> | 1   |
==> +-----+
==> 1 row
==> 20 ms

如果您将过滤条件更改为n > 1n > 2,它仍会返回1,因为仍有一个集合。如果您希望过滤器更改结果,则可能需要使用length

WITH [1,2] AS nn
RETURN LENGTH (FILTER (n IN nn WHERE n > 0)) AS cnt;
==> +-----+
==> | cnt |
==> +-----+
==> | 2   |
==> +-----+
==> 1 row
==> 20 ms
neo4j-sh (?)$ 

我不太了解您的查询,所以我不知道如何回答其余问题。特别是,a)哪个节点具有日期属性?和b)为什么要在路径p中的所有节点上测试日期属性?您可以将示例数据放在a console中,以便更轻松地回答。

答案 2 :(得分:0)

终于发现我做错了什么。

这部分代码不正确。

WITH load,  collect(shipFrom) as FromCities, collect(shipTo) as ToCities, 
     COUNT(filter(x IN Nodes(p) WHERE x:Shipment and x.PickupDate <= 4/30/2014 12:00:00 AM +05:30)) as LessThanWeek , 
     COUNT(filter(x IN Nodes(p) WHERE x:Shipment and (x.PickupDate > 4/30/2014 12:00:00 AM +05:30) and (x.PickupDate <= 5/14/2014 12:00:00 AM +05:30))) as NextWeekToFortnight, 
     COUNT(filter(x IN Nodes(p) WHERE x:Shipment and x.PickupDate > 5/14/2014 12:00:00 AM +05:30)) as LaterThan3Week   
RETURN LessThanWeek AS OneWeek , NextWeekToFortnight AS SevenToTwentyOneDays , LaterThan3Week AS Later 

相反,我需要的是这样的东西:

WITH load,  collect(shipFrom) as FromCities, collect(shipTo) as ToCities, 
     filter(x IN Nodes(p) WHERE x:Shipment and x.PickupDate <= 4/30/2014 12:00:00 AM +05:30) as LessThanWeek , 
     filter(x IN Nodes(p) WHERE x:Shipment and (x.PickupDate > 4/30/2014 12:00:00 AM +05:30) and (x.PickupDate <= 5/14/2014 12:00:00 AM +05:30)) as NextWeekToFortnight, 
     filter(x IN Nodes(p) WHERE x:Shipment and x.PickupDate > 5/14/2014 12:00:00 AM +05:30) as LaterThan3Week   
RETURN 
   COUNT( DISTINCT LessThanWeek) AS OneWeek , 
   COUNT( DISTINCT NextWeekToFortnight) AS SevenToTwentyOneDays , 
   COUNT( DISTINCT LaterThan3Week) AS Later