Helo,
i want to match a graph where a node can be typeX or typeY
my first thought was:
match (:typeX|typeY)-[]-(z) return z
But this doesn´t work :(
Is there any way without typing the query twice?
Like this:
match (:typeX)-[]-(z), (:typeY)-[]-(z) return z
Can someone help me?
thank you in advance :)
One way is
MATCH (n) WHERE labels(n) IN ['typeX','typeY']
WITH n
MATCH (n)-[]-(z)
RETURN z
However, if "either typeX or typeY" are queried frequently and share some common purpose in your domain, you could add another common label to them like "commonXY" and query using that label instead.
Unfortunately there's not a good efficient way to do this without sacrificing performance. All other current answers are forced to scan all nodes and then filter on their labels, which isn't performant with large numbers of nodes (PROFILE the queries). All the efficient means I know of are more verbose.
You can perform a UNION of the two queries to return nodes one hop from all :typeX and :typeY nodes.
match (:typeX)--(z)
return z
union
match (:typeY)--(z)
return z
This query will work even if n has multiple labels:
MATCH (n)
WHERE ANY(lab IN labels(n) WHERE lab IN ['typeX', 'typeY'])
MATCH (n)--(z)
RETURN z
there is a n predicate n:Label
MATCH (n)--(z)
WHERE n:typeX OR n:typeY
RETURN z
Related
Given a list of (let say 4) MicroRNA and a list of relationships (pictar, rna22,…),
returns the list of target TargetGenes common to all MicroRNA in all relationships.
I am trying to do by this way but it does not work...
MATCH (n:microRNA)-[r]->(n:Target)
WHERE r.name='RNA22v2'
OR r.name='PicTar'
RETURN n
But it does not give me any results.
This may or may not be the actual problem, but instead of
MATCH (n:microRNA)-[r]->(n:Target)
WHERE r.name='RNA22v2'
OR r.name='PicTar'
RETURN n
shouldn't you have
MATCH (m:microRNA)-[r]->(t:Target)
WHERE r.name='RNA22v2'
OR r.name='PicTar'
RETURN m,t
Using the same variable n for two different nodes may confuse things.
Hope this helps,
Tom
I want to write a query in Cypher and run it on Neo4j.
The query is:
Given some start vertexes, walk edges and find all vertexes that is connected to any of start vertex.
(start)-[*]->(v)
for every edge E walked
if startVertex(E).someproperty != endVertex(E).someproperty, output E.
The graph may contain cycles.
For example, in the graph above, vertexes are grouped by "group" property. The query should return 7 rows representing the 7 orange colored edges in the graph.
If I write the algorithm by myself it would be a simple depth / breadth first search, and for every edge visited if the filter condition is true, output this edge. The complexity is O(V+E)
But I can't express this algorithm in Cypher since it's very different language.
Then i wrote this query:
find all reachable vertexes
(start)-[*]->(v), reachable = start + v.
find all edges starting from any of reachable. if an edge ends with any reachable vertex and passes the filter, output it.
match (reachable)-[]->(n) where n in reachable and reachable.someprop != n.someprop
so the Cypher code looks like this:
MATCH (n:Col {schema:"${DWMDATA}",table:"CHK_P_T80_ASSET_ACCT_AMT_DD"})
WITH n MATCH (n:Col)-[*]->(m:Col)
WITH collect(distinct n) + collect(distinct m) AS c1
UNWIND c1 AS rn
MATCH (rn:Col)-[]->(xn:Col) WHERE rn.schema<>xn.schema and xn in c1
RETURN rn,xn
The performance of this query is not good as I thought. There are index on :Col(schema)
I am running neo4j 2.3.0 docker image from dockerhub on my windows laptop. Actually it runs on a linux virtual machine on my laptop.
My sample data is a small dataset that contains 0.1M vertexes and 0.5M edges. For some starting nodes it takes 60 or more seconds to complete this query. Any advice for optimizing or rewriting the query? Thanks.
The following code block is the logic I want:
VertexQueue1 = (starting vertexes);
VisitedVertexSet = (empty);
EdgeSet1 = (empty);
While (VertexSet1 is not empty)
{
Vertex0 = VertexQueue1.pop();
VisitedVertexSet.add(Vertex0);
foreach (Edge0 starting from Vertex0)
{
Vertex1 = endingVertex(Edge0);
if (Vertex1.schema <> Vertex0.schema)
{
EdgeSet1.put(Edge0);
}
if (VisitedVertexSet.notContains(Vertex1)
and VertexQueue1.notContains(Vertex1))
{
VertexQueue1.push(Vertex1);
}
}
}
return EdgeSet1;
EDIT:
The profile result shows that expanding all paths has a high cost. Looking at the row number, it seems that Cypher exec engine returns all paths but I want distint edge list only.
LEFT one:
match (start:Col {table:"F_XXY_DSMK_ITRPNL_IDX_STAT_W"})
,(start)-[*0..]->(prev:Col)-->(node:Col)
where prev.schema<>node.schema
return distinct prev,node
RIGHT one:
MATCH (n:Col {schema:"${DWMDATA}",table:"CHK_P_T80_ASSET_ACCT_AMT_DD"})
WITH n MATCH (n:Col)-[*]->(m:Col)
WITH collect(distinct n) + collect(distinct m) AS c1
UNWIND c1 AS rn
MATCH (rn:Col)-[]->(xn:Col) WHERE rn.schema<>xn.schema and xn in c1
RETURN rn,xn
I think Cypher lets this be much easier than you're expecting it to be, if I'm understanding the query. Try this:
MATCH (start:Col {schema:"${DWMDATA}",table:"CHK_P_T80_ASSET_ACCT_AMT_DD"})-->(node:Col)
WHERE start.schema <> node.schema
RETURN start, node
Though I'm not sure why you're comparing the schema property on the nodes. Isn't the schema for the start node fixed by the value that you pass in?
I might not be understanding the query though. If you're looking for more than just the nodes connected to the start node, you could do:
MATCH
(start:Col {schema:"${DWMDATA}",table:"CHK_P_T80_ASSET_ACCT_AMT_DD"})
(start)-[*0..]->(prev:Col)-->(node:Col)
WHERE prev.schema <> node.schema
RETURN prev, node
That open-ended variable length relationship specification might be slow, though.
Also note that when Cypher is browsing a particular path it stops which it finds that it's looped back onto some node (EDIT relationship, not node) in the path matched so far, so cycles aren't really a problem.
Also, is the DWMDATA value that you're passing in interpolated? If so, you should think about using parameters for security / performance:
http://neo4j.com/docs/stable/cypher-parameters.html
EDIT:
Based on your comment I have a couple of thoughts. First limiting to DISTINCT path isn't going to help because every path that it finds is distinct. What you want is the distinct set of pairs, I think, which I think could be achieved by just adding DISTINCT to the query:
MATCH
(start:Col {schema:"${DWMDATA}",table:"CHK_P_T80_ASSET_ACCT_AMT_DD"})
(start)-[*0..]->(prev:Col)-->(node:Col)
WHERE prev.schema <> node.schema
RETURN DISTINT prev, node
Here is another way to go about it which may or may not be more efficient, but might at least give you an idea for how to go about things differently:
MATCH
path=(start:Col {schema:"${DWMDATA}",table:"CHK_P_T80_ASSET_ACCT_AMT_DD"})-->(node:Col)
WITH rels(path) AS rels
UNWIND rels AS rel
WITH DISTINCT rel
WITH startNode(rel) AS start_node, endNode(rel) AS end_node
WHERE start_node.schema <> end_node.schema
RETURN start_node, end_node
I can't say that this would be faster, but here's another way to try:
MATCH (start:Col)-[*]->(node:Col)
WHERE start.property IN {property_values}
WITH collect(ID(node)) AS node_ids
MATCH (:Col)-[r]->(node:Col)
WHERE ID(node) IN node_ids
WITH DISTINCT r
RETURN startNode(r) AS start_node, endNode(r) AS end_node
I suspect that the problem in all cases is with the open-ended variable length path. I've actually asked on the Slack group to try to get a better understanding of how it works. In the meantime, for all the queries that you try I would suggest prefixing them with the PROFILE keyword to get a report from Neo4j on what parts of the query are slow.
// this is very inefficient!
MATCH (start:Col)-[*]->(node:Col)
WHERE start.property IN {property_values}
WITH distinct node
MATCH (prev)-[r]->(node)
RETURN distinct prev, node;
you might be better off with this:
MATCH (start:Col)
WHERE start.property IN {property_values}
MATCH (node:Col)
WHERE shortestPath((start)-[*]->(node)) IS NOT NULL
MATCH (prev)-[r]->(node)
RETURN distinct prev, node;
Usually I can find everything I need already on SO but not this time. I'm looking for a very simple way to exclude labels, for example (pseudo code):
match (n) where n not in (Label1, Label2) return n
Sorry about crappy query. In short I have labels x,y,z and I want to return all of them apart from z.
Thnx!
This should do it:
MATCH (n)
WHERE NOT n:Label1 AND NOT n:Label2
RETURN n;
If you have a long list of labels you want to exclude, I find this syntax to be helpful:
match (n)
where not labels(n) in [['label1'],['label2'],['label3']]
I'm trying to find a generic way to search for a node or set of nodes which does not have a link to a another node or set of nodes.
As an example, I was able to find all the nodes of a specific type (e.g. :Style) which are connected somehow to a specific set of nodes (e.g. :MetadataRoot), with the following:
match (root:MetadataRoot),
(n:Style),
p=shortestPath((root)-[*]-(n))
return p
Using this, I was able to subtract the set of all :Style nodes from the nodes returned by the above query, but that doesn't seem like the best way to go about this.
If you know the label of the start nodes you can use the EXISTS function :
MATCH (n:Style)
WHERE NOT EXISTS((n)-[]-())
RETURN n
If you know the end node :
MATCH (n:Style)
WHERE NOT EXISTS ((n)-[*]-(:MetadataRoot))
RETURN n
EDIT :
Not sure, but regarding the performance issues in your comment, a workaround could be something like this :
MATCH p=allShortestPaths((n:Style)-[*]-(:MetadataRoot))
WITH nodes(p) as nodesRelated
MATCH (s:Style) WHERE NOT s IN nodesRelated
This should be way faster and it should need less resources to execute:
MATCH (n:Style),
OPTIONAL MATCH p=shortestPath((:MetadataRoot)-[*0..40]-(n))
WITH n, p
WHERE p IS NULL
RETURN n ```
using Cypher 2 I want to find all the nodes of a certain label (Context), which are called either "health" or "opinion".
The query that works is:
MATCH (c:Context) WHERE c.name="health" OR c.name="opinion" RETURN c;
But I'm wondering if Cypher has a syntax that I could put it into the first MATCH part, something like this:
MATCH (c:Context{name:"health"|name:"opinion})
The example above doesn't work, but I'm just showing it to let you know what I mean.
Thank you!
Alternatively, you can do this:
MATCH (c:Context) WHERE c.name IN ['health', 'opinion'] RETURN c
Still not in the "MATCH" statement, but a little easier as your list of possible values grows.
You could do
MATCH (c:Context {name:"health"}), (d:Context { name:"opinion"})
RETURN c,d