具有多个条件的 Neo4j Cypher 查询
Neo4j Cypher query with multiple conditions
在我的 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;
}
我需要select一个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
但是这个查询是错误的。我需要 select 一个决策节点,对于具有 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
个节点符合此条件,但 returns 两个节点:
Neo4j
Oracle
我哪里错了?
您查询中的主要缺陷是使用 AND 来创建不可能的 where 子句。您实际上是在要求它 return 值,其中 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 子句,因为您只是 returning childD。不确定那是不是因为你忘记了 return return 中的其他变量,但如果你真的只是 returning childD,那么你可以删除你的 WITH 子句,以及第一行中的 ru 和 u 变量匹配。如果 :Decisions 总是由用户创建,那么您可以通过删除“-[ru:CREATED_BY]->(u:User)”来trim您的第一个匹配项。这将使您的查询看起来像:
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
我想问一下,您真的可以用这种方式对图表建模吗?您有特征节点,但您存储的是关于关系的特征数据,而不是节点本身。当看起来很明显您实际上有不同的类型时,您也使用了单个 Characteristic 节点,例如 PriceCharacteristic 和 LicenseCharacteristic 等。您是否有这样做的要求或充分理由,或者您是否可以自由更改图形数据的表示方式?
在我的 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;
}
我需要select一个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
但是这个查询是错误的。我需要 select 一个决策节点,对于具有 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
个节点符合此条件,但 returns 两个节点:
Neo4j
Oracle
我哪里错了?
您查询中的主要缺陷是使用 AND 来创建不可能的 where 子句。您实际上是在要求它 return 值,其中 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 子句,因为您只是 returning childD。不确定那是不是因为你忘记了 return return 中的其他变量,但如果你真的只是 returning childD,那么你可以删除你的 WITH 子句,以及第一行中的 ru 和 u 变量匹配。如果 :Decisions 总是由用户创建,那么您可以通过删除“-[ru:CREATED_BY]->(u:User)”来trim您的第一个匹配项。这将使您的查询看起来像:
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
我想问一下,您真的可以用这种方式对图表建模吗?您有特征节点,但您存储的是关于关系的特征数据,而不是节点本身。当看起来很明显您实际上有不同的类型时,您也使用了单个 Characteristic 节点,例如 PriceCharacteristic 和 LicenseCharacteristic 等。您是否有这样做的要求或充分理由,或者您是否可以自由更改图形数据的表示方式?