2014-06-17 6 views
5

Ich habe Probleme mit dem Parameter in der Chiffre in Neo4J von Java. Ich führe die eingebettete Datenbank aus.Wie setze ich in Neo4J das Label als Parameter in einer Abfrage von Java?

Der Code sollte wie folgt sein (GraphDB.cypher geht direkt an die 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); 

aber es endet in dieser Ausnahme

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" 

Die Dokumentation (und Tutorial) erzählt die verwenden {}, um die Parameter abzudecken, ABER dies wird auch als die cpher-json-Notation für Eigenschaften verwendet. @see http://docs.neo4j.org/chunked/milestone/tutorials-cypher-parameters-java.html

Gibt es eine andere Möglichkeit, dieses Problem zu lösen, anstatt den Aufbau der Query-String wie folgt aus (oder mit anderen Template-Methoden)

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

Dies ist erforderlich, da die Zielmarke ändern kann, und ich will um den Code vollständig wiederzuverwenden.

Vielen Dank im Voraus.

[[EDITED A (seufz) nach dem Aufstehen NO AS ANTWORT]]

Da diese Form der Parameter ist derzeit (2014,6) nicht unterstützt wird, ich werde ein wenig replacer rechts laufen, bevor die Abfrage gesendet wird.

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); 
} 

kann es eine readble

+0

Nun ja, Sie statisch Abfragevorlagen definieren können, aber das ist irgendwie aus Neo4j Umfang diese Art von Funktionen zur Verfügung zu stellen, nicht du denkst? – Rolf

+0

@Raxa, Ihre Lösung mit "Ersatz" ist sehr interessant. Auf den ersten Blick scheint Ihre Verwendung von "# theLabel1 #" statisch zu sein und hat somit das eigentliche Problem, Cypher 'label' mit' parameter' zu bezeichnen, nicht dynamisch angegangen. Wenn es jedoch einfach als ein Platzhalter angesehen wird, der durch die Übereinstimmung in "Parameter" ersetzt werden soll, erreicht es eine dynamische Übergabe von "Label".Ich bin mir nicht sicher, ob es eine Standardlösung gibt, aber es ist eine ziemlich interessante Abschwächung. – Causality

Antwort

5

Ich fürchte, dies zur Zeit nicht unterstützt wird.

Und es könnte aus dem gleichen Grund als die in dieser Ausgabe erläutert: https://github.com/neo4j/neo4j/pull/1542.

Die Idee hinter parametrisierten Abfragen ist die Wiederverwendung von Ausführungsplänen (Cache). Wenn eine Knotenbeschriftung oder ein Beziehungstyp variiert, wäre der Ausführungsplan nicht derselbe, was die Nützlichkeit des Caching des Ausführungsplans ruiniert.

+1

Es ist eine Schande, dass die Neo4J-Dokumentation uns die Idee in 7.5 verkauft: "Das bedeutet, dass Entwickler nicht auf String-Erstellung zurückgreifen müssen, um eine Abfrage zu erstellen." Dies ist natürlich nicht die eigentliche Motivation. Es wäre vernünftiger, wenn der Cypher-Motor dieses Zeug ausbaute und in unserem Auftrag einen Ersatz wie den oben genannten machte. Entwickler können dann Abfragen vollständig parametrisieren, und wenn Neo4J im Laufe der Zeit verbessert wird, kann es diese Parametrisierung wo immer es möglich ist, ausnutzen. – Herc

+0

Fühlen Sie sich frei, ein Problem zu öffnen: https://github.com/neo4j/neo4j/issues :) – Rolf

4

nur einen Weg, dies zu erreichen, herausgefunden, wie ich in die gleiche Sache lief:

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

Die Etikett() Funktion, um alle Etiketten auf einem Knoten zurückgibt, und die IN-Operator-Tests für Existenz in der Liste . Anscheinend erlaubt Cypher dieses Konstrukt, weil es einen Parameter in einem Variablenfeld im Prädikat nutzt. Laut den Cypher-Dokumenten wird das Vergleichen von Beschriftungen oder Eigenschaften in WHERE-Klauseln und direkten Embeds von Eigenschaften und Beschriftungen in der Knotendefinition auf die gleiche Weise optimiert, sodass sie keinen signifikanten Leistungseinbruch darstellen sollten.

Nicht sicher eine einfache Möglichkeit, mehr möglichen Etiketten zu unterstützen ...

+1

Große und einfache Antwort. Genius! Um diese Antwort zu vervollständigen, müssen Sie, wenn Sie das Gleiche auch für Beziehungen tun möchten, die integrierte TYPE-Funktion verwenden, zB: 'MATCH (a) - [r] -> (b) WHERE {relName} = TYPE (r) RETURN-ID (r) AS relId, TYP (r) AS relName' – artemisian

+0

Sie können mehrere Beschriftungen mit der Funktion 'any()' unterstützen. Zum Beispiel 'MATCH (o) WHERE ANY (Element IN Etiketten (o) WHERE Element IN $ list_of_Labels)' – John

+0

aber es gibt keine Optimierung, es wird eine vollständige Datenbank-Scan mit Prüfungen pro Knoten sein, während eine Suche nach Label ist eine Bezeichnung -Scan-Speichervorgang. Sie können Ihre Abfrage dynamisch erstellen und dann z. Verwenden Sie apoc.cypher.run, um es auszuführen –

Verwandte Themen