2014-06-17 2 views
5

자바에서 Neo4J의 cypher에있는 매개 변수에 문제가 있습니다. 나는 임베디드 데이터베이스를 실행한다.Neo4J에서 Java의 사이퍼 쿼리에서 매개 변수로 레이블을 설정하는 방법은 무엇입니까?

코드는 다음과 같이해야한다 (GraphDB.cypher가 ExecutionEngine로 직접 이동)

HashMap<String, Object> parameter = new HashMap<>(); 
parameter.put("theLabel1", "Group"); 
parameter.put("theRelation", "isMemberOf"); 
parameter.put("theLabel2", "Person"); 
GraphDB.cypher("MATCH (n1:{theLabel1})-[r:{theRelation}]->(n2:{theLabel2}) RETURN n1, r, n2", parameter); 

그러나이 예외

Exception in thread "main" Invalid input '{': expected whitespace or a label name (line 1, column 11) 
"MATCH (n1:{theLabel1})-[r:{theRelation}]->(n2:{theLabel2}) RETURN n1, r, n2" 

문서 (및 튜토리얼)로 끝나는은을 사용하도록 지시 {}를 사용하여 매개 변수를 처리 할 수 ​​있지만 속성의 cypher json 표기법으로도 사용됩니다. @see http://docs.neo4j.org/chunked/milestone/tutorials-cypher-parameters-java.html

GraphDB.cypher("MATCH (n:" + labelName + ")-[r:" + relationName + "]->... 

대상 레이블을 변경하고 내가 원하는 때문이 필요한이 문제를 해결하기보다는 (다른 템플릿 방법을 나와) 같은 쿼리 문자열을 구축하는 또 다른 방법이 있나요 코드를 완전하게 재사용 할 수 있습니다.

미리 감사드립니다.

는 [난 후에 편집 된 (한숨) NO ANSWER는 바와 같이] 파라미터의 형식은 (2014.6)에서 지원하지 않기 때문에

, I 바로 조회를 전송하기 전에 약간의 대체물을 실행한다.

HashMap<String, Object> parameter = new HashMap<>(); 
parameter.put("theLabel1", "Group"); 
parameter.put("theRelation", "isMemberOf"); 
parameter.put("theLabel2", "Person"); 

parameter.put("aName", "Donald Duck"); 

GraphDB.cypher("MATCH (n1:#theLabel1#)-[r:#theRelation#]->(n2:#theLabel2#) WHERE n2.Name = {aName} RETURN n1, r, n2", parameter); 

... with ... 

public static ExecutionResult cypher(String query, Map<String, Object> params) { 
    for (String key : params.keySet()) { 
     query = query.replaceAll("#" + key + "#", String.valueOf(params.get(key))); 
    } 
    return params == null ? cypherEngine.execute(query) : cypherEngine.execute(query, params); 
} 

내가이 순간에 지원되지 않습니다 두려워 더 readble

+0

음,하지만이 기능이 종류를 제공하기 위해 Neo4j의 범위를 벗어나 좀있다,하지 너 생각하니? – Rolf

+0

@ Raxa, "replacer"를 가진 당신의 솔루션은 매우 흥미 롭습니다. 언뜻보기에 "# theLabel1 #"을 사용하는 것은 정적 인 것처럼 보이므로 Cypher의 'label'을 'parameter'로 '동적으로'지정하는 진정한 문제는 해결하지 못했습니다. 그러나 단순히 '매개 변수'에서 일치로 대체 될 자리 표시 자로 간주 될 때 동적으로 '레이블'을 전달합니다.오는 표준 솔루션이 있는지 확실하지 않지만 매우 흥미로운 완화 방법입니다. – Causality

답변

5

가있을 수 있습니다.

그리고이 문제에서 설명한 것과 동일한 이유로 https://github.com/neo4j/neo4j/pull/1542 일 수 있습니다.

매개 변수가있는 쿼리의 기본 개념은 실행 계획을 다시 사용 (캐시)하는 것입니다. 노드 레이블이나 관계 유형이 다양하면 실행 계획이 전혀 같지 않으므로 실행 계획 캐싱의 유용성이 손상됩니다.

+1

Neo4J 문서는 7.5에서 "개발자가 쿼리 작성을 위해 문자열 작성에 의존 할 필요가 없다는 것을 의미합니다." 분명히 이것은 진정한 동기가 아닙니다. Cypher 엔진이이 작업을 수행하고 우리를 대신하여 위와 같은 대체 작업을 수행하는 것이 더 합리적입니다. 개발자는 쿼리를 완전히 매개 변수화 할 수 있으며 Neo4J가 시간이 지남에 따라 향상되므로 가능한 경우이 매개 변수화를 이용할 수 있습니다. – Herc

+0

언제든지 문제를 열어보십시오 : https://github.com/neo4j/neo4j/issues :) – Rolf

4

그냥 내가 같은 일에 실행되면서이 작업을 수행하는 방법을 알아 낸 :

MATCH (n) WHERE {label} IN labels(n) 

레이블을() 함수가리스트에 존재 노드의 모든 레이블 및 IN 연산자 테스트를 반환 . 분명히 Cypher는 프리디 케이트의 변수 필드에서 매개 변수를 사용하기 때문에이 구문을 허용합니다. Cypher 문서에 따르면 WHERE 절의 레이블이나 속성을 비교하고 노드 정의에 직접 속성/레이블 포함을 최적화하는 방식이 동일하므로 성능이 크게 떨어지지 않아야합니다.

그래, 당신이 정적 쿼리 템플릿을 정의 할 수 있습니다

가능한 여러 레이블을 지원하는 쉬운 방법 확실하지 ...

+1

위대하고 간단한 대답입니다. 천재! 이 답변을 보완하기 위해 TYPE 기본 제공 함수를 사용해야하는 경우에도 다음을 수행해야합니다. 예 : 'MATCH (a) - [r] -> (b) WHERE {relName} = TYPE (r) RETURN ID (r) AS relId, TYPE (r) AS relName' – artemisian

+0

'any()'함수를 사용하여 여러 라벨을 지원할 수 있습니다. 예를 들어'MATCH (o) WHERE ANY (item in labels (o) WHERE item IN $ list_of_labels)' – John

+0

과 같이 최적화가 없다면, 노드 별 수표가있는 전체 데이터베이스 스캔이 될 것이고, label 별 조회는 레이블입니다 -scan-store 조작. 사이퍼 쿼리를 동적으로 구성한 다음 .e.g를 구성 할 수 있습니다. apoc.cypher.run을 사용하여 실행하십시오. –

관련 문제