I'm new programming with Neo4j, so I don't know enough from it's cypher language yet to solve without help an annoying bug from legacy and undocumented code.
My main problem is that I can't guess the purpose of the following query... :s .
That's the problematic query:
START
n=node({self})
MATCH
n-[:RECOMMENDATION]->(m)
WHERE
m.concept_type='unifying_theme' AND
not( ()-[:REQUIRED]->m ) RETURN m
The query itself is written with only one line, I've formatted it to make more readable. The error message is the following (reformatted to be easier to read):
PatternException: Some identifiers are used as both relationships and nodes:
UNNAMED1 Query:
START n=node({self})
MATCH n-[:RECOMMENDATION]->(m)
WHERE m.concept_type='unifying_theme' AND not( ()-[:REQUIRED]->m )
RETURN m
Params: {'self': 423}
Trace:
org.neo4j.cypher.internal.pipes.matching.PatternGraph.validatePattern(PatternGraph.scala:98)
org.neo4j.cypher.internal.pipes.matching.PatternGraph.<init>(PatternGraph.scala:36)
org.neo4j.cypher.internal.executionplan.builders.PatternGraphBuilder$cla...
The query is embedded inside a NeoModel's python library "StructuredNode" instance. I guess the {self} refers to the node represented by the StructuredNode instance, and that the error if this query is related with the m variable...
I suppose maybe I should use more variable names to avoid conflicts, but I'm suspicious. I think there are more errors on this query because I've seen more ugly and buggy code of this disastrous programmer.
I don't know what was trying to do with the not( ()-[:REQUIRED]->m ) block, Is that a legal Cypher "subsentence" if m represents a node?
P.D.: I'm using Neo4j 1.9.7 .
Thank you in advance.
Related
I am new to Neo4j and I have a relatively complex (but small) database which I have simplified to the following:
The first door has no key, all other doors have keys, the window doesn't require a key. The idea is that if a person has key:'A', I want to see all possible paths they could take.
Here is the code to generate the db
CREATE (r1:room {name:'room1'})-[:DOOR]->(r2:room {name:'room2'})-[:DOOR {key:'A'}]->(r3:room {name:'room3'})
CREATE (r2)-[:DOOR {key:'B'}]->(r4:room {name:'room4'})-[:DOOR {key:'A'}]->(r5:room {name:'room5'})
CREATE (r4)-[:DOOR {key:'C'}]->(r6:room {name:'room6'})
CREATE (r2)-[:WINDOW]->(r4)
Here is the query I have tried, expecting it to return everything except for room6, instead I have an error which means I really don't know how to construct the query.
with {key:'A'} as params
match (n:room {name:'room1'})-[r:DOOR*:WINDOW*]->(m)
where r.key=params.key or not exists(r.key)
return n,m
To be clear, I don't need my query debugged so much as help understanding how to write it correctly.
Thanks!
This should work for you:
WITH {key:'A'} AS params
MATCH p=(n:room {name:'room1'})-[:DOOR|WINDOW*]->(m)
WHERE ALL(r IN RELATIONSHIPS(p) WHERE NOT EXISTS(r.key) OR r.key=params.key)
RETURN n, m
With your sample data, the result is:
╒════════════════╤════════════════╕
│"n" │"m" │
╞════════════════╪════════════════╡
│{"name":"room1"}│{"name":"room2"}│
├────────────────┼────────────────┤
│{"name":"room1"}│{"name":"room3"}│
├────────────────┼────────────────┤
│{"name":"room1"}│{"name":"room4"}│
├────────────────┼────────────────┤
│{"name":"room1"}│{"name":"room5"}│
└────────────────┴────────────────┘
I try to write a cypher query that extracts a set of labels, that share one specific label. After is selected the labels i try to rename them. Which means add a prefix to each of the labels andrename the labels in the graph with help of apoc.refactor.rename.label. Therefore i wrote the following query.
match (c:TheLabel)
with collect(distinct filter( l in labels(c) where not l in ["UNIQUE IMPORT LABEL","TheLabel"])[0]) as curr_label
unwind curr_label as cl
with cl as cl, "AR_"+cl as nl
call apoc.refactor.rename.label(cl, nl)
return null
But this query fails with the following error message:
Neo.ClientError.Statement.SyntaxError: Procedure call inside a query does not support naming results implicitly (name explicitly using `YIELD` instead) (line 5, column 1 (offset: 214))
"call apoc.refactor.rename.label(cl, nl) return null"
I can't understand where i could use yield to get this query run.
I tried the first part separately i.e. return nl & cl after the with. This works fine. I also tried to use the rename function with one specific cl and cl that i got while trying the first part of the query. That is also working fine. Only the combination seems not to work.
Edit:
I figured out that every unwind seems to break the query never the less if I use the variable that is defined by unwind or not.
Minimal example that produces the same error:
unwind [1,2,3,4] as cl
call apoc.refactor.rename.label("Test", "Test")
return cl
Thanks in advance for any help or solutions.
If a procedure is defined to return any results, then the Cypher language requires that the CALL clause must be paired with a YIELD clause -- even if you don't care about any of the results. The only exception is when the entire Cypher statement consists of just a CALL clause (this is referred to in the docs as a "standalone procedure call").
To quote from the docs:
If the called procedure declares at least one result field, YIELD may
generally not be omitted. However YIELD may always be omitted in a
standalone procedure call. In this case, all result fields are yielded
as newly-bound variables from the procedure call to the user.
Ok after trying around i figured it out. You need to yield at least one field of the return of the call for example:
unwind [1,2,3,4] as cl
call apoc.refactor.rename.label("Test", "Test")
yield total
return null // everything is possible for return.
I don't know why it's working but it works. Maybe it has to do something with the stream that the procedure produces, but I'm really not sure. If somebody knows why it solves my problem please comment.
I am working on a Ruby on Rails project that will read and parse somewhat big text file (around 100k lines) and build Neo4j nodes (I am using Neography) with that data.
This is the Neo4j related fraction of the code I wrote:
d= Neography::Rest.new.execute_query("MATCH (n:`Label`) WHERE (n.`name`='#{id}') RETURN n")
d= Neography::Node.load(d, #neo)
p= Neography::Rest.new.create_node("name" => "#{id}")
Neography::Rest.new.add_label(p, "LabelSample")
d=Neography::Rest.new.get_node(d)
Neography::Rest.new.create_relationship("belongs_to", p, d)
so, what I want to do is: a search in the already populated db for the node with the same "name" field as the parsed data, create a new node for this data and finally create a relationship between the two of them.
Obiously this code simply takes way too much time to be executed.
So I tried with Neography's batch, but I ran into some issues.
p = Neography::Rest.new.batch [:create_node, {"name" => "#{id}"}]
gave me a "undefined method `split' for nil:NilClass" in
id["self"].split('/').last
d=Neography::Rest.new.batch [:get_node, d]
gives me a Neography::UnknownBatchOptionException for get_node
I am not even sure this will save me enough time either.
I also tried different ways to do this, using Batch Import for example, but I couldn't find a way to get the already created node I need from the db.
As you can see I'm kinda new to this so any help will be appreciated.
Thanks in advance.
You might be able to do this with pure cypher (or neography generated cypher). Something like this perhaps:
MATCH (n:Label) WHERE n.name={id}
WITH n
CREATE (p:LabelSample {name: n.name})-[:belongs_to]->n
Not that I'm using CREATE, but if you don't want to create duplicate LabelSample nodes you could do:
MATCH (n:Label) WHERE n.name={id}
WITH n
MERGE (p:LabelSample {name: n.name})
CREATE p-[:belongs_to]->n
Note that I'm using params, which are generally recommended for performance (though this is just one query, so it's not as big of a deal)
I am trying example provided in Graph Databases book (PDF page 51-52)with Neo4j 2.0.1 (latest). It appears that I cannot just copy paste the code sample from the book (I guess the syntax is no longer valid).
START bob=node:user(username='Bob'),
charlie=node:user(username='Charlie')
MATCH (bob)-[e:EMAILED]->(charlie)
RETURN e
Got #=> Index `user` does not exist.
So, I tried without 'user'
START bob=node(username='Bob'),
charlie=node(username='Charlie')
MATCH (bob)-[e:EMAILED]->(charlie)
RETURN e
Got #=> Invalid input 'u': expected whitespace, an unsigned integer, a parameter or '*'
Tried this but didn't work
START bob=node({username:'Bob'}),
(charlie=node({username:'Charlie'})
MATCH (bob)-[e:EMAILED]->(charlie)
RETURN e
Got #=> Invalid input ':': expected an identifier character, whitespace or '}'
I want to use START then MATCH to achieve this. Would appreciate little bit of direction to get started.
From version 2.0 syntax has changed.
http://docs.neo4j.org/chunked/stable/query-match.html
Your first query should look like this.
MATCH (bob {username:'Bob'})-[e:EMAILED]->(charlie {username:'Charlie'})
RETURN e
The query does not work out of the box because you'll need to create the user index first. This can't be done with Cypher though, see the documentation for more info. Your syntax is still valid, but Lucene indexes are considered legacy. Schema indexes replace them, but they are not fully mature yet (e.g. no wildcard searches, IN support, ...).
You'll want to use labels as well, in your case a User label. The query can be refactored to:
MATCH (b:User { username:'Bob' })-[e:EMAILED]->(c:User { username:'Charlie' })
RETURN e
For good performance, add a schema index on the username property as well:
CREATE INDEX ON :User(username)
Start is optional, as noted above. Given that it's listed under the "deprecated" section in the Cypher 2.0 refcard, I would try to avoid using it going forward just for safety purposes.
However, the refcard does state that you can prepend your Cypher query with "CYPHER 1.9" (without the quotes) in order to make explicit use of the older syntax.
In the following scenario, node "x" does not exist.
start x=node:node_auto_index(key="x"), y=node(*)
return count(x), count(y)
It seems that if any of the starting points can't be found, nothing is returned.
Any suggestions how to work around this issue?
This is like saying the below (in SQL)--what do you expect will happen if table X is empty?
select count(x), count(y)
from x, y
I'm not sure exactly what you're trying to query here, but you might need to get your counts one at a time, if there's a chance that x will come back with no results:
start x=node:node_auto_index(key="x")
with count(x) as cntx
start y=node(*)
return cntx, count(y) as cnty
Thanks to Wes, I figured out how to do a "conditional add" with the old Cypher syntax (pre 2.0):
START x=node:node_auto_index(key="x")
with count(x) as exists
start y=node:node_auto_index(key="y")
where exists = 0
create (n {key:"y"})<-[:rel]-y
return n, y
The crux here is that you can't fire another "start" after a "where" clause. You need to query for the second node before checking for conditions (which is kind of bad for performance). This is remedied in 2.0 with if-then-else statements anyway...