need some tips/advise on a gremlin query ... :)
I have these types of vertices ...
orders: id, cid (string), ts (long)
// predicates for the orders
ip: id
phone: id
// few more
and Edges go from predicates to orders:
ip -- ip_used_in --> order
phone -- ph_used_in --> order
// few more from predicates to orders
Now i want to insert an order vertex and the corresponding ip and phone vertices if they are not present and add the edge between them.
I have got first part working using the fold + coalesce pattern. But it adds parallel edges if edge already exists.
// inserting o3, ip1 and ph1 if not present and adding edge between them
g.
V("o3").fold().coalesce(unfold(),addV("order").property(id, "o3").property("ts", 11).property("cid", "c1")).
sideEffect(addE('ip_used_in').from(V('ip1').fold().coalesce(unfold(), addV("ip").property(id, "ip1")))).
sideEffect(addE('ph_used_in').from(V('ph1').fold().coalesce(unfold(), addV("ph").property(id, "ph1")))).
// ... few more predicates omitted
iterate()
Now i'm stuck at an additional condition : add the edge between order and ip/phone/predicate if there doesn't exist any other edge to an order having same cid, with greater or equal ts. if some order exists with same cid but lesser ts, drop that edge and add the new one. Because of the fold i cannot refer to conditionally added order vertex in the beginning.
Essentially i want to only have the latest order (max ts) connected to the predicates (ip, phone, ... etc) per cid.
So Q1. How to nest conditions/side-effects to conditionally add a vertex and link an edge to it based on another condition ?
Q2. Is the effect of the SideEffect visible in later parts of the traversal ? didnt seem to find the info in gremlin reference.
Sample code to test in gremlin consiole:
// create initial state
// o1, ip1, ph1
// o2, ip2, ph1
g.
addV("order").property(id, "o1").property("ts", 10).property("cid", "c1").as("o1").
addV("order").property(id, "o2").property("ts", 9).property("cid", "c2").as("o2").
addV("ip").property(id, "ip1").as("ip1").
addV("ip").property(id, "ip2").as("ip2").
addV("ph").property(id, "ph1").as("ph1").
addE("ip_used_in").from("ip1").to("o1").
addE("ip_used_in").from("ip2").to("o2").
addE("ph_used_in").from("ph1").to("o1").
addE("ph_used_in").from("ph1").to("o2").
iterate()
// try different scenarios
// try to add o1 again, no exception but in tinkergraph got duplicate edges between o1 - ip1 and o1 - ph1
g.
V("o1").fold().coalesce(unfold(),addV("order").property(id, "o1").property("ts", 11).property("cid", "c1")).
sideEffect(addE('ip_used_in').from(V('ip1').fold().coalesce(unfold(), addV("ip").property(id, "ip1")))).
sideEffect(addE('ph_used_in').from(V('ph1').fold().coalesce(unfold(), addV("ph").property(id, "ph1")))).
iterate()
// how to remove existing edges between o1 - ip1 and o1 - ph1 ?
g.
V("o3").fold().coalesce(unfold(),addV("order").property(id, "o3").property("ts", 11).property("cid", "c1")).
sideEffect(addE('ip_used_in').from(V('ip1').fold().coalesce(unfold(), addV("ip").property(id, "ip1")))).
sideEffect(addE('ph_used_in').from(V('ph1').fold().coalesce(unfold(), addV("ph").property(id, "ph1")))).
iterate()
// how to avoid adding edges since later orders exist from same cid = c1 against ip1 and ph1 ?
g.
V("o0").fold().coalesce(unfold(),addV("order").property(id, "o0").property("ts", 0).property("cid", "c1")).
sideEffect(addE('ip_used_in').from(V('ip1').fold().coalesce(unfold(), addV("ip").property(id, "ip1")))).
sideEffect(addE('ph_used_in').from(V('ph2').fold().coalesce(unfold(), addV("ph").property(id, "ph2")))).
iterate()
Related
I want to use the result of two traversals a, b to calculate the value for an property. I don't know how to join them into combinedTraversal with both traversals starting from the origin element/vertex.
Graph graph = TinkerFactory.createModern();
GraphTraversal a = __.values("age").count().as("count")
.constant(10).as("allCount")
.math("count / allCount")
// .as("a");
GraphTraversal b = __.values("age").count().as("count")
.constant(10).as("allCount")
.math("count / allCount")
// .as("b");
GraphTraversal combinedTraversal = __
.local(a).as("a")
.local(b).as("b")
.math("a * b");
graph.traversal().V()
.has("age")
.property(Cardinality.single, "value", combinedTraversal)
.iterate();
In the example, traversal a and b assume to start at a given vertex and calculate their value. When i'm using local() the position of the traversal is changed and I don't know how to step back to the origin.
Using sideEffect() on the other hand does not refer to the current element, instead calculating the values for all elements into a map.
Is there any way to build such a combinedTraversal? (The "complex" calculation traversals are chosen on purpose, of course there are simpler ways to solve this example)
Thank You.
I found a solution: projection https://tinkerpop.apache.org/docs/current/reference/#project-step
GraphTraversal combinedTraversal = __.project("a", "b").by(a).by(b).math("a * b");
In a CosmosDB Graph collection, I'm trying to find all nodes of type typeA that do not have any "live" edges pointing to nodes of type typeB.
Some edges may be "soft-deleted" (i.e. g.E().has('softDeleted', true) ). These edges should be ignored.
This is what I tried:
g.V().hasLabel('typeA')
-> returns 10 nodes of type "typeA", as expected
g.V().hasLabel('typeA')
.outE().not(has('softDelete', true))
.inV().hasLabel('typeB')
-> returns 2 nodes of type "typeB", as expected
g.V().hasLabel('typeA')
.where( // same condition as above, inside a 'where' clause
outE().not(has('softDelete', true))
.inV().hasLabel('typeB')
.count().is(eq(0)) // " where there are no such edges"
)
-> returns all 10 nodes of type "typeA" again ?!
In the query above, applying the where clause seems to not filter anything.
The following query will find all typeA vertices that do not have an edge to a typeB vertex. Only edges that have no softDelete property or that edges that have softDelete set to false will be considered, other edges will be ignored.
g.V().hasLabel('typeA').
not(outE().or(hasNot('softDelete'),
has ('softDelete', false)).
inV().hasLabel('typeB'))
I have a hierarchy of node relationships like:
Organisation -> Department -> System -> Function -> Port - > Request -> Response -> Parameter
The query -
MATCH q=(p)-[*]->(b:checkoutby) WHERE p.name ="william" RETURN q
gives the entire network belonging to the Parent node -> william up-till the last node mentioned -> checkoutby.
However, I want only the two related nodes to appear.
I tried the query -
MATCH (n:william) WHERE n is null RETURN n UNION MATCH n=(p)-
[:Parameter]->(b) WHERE
b.name ="checkoutBy" RETURN n
But here the effect of "william" node i.e. the first parent node is nullified and we get the output irrespective of the parent node.
For which, I even tried this query -
MATCH (n) WHERE none(node in nodes(n) WHERE node:william) RETURN n
UNION MATCH n=(p)--()-[:Parameter]->(b) WHERE b.name ="cabinet"
RETURN n
but I get error -
Neo.ClientError.Statement.SyntaxError: Type mismatch: expected Path but was Node (line 1, column 36 (offset: 35))
"MATCH (n) WHERE none(node in nodes(n) WHERE node: william ) RETURN n UNION MATCH n=(p)--()-[:Parameter]->(b) WHERE b.name ="cabinet" RETURN n"
I even tried the intersection query but to no avail .
MATCH (n1:william), (n2),(q:cabinet)
WHERE (n1)<-[:Department]-() AND (n2)<-[:Parameter]-(q)
RETURN count(q), collect(q.name)
Warning Error-
This query builds a Cartesian product between disconnected patterns.
If a part of a query contains multiple disconnected patterns, this will build a Cartesian product between all those parts. This may produce a large amount of data and slow down query processing. While occasionally intended, it may often be possible to reformulate the query that avoids the use of this cross product, perhaps by adding a relationship between the different parts or by using OPTIONAL MATCH (identifier is: (n2))
EXPLAIN MATCH (n1:william), (n2),(ego:cabinet)
^
Even this query doesn't work -
MATCH (n:william) RETURN n UNION MATCH n=(p)-[:Parameter]->(b)
WHERE b.name ="checkoutBy"
call apoc.path.expandConfig(n, {labelFilter:'-william'}) yield path
return path
I want to retrieve the checkoutby / cabinet node only if it is from the topmost parent node (william).
I don't have reputations to comment so asking here:
It's not clear from your question if William is a Name property or a Label?
You used it as a name in the first query and as a Label in all other queries.
I am assuming it is a Label, It looks like it is a label from the screenshot you shared.
If you want to check if the checkoutby/cabinet node is related to William node and return only if it's related you can use the following query:
MATCH (w:william)-[*]-(c:checkoutby) return w,c
Please note: These type of queries consumes too much Memory.
If I've understood your problem the (b:checkoutby) node does not have any incoming relationships so you could write :
MATCH (p)-[*]->(b:checkoutby) WHERE p.name ="william" AND NOT EXISTS ( (b)-[]->()) RETURN p, b
I have this following type of graph which I get using this query:
MATCH (p:Person)-[:REPORTS_TO *]->(c:Person) WHERE p.name="F"
WITH COLLECT (c) + p AS all
UNWIND all as p MATCH (p)-[:REPORTS_TO]-(c)
RETURN p,c;
Use-Case:
1. I want to find what level is a node at with respect to node F?
Example :
Node `D`, `E` are direct child of `F`, hence they are at level 1
Node `A,B,C` are childs of `D` (which is child of `F`) hence level 2
Node `X` is child of `A' (which is at level 2), hence level 3
and so onnnnn....
I tried to solve this by introducing a variable i and increment it with each iteration (but it didn't worked).
MATCH (p:Person)-[:REPORTS_TO *]->(c:Person) WHERE p.name="F"
WITH COLLECT (c) + p AS all ,i:int=0
UNWIND all as p MATCH (p)-[:REPORTS_TO]->(c)
RETURN p,c, i=i+1;
2. Given two nodes find relation between then
e.g Find relation between F and X?
Expected answer = 3 (as it is at level 3)
How should I proceed to solve these use-cases?
Note : Graphical response from Neo4j server isn't necessarily needed , Json response will also be fine.
UC1 Use Path and length(p) function
MATCH p=(root:Person)-[:REPORTS_TO *]->(child:Person)
WHERE root.name="F"
RETURN nodes(p)[-2], nodes(p)[-1],length(p)
This will find all paths from root node, and return pairs of second to last and last nodes + level you want.
nodes(p) - list of nodes on path p
[-2] - second node from the end of the list
UC2: use shortestPath function:
MATCH (p1:Person),(p2:Person)
WHERE p1.name = '..' AND p2.name = '...'
MATCH p=shortestPath((p2)-[:REPORTS_TO*]->(p2))
RETURN length(p)
My use-case contains two types of node Problem and Tag where a Problem can have "One-To-Many" relation with Tag i.e. there are multiple (Problem)-[:CONATINS]->(Tag) relations for a single problem (ignore the syntax). With the given array of tags I want cypher query to get Problem which do not contain any of those Tag
Sample Nodes:
Problem {id:101, rank:2.389} ; Tag {name: "python"}
Consider this example dataset:
CREATE (p1:Problem {id:1}),
(p2:Problem {id:2}),
(p3:Problem {id:3}),
(t1:Tag {name:'python'}),
(t2:Tag {name:'cypher'}),
(t3:Tag {name:'neo4j'}),
(t4:Tag {name:'ruby'}),
(t1)-[:TAGS]->(p1),
(t2)-[:TAGS]->(p1),
(t2)-[:TAGS]->(p2),
(t3)-[:TAGS]->(p2),
(t3)-[:TAGS]->(p3),
(t4)-[:TAGS]->(p3)
If you want problems that aren't tagged by python or cypher, you only want problem 3 to be returned.
MATCH (t:Tag)
WHERE t.name IN ['python', 'cypher']
MATCH (p:Problem)
WITH p, sum(size((t)-[:TAGS]->(p))) AS matches
WHERE matches = 0
RETURN p;
This returns only problem 3.
In your case, you have to MATCH both nodes which don't have connections to Tag and nodes which are connected to other Tag nodes (but not the ones in your list). I would split this in two queries:
// unconnected nodes
MATCH (p:Problem)
WHERE NOT (p)-[:CONTAINS]-()
RETURN p
// combine queries with union (both have to return the same)
UNION
// nodes which fullfill you criterion
MATCH (p:Problem)-[:CONTAINS]->(t:Tag)
// collect distinct Problem nodes with a list of associated Tag names
WITH DISTINCT p, collect(t.name) AS tag_name
// use a none predicate to filter all Problems where none
// of the query tag names are found
WHERE none(x IN ['python', 'java', 'haskell'] WHERE x IN tag_name)
RETURN p