具有多种条件的Neo4j Cypher查询

时间:2016-08-07 18:37:19

标签: neo4j cypher spring-data-neo4j spring-data-neo4j-4

在我的SDN 4项目中,我有以下权利:

@NodeEntity
public class Characteristic extends Authorable {

    private final static String CONTAINS = "CONTAINS";
    private final static String DEFINED_BY = "DEFINED_BY";

    private String name;

    private String description;

    @Relationship(type = DEFINED_BY, direction = Relationship.OUTGOING)
    private Decision owner;

}

@NodeEntity
public class Decision extends Commentable {

    private final static String DEFINED_BY = "DEFINED_BY";

    @Relationship(type = DEFINED_BY, direction = Relationship.INCOMING)
    private Set<Characteristic> characteristics = new HashSet<>();

}

@RelationshipEntity(type = "DECISION_CHARACTERISTIC")
public class DecisionCharacteristic {

    @GraphId
    private Long id;

    @StartNode
    private Decision decision;

    @EndNode
    private Characteristic characteristic;

    private Object value;

}

我需要选择符合特定特征的Decision个节点。

我创建了以下Cypher查询:

MATCH (parentD)-[:CONTAINS]->(childD:Decision)-[ru:CREATED_BY]->(u:User) WHERE id(parentD) = {decisionId} MATCH (childD)-[rdc:DECISION_CHARACTERISTIC]->(characteristic:Characteristic) WHERE  ( ( (  id(characteristic) = 138 AND  (rdc.value > 15000.32)) AND (  id(characteristic) = 138 AND  (rdc.value < 50000.32)) ) AND (  id(characteristic) = 139 AND  (rdc.value = 'Commercial')) )  WITH childD, ru, u RETURN childD

但是这个查询错误。我需要选择一个决策节点,其中id=138的特征具有value between 15000.32 and 50000.32,而id=139的特征具有精确的value = 'Commercial'

我的查询错误,如何转换以便按预期工作?

已更新

我有以下节点:

        DecisionCharacteristic neo4jPriceDecisionCharacteristic = new DecisionCharacteristic(neo4jDecision, priceCharacteristic, new Double(10000.32d));
        decisionCharacteristicRepository.save(neo4jPriceDecisionCharacteristic);

        DecisionCharacteristic oraclePriceDecisionCharacteristic = new DecisionCharacteristic(oracleDecision, priceCharacteristic, new Double(35000.2d));
        decisionCharacteristicRepository.save(oraclePriceDecisionCharacteristic);

        assertNotNull(neo4jPriceDecisionCharacteristic);
        assertNotNull(neo4jPriceDecisionCharacteristic.getId());

        DecisionCharacteristic neo4jLicenseDecisionCharacteristic = new DecisionCharacteristic(neo4jDecision, licenseCharacteristic, "Commercial");
        decisionCharacteristicRepository.save(neo4jLicenseDecisionCharacteristic);

        DecisionCharacteristic orientLicenseDecisionCharacteristic = new DecisionCharacteristic(orientDecision, licenseCharacteristic, "Free");
        decisionCharacteristicRepository.save(orientLicenseDecisionCharacteristic);

        DecisionCharacteristic oracleLicenseDecisionCharacteristic = new DecisionCharacteristic(oracleDecision, licenseCharacteristic, "Commercial");
        decisionCharacteristicRepository.save(oracleLicenseDecisionCharacteristic);

的ID:

priceCharacteristic ID: 138
licenseCharacteristic ID: 139

我正在尝试使用以下查询获取Decision个节点:

   MATCH (parentD)-[:CONTAINS]->(childD:Decision)-[ru:CREATED_BY]->(u:User) WHERE id(parentD) = {decisionId} MATCH (childD)-[rdc:DECISION_CHARACTERISTIC]->(characteristic:Characteristic) WHERE  ( id(characteristic) = 138 AND  ( id(characteristic) = 138 AND  (  (rdc.value > 15000.32)) AND (  (rdc.value < 50000.32)) ) OR (  id(characteristic) = 139 AND  (rdc.value = 'Commercial')) )  RETURN childD

我希望只有oracleDecision节点匹配此条件,但它返回两个节点:

Neo4j
Oracle

我哪里错了?

1 个答案:

答案 0 :(得分:1)

查询中的主要缺陷是使用AND来创建一个不可能的where子句。你实际上要求它返回id为两个不同数字的值,并且rdc.value同时是多个值...不可能。您需要在正确的位置使用OR,以便您可以匹配一个ID或另一个ID。此外,我们可以改进rdc.value限制。

MATCH (parentD)-[:CONTAINS]->(childD:Decision)-[ru:CREATED_BY]->(u:User) 
WHERE id(parentD) = {decisionId} 
MATCH (childD)-[rdc:DECISION_CHARACTERISTIC]->(characteristic:Characteristic) 
WHERE  (id(characteristic) = 138 AND (15000.32 < rdc.value < 50000.32)) 
OR (id(characteristic) = 139 AND (rdc.value = 'Commercial'))  
WITH childD, ru, u 
RETURN childD

最后,您根本不需要WITH子句,因为您只返回childD。不确定是否因为你忘了在返回中返回其他变量,但是如果你真的只返回childD,那么你可以消除你的WITH子句,以及你的第一个中的ru和u变量线路匹配。如果:决策总是由用户创建,那么您可以通过删除&#34; - [ru:CREATED_BY] - &gt;(u:用户)&#34;来修剪您的第一场比赛。这会使您的查询看起来像:

MATCH (parentD)-[:CONTAINS]->(childD:Decision) 
WHERE id(parentD) = {decisionId} 
MATCH (childD)-[rdc:DECISION_CHARACTERISTIC]->(characteristic:Characteristic) 
WHERE  (id(characteristic) = 138 AND (15000.32 < rdc.value < 50000.32)) 
OR (id(characteristic) = 139 AND (rdc.value = 'Commercial'))  
RETURN childD

修改

啊,好吧,从您的查询中可以清楚地知道您想要匹配两种不同类型的特征并对两者都设置限制。在这种情况下,针对特征的单一匹配是不够的。您需要单独指定它们。

MATCH (parentD)-[:CONTAINS]->(childD:Decision)-[:CREATED_BY]->(:User)
WHERE id(parentD) = {decisionId} 
MATCH (childD)-[pdc:DECISION_CHARACTERISTIC]->(priceChar:Characteristic) 
WHERE  (id(priceChar) = 138 AND (15000.32 < pdc.value < 50000.32))
MATCH (childD)-[ldc:DECISION_CHARACTERISTIC]->(licenseChar:Characteristic) 
WHERE (id(licenseChar) = 139 AND (ldc.value = 'Commercial'))  
RETURN childD

我必须问一下,你是否真的可以用这种方式建模你的图形?您有特征节点,但是您要在关系上存储特征数据而不是节点本身。当你看起来很清楚你确实有单独的类型时,你也会使用一个特征节点,比如PriceCharacteristic和LicenseCharacteristic等。您是否有要求或有充分理由这样做,或者您是否可以自由更改图表数据的表示方式?