Getting alphanumeric reference of nodes in py2neo, when looking for paths - neo4j

I have a graph that consists of DATASET and GRAPH nodes. With the following relationships:
DATASET->READS->GRAPH
GRAPH->WRITES->DATASET
When I run the following : MATCH (p1:DATASET_NAME { name:'test1.dat' }),(p3:DATASET_NAME { name:'test32.txt' }), p = ((p1)-[:READS|:WRITES*1..8]->(p3))
RETURN p
In Neo4J Desktop I get a result that is correct, where node names are present. But when I run it in py2neo:
graph.run("MATCH (p1:DATASET_NAME {
name:'test1.dat' }),(p3:DATASET_NAME { name:'test32.txt' }), p = ((p1)-[:READS|:WRITES*1..8]->(p3)) RETURN p").dump()
I get a result in the following format:
(f3ff862)-[:READS]->(c539bdc)-[:WRITES]->(b217f5a)-[:READS]->(ebf9c4f)-[:WRITES]->(f9ddd22)-[:READS]->(fcca016)-[:WRITES]->(a9c241a)
(f3ff862)-[:READS]->(c539bdc)-[:WRITES]->(b217f5a)-[:READS]->(ebf9c4f)-[:WRITES]->(f9ddd22)-[:READS]->(fcca016)-[:WRITES]->(e152f69)-[:READS]->(fcca016)-[:WRITES]->(a9c241a)
(f3ff862)-[:READS]->(c539bdc)-[:WRITES]->(b217f5a)-[:READS]->(ebf9c4f)-[:WRITES]->(cbc5d42)-[:READS]->(fcca016)-[:WRITES]->(a9c241a)
I am assuming that these are some sort of references. Is there a way where I can get the string value for name from these references?

You are returning the matched path so what you see in py2neo is the representation of the path object. In the neo4j console it does a little extra looking up for you and presents the path as a set of nodes and relationships and it labels them according to what you have configured in the console.
If you want to see the names in your py2neo output you could use the reduce function on the returned path p to produce a string with the node names and relationship types. Something like this should get you started.
MATCH (p1:DATASET_NAME { name:'test1.dat' }),(p3:DATASET_NAME { name:'test32.txt' }), p = ((p1)-[:READS|:WRITES*1..8]->(p3))
RETURN head(nodes(p)).name + ' - ' + reduce(path_str = "", r in relationships(p) | path_str + type(r) + ' - ' + endnode(r).name)
In py2neo [Note the escape characters added in order to avoid cypher error. # ...reduce(path_str = \"\"... ]:
graph.run("MATCH (p1:DATASET_NAME { name:'/projects/bkrpty_vfcn/bkrpty_vfcn_vendr/data/serial/temp/yyyymmdd_yyyymmddhhmiss_bk_mrk_stat_init.dat' }),(p3:DATASET_NAME { name:'/projects/bkrpty_vfcn/bkrpty_vfcn_vendr/tables/onevgb1/ai_bkrpty_case' }), p = ((p1)-[:READS|:WRITES*1..8]->(p3)) RETURN head(nodes(p)).name + ' - ' + reduce(path_str = \"\", r in relationships(p) | path_str + type(r) + ' - ' + endnode(r).name)").dump()

Related

Understanding Operators of Neo4j

String query = "START n1=node:TEST_INDEX(nodeName='" + elementID
+ "') match n1-[:hasSubClass]->n2-[:hasPropertyGroup]->n3-[:containsProperty]->n4 with n2 match n2-[:hasInstance]->n5 "
+ "where n2.elementType='class' and not(n4.status! = 'Deleted') and n4.nodeName! =~ '(?i)" + propertyName + "' and where count(n5)=0 return n4,count(n5)";
I am trying to convert this particular query to MATCH query facing issue in understanding these conditions
not(n4.status! = 'Deleted') and n4.nodeName! =~ '(?i)" + propertyName
+ "'
I tried to change the query :-
MATCH(n1:TESTDATA{nodeName:'ProductConcept'})
match (n1)-[:hasSubClass]->(n2)-[:hasPropertyGroup]->(n3)-[:containsProperty]->(n4) with n2,n4
match (n2)-[:hasInstance]->(n5)
where n2.elementType='class'
and NOT EXISTS(n4.status)
and n4.nodeName <>'(?i)view'
//and where count(n5)=0
return n4,count(n5)
Assuming you pass elementId and propertyName as parameters, this Cypher seems to be equivalent to the intent of your original query:
START n1=node:TEST_INDEX(nodeName=$elementId)
MATCH (n1)-[:hasSubClass]->(n2)-[:hasPropertyGroup]->()-[:containsProperty]->(n4)
WHERE
n2.elementType = 'class' AND
n4.status = 'Deleted' AND
(NOT n4.nodeName =~ ('(?i)' + $propertyName)) AND
SIZE((n2)-[:hasInstance]->()) = 0
RETURN n4
This query does not bother to return the equivalent of COUNT(n5), since the query requires that the value must always be 0.

how to perform neo4j cypher code formatting

Is there a way/website/sublime plugin etc, to format cypher code (make it align and tidy)?
Same as this site is doing for javascript for example:
http://jsbeautifier.org/
While not perfect, here is what I have been doing. (hopefully others will jump in and improve it)
var Cypher = document.body.innerText
Cypher = Cypher.replace(/(?:\s*(OPTIONAL MATCH|MATCH|WHERE|WITH|RETURN|DETACH DELETE|DELETE|UNWIND|CASE)\s*)/gi, function(match) {
return '\n' + match.toUpperCase() + ' '
});
Cypher = Cypher.replace(/(?:\s*(AND|NOT|DISTINCT)\s*)/gi, function(match) {
return ' ' + match.toUpperCase().trim() + ' '
});
Cypher = Cypher.replace(/(?:\s*(\w+)\(\s*)/gi, function(match) {
return ' ' + match.toUpperCase().trim()
});
document.body.innerText = Cypher
match (n), (n)--(m) where n.car=1 and not n.id="rawr" with n.name return collect(n) as cars
(JSFiddle version)

Neo4j: Conditional return/IF clause/String manipulation

This is in continuation of Neo4j: Listing node labels
I am constructing a dynamic MATCH statement to return the hierarchy structure & use the output as a Neo4j JDBC input to query the data from a java method:
MATCH p=(:Service)<-[*]-(:Anomaly)
WITH head(nodes(p)) AS Service, p, count(p) AS cnt
RETURN DISTINCT Service.company_id, Service.company_site_id,
"MATCH srvhier=(" +
reduce(labels = "", n IN nodes(p) | labels + labels(n)[0] +
"<-[:BELONGS_TO]-") + ") WHERE Service.company_id = {1} AND
Service.company_site_id = {2} AND Anomaly.name={3} RETURN " +
reduce(labels = "", n IN nodes(p) | labels + labels(n)[0] + ".name,");
The output is as follows:
MATCH srvhier=(Service<-[:BELONGS_TO]-Category<-[:BELONGS_TO]-SubService<-
[:BELONGS_TO]-Assets<-[:BELONGS_TO]-Anomaly<-[:BELONGS_TO]-) WHERE
Service.company_id = {1} and Service.company_site_id = {21} and
Anomaly.name={3} RETURN Service.name, Category.name, SubService.name,
Assets.name, Anomaly.name,
The problem I am seeing:
The "BELONGS_TO" gets appended to my last node
Line 2: Assets<-[:BELONGS_TO]-Anomaly**<-[:BELONGS_TO]-**
Are there string functions (I have looked at Substring..) that can be used to remove it? Or can I use a CASE statement with condition n=cnt to append "BELONGS_TO"?
The same problem persists with my last line:
Line 5: Assets.name,Anomaly.name**,** - the additional "," that I need to eliminate.
Thanks.
I think you need to introduce a case statement into the reduce clause something like this snippet below. If the node isn't the last element of the collection then append the "<-[:BELONGS_TO]-" relationship. If it is the last element then don't append it.
...
reduce(labels = "", n IN nodes(p) |
CASE
WHEN n <> nodes(p)[length(nodes(p))-1] THEN
labels + labels(n)[0] + "<-[:BELONGS_TO]-"
ELSE
labels + labels(n)[0]
END
...
Cypher has a substring function that works basically like you'd expect. An example: here's how you'd return everything but the last three characters of a string:
return substring("hello", 0, length("hello")-3);
(That returns "he")
So you could use substring to trim the last separator off of your query that you don't want.
But I don't understand why you're building your query in such a complex way; you're using cypher to write cypher (which is OK) but (and I don't understand your data model 100%) it seems to me like there's probably an easier way to write this query.

How do I extract results individually from an ExecutionResult?

I have the following java code snippet that demonstrates the problem. The error I receive is also included below.
It correctly pulls the correct set, but I am having trouble printing.
I'm using the org.neo4j.graphdb.Node node. Is this the wrong class?
If not, how do I obtain the results movieid, avgrating and movie_title from the ExecutionEngine?
Java Code
GraphDatabaseService db = new GraphDatabaseFactory().newEmbeddedDatabase(DB_PATH);
ExecutionEngine engine = new ExecutionEngine(db);
String cypherQuery = "MATCH (n)-[r:RATES]->(m) \n"
+ "RETURN m.movieid as movieid, avg(toFloat(r.rating)) as avgrating, m.title as movie_title \n"
+ "ORDER BY avgrating DESC \n"
+ "LIMIT 20;";
ExecutionResult result = engine.execute(cypher);
for (Map<String, Object> row : result) {
Node x = (Node) row.get("movie_title");
for (String prop : x.getPropertyKeys()) {
System.out.println(prop + ": " + x.getProperty(prop));
}
}
Error
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to org.neo4j.graphdb.Node
at beans.RecommendationBean.queryMoviesWithCypher(RecommendationBean.java:194)
at beans.RecommendationBean.main(RecommendationBean.java:56)
Node x = (Node) row.get("movie_title");
...looks to be the culprit.
In your Cypher statement, you return m.title as movie_title, i.e. you're returning a node property (in this case, a string), and, in the offending line, you're trying to cast that string result as a Node.
If you want Cypher to return a series of nodes you can iterate through, try returning m (the whole node) instead of just individual properties and aggregates, e.g.
"...RETURN m AS movie;"
...
Node x = (Node) row.get("movie");
Etc.

How do I get list of nodes from calculated shortest path?

My Cypher looks like this:
START source=node(16822), target=node(12449)
MATCH p = allShortestPaths(source-[*]-target)
return p
And I want to write equivalent C# code for this. This is what I've come up till now
var query = client.Cypher
.Start(new { source = sourceNode.Reference, target = targetNode.Reference })
.Match("p = allShortestPaths(source-[*]-target)")
.Return<Node<Data>>("x");
Where Data is the class which has a string property(string ID).
What should i put in place of x to get my result as a list of concatenated IDs which comprises the path.
Cypher 2.0
START source=node(16822), target=node(12449)
MATCH p = allShortestPaths(source-[*]-target)
return nodes(p)
Good old way of executing query was the last resort which i used
CypherQuery query1 = new CypherQuery(#"START m=node(" + sourceNode.Reference.Id.ToString() + "), n=node(" + targetNode.Reference.Id.ToString() + #")
match p = allshortestpaths(m-[*]-n)
return distinct Extract(x in NODES(p): x.NodeId) as paths", paramCollection, CypherResultMode.Set);
var paths = ((IRawGraphClient)client).ExecuteGetCypherResults<List<string>>(query1);

Resources