How to remove cyclic vertex list from list of outer vertexes - datastax

I am new in dse graph, I want to create gremlin query which gives me list of all vertex which is linked from specified vertex but from this list I want to remove those list which are linked cyclic.
e.g.
A --> B
A --> C
A --> D
B --> A
If I have above relation then I want below vertex list as result
[C,D]
B and A should not be in above list as it has cyclic relation
I have below two separate query to find all linked vertexes and to find cyclic vertex
g.V().has('id','id').as('mainV').outE('Prerequisite').inV();
g.V().has('id','id').as('mainV').out().out().cyclicPath().path().unfold().dedup();
Could you please help me to find exact query to achieve my requirement.

So you basically want to filter out vertices, that have an in and an out edge to a particular vertex.
This is your sample graph:
gremlin> g = TinkerGraph.open().traversal()
==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
gremlin> g.addV().property(id, "A").as("a").
......1> addV().property(id, "B").as("b").
......2> addV().property(id, "C").as("c").
......3> addV().property(id, "D").as("d").
......4> addE("link").from("a").to("b").
......5> addE("link").from("a").to("c").
......6> addE("link").from("a").to("d").
......7> addE("link").from("b").to("a").iterate()
And this is the traversal you're looking for:
gremlin> g.V().as("a").not(out().out().where(eq("a"))).not(__.in().in().where(eq("a")))
==>v[C]
==>v[D]

It sounds like you want to use SimplePath. Please see here for documentation - http://tinkerpop.apache.org/docs/current/reference/#simplepath-step

Related

How to use multiple union step in gremlin query?

I want to convert following cypher query in gremlin but facing issue while using union.
match d=(s:Group{id:123})<-[r:Member_Of*]-(p:Person) with d,
RELATIONSHIPS(d) as rels
WHERE NONE(rel in rels WHERE EXISTS(rel.`Ceased On`))
return *
UNION
match d=(s:Group{id:123})<-[r:Member_Of*]-(p:Group)-[r1:
Member_Of*]->(c:Group) with d,
RELATIONSHIPS(d) as rels
WHERE NONE(rel in rels WHERE EXISTS(rel.`Ceased On`))
return *
UNION
match d=(c:Group{id:123})-[r:Member_Of*]->(p:Group) with d,
RELATIONSHIPS(d) as rels
WHERE NONE(rel in rels WHERE EXISTS(rel.`Ceased On`))
return *
UNION
match d=(s:Group{id:123})<-[r:Member_Of*]-(p:Group)<-[r1:
Member_Of*]-(c:Person) with d,
RELATIONSHIPS(d) as rels
where NONE(rel in rels WHERE EXISTS(rel.`Ceased On`))
return *
In above cypher query, source vertex is Group, which has id '123', so for incoming and outgoing edge, I have created following gremlin query.
g.V().hasLabel('Group').has('id',123)
union(
__.inE('Member_Of').values('Name'),
__.outE('Member_Of').values('Name'))
.path()
Now I have to traverse incoming edge for the vertex, which is incoming vertex for source vertex in above query, where I am confused with union syntax.
Please help, Thanks :)
This part of the Cypher query
match d=(s:Group{id:123})<-[r:Member_Of*]-(p:Group)<-[r1:Member_Of*]-(c:Person)
In Gremlin, can be expressed as
g.V().has('Group','id',123).
repeat(inE('Member_Of').outV()).until(hasLabel('G')).
repeat(inE('Member_Of').outV()).until(hasLabel('Person')).
path().
by(elementMap())
If there are not really multiple hops involved (i.e. in Cypher if you do not really need the '*') you can remove the repeat construct and just keep the inE and outV steps. Anyway, this bit of Gremlin will get you the nodes and edges (relationships) along with all their properties etc. as the path will contain their elementMap.
Note that a straight port from Cypher to Gremlin may not take full advantage of the target database. For example, many Gremlin enabled stores allow user provided (real) ID values. This makes querying a lot more efficient as you can use something like this:
g.V('123')
to directly find a vertex.
Please add a comment below if this does not fully unblock you.
UPDATED: 2021-10-29
I used the air routes data set to test that the query pattern works, using this query:
g.V().has('airport','code','AUS').
repeat(inE('contains').outV()).until(hasLabel('country')).limit(1).
repeat(outE('contains').inV()).until(hasLabel('airport')).limit(3).
path().
by(elementMap())
Following is the total replacement of cypher query with gremlin query.
g.V().has('Group','id',123). //source vertex
union(
//Following represent incoming Member_Of edge towards source vertex from Person Node, untill the last node in the chain
repeat(inE('Member_Of').outV()).until(hasLabel('Person')),
//Following represent incoming Member_Of edge from Group to source vertex and edge outwards from same Group, untill the last node in the chain
repeat(inE('Member_Of').outV().hasLabel('Group').simplePath()).until(inE().count().is(0)).
repeat(outE('Member_Of').inV().hasLabel('Group').simplePath()).until(inE().count().is(0)),
//Following represent outgoing Member_Of edge from source vertex to another Group node, untill the last node in the chain
repeat(outE('Member_Of').inV().hasLabel('Group').simplePath()).until(outE().count().is(0)),
//Following represent incoming Member_Of edge from Group to source vertex and incoming edge from person to Group untill the last node in the chain
repeat(inE('Member_Of').outV().hasLabel('Group').simplePath()).until(inE().count().is(0)).
repeat(inE('Member_Of').outV().hasLabel('Person').simplePath()).until(inE().count().is(0))
).
path().by(elementMap())

Cypher query for gremlin traversal

New to cypher query
g.V().has('Entity1','id',within(id1)).in('Entity2').
where(__.out('Entity3').where(__.out('Entity4').has('name',within(name))))
how to convert the above gremlin to cypher and return adjacent Entity2 invertex.
Here condition is
out('Entity3') should be out of Entity2
out('Entity4') should be out of Entity3 and name in the provided list of values
Return adjacent vertex of inEntity2
Straight answer:
MATCH (m:Entity1 )<-[:Entity2]-(n)
WHERE (n)-[:Entity3]->()-[:Entity4]->({name: "ABC"})
AND m.id in ["id1"]
RETURN n
# Assuming id is a property here.
# If id is the actual ID of the node
MATCH (m:Entity1 )<-[:Entity2]-(n)
WHERE (n)-[:Entity3]->()-[:Entity4]->({name: "ABC"})
AND ID(m) in ["id1"]
RETURN n
I tried to create the graph for you use-case using this query:
CREATE (a:Entity2)-[:Entity2]->(b:Entity1 {id:"id1"}),
(a)-[:Entity3]->(:Entity3)-[:Entity4]->(:Entity4 {name:"ABC"})
the graph looks like this:
However, I think while writing your gremlin traversal you had the intention of specifying the label of the vertex rather than label of the edge. That is why in the query I wrote to create the graph, the relationship and the vertex, relationship is pointing to have same label.
If that is your intention then your cypher query would look like.
MATCH (:Entity1 {id:"id1"})<--(n:Entity2)
WHERE (n)-->(:Entity3)-->(:Entity4 {name: "ABC"})
RETURN n
I'm not 100% sure what you are looking for as the Gremlin above seems incomplete compared to the description but I think what you are looking for is something like this:
MATCH (e1:Entity1)<-[:Entity2]-(e2)-[:Entity3]->(e3)-[:Entity4]->(e4 {code: 'LHR'})
WHERE e1 IN (id1)
RETURN e2

Create subgraph query in Gremlin around single node with outgoing and incoming edges

I have a large Janusgraph database and I'd to create a subgraph centered around one node type and including incoming and outgoing nodes of specific types.
In Cypher, the query would look like this:
MATCH (a:Journal)N-[:PublishedIn]-(b:Paper{paperTitle:'My Paper Title'})<-[:AuthorOf]-(c:Author)
RETURN a,b,c
This is what I tried in Gremlin:
sg = g.V().outE('PublishedIn').subgraph('j_p_a').has('Paper','paperTitle', 'My Paper Title')
.inE('AuthorOf').subgraph('j_p_a')
.cap('j_p_a').next()
But I get a syntax error. 'AuthorOf' and 'PublishedIn' are not the only edge types ending at 'Paper' nodes.
Can someone show me how to correctly execute this query in Gremlin?
As written in your query, the outE step yields edges and the has step will check properties on those edges, following that the query processor will expect an inV not another inE. Without your data model it is hard to know exactly what you need, however, looking at the Cypher I think this is what you want.
sg = g.V().outE('PublishedIn').
subgraph('j_p_a').
inV().
has('Paper','paperTitle', 'My Paper Title').
inE('AuthorOf').
subgraph('j_p_a')
cap('j_p_a').
next()
Edited to add:
As I do not have your data I used my air-routes graph. I modeled this query on yours and used some select steps to limit the data size processed. This seems to work in my testing. Hopefully you can see the changes I made and try those in your query.
sg = g.V().outE('route').as('a').
inV().
has('code','AUS').as('b').
select('a').
subgraph('sg').
select('b').
inE('contains').
subgraph('sg').
cap('sg').
next()

need to join the vertex in dse

I have created properties and vertex like
schema.propertyKey('REFERENCE_ID').Int().multiple().create();
schema.propertyKey('Name').Text().single().create();
schema.propertyKey('PARENT_NAME').Text().single().create(); ... ....
.. schema.propertyKey('XXX').Text().single().create();
schema.vertexLabel('VERT1').properties("REFERENCE_ID",.."PROPERTY10"....."PROPERTY15")//15
PROPERTIES
schema.vertexLabel('VER2').properties("REFERENCE_ID",.."PROPERTY20"......"PROPERTY35")//35
PROPERTIES
schema.vertexLabel('VERT3').properties("REFERENCE_ID",.."PROPERTY20"....."PROPERTY25")//25
PROPERTIES
schema.vertexLabel('VERT4').properties("REFERENCE_ID",.."PROPERTY20"....."PROPERTY25")//25
PROPERTIES
and loaded csv data using DSG GRAPHLOADER(CSV TO(VERTEX)).
and created edge
schema.edgeLabel('ed1').single().create()
schema.edgeLabel('ed1').connection('VERT1', 'VER2').add()
schema.edgeLabel('ed1').single().create()
schema.edgeLabel('ed1').connection('VERT1', 'VERT3').add()
schema.edgeLabel('ed2').single().create()
schema.edgeLabel('ed2').connection('VERT3','VERT4').add()
But I don't know how to map the data between vertex and edge. I want to join all these 4 vertex. Could you please help on this?
I'm new to dse. I just ran the above code in datastax studio successfully and I can see the loaded data. I need to join the vertex...
Sql code: I want same in dse germlin.
select v1.REFERENCE_ID,v2.name,v3.total from VERT1 v1
join VER2 v2 on v1.REFERENCE_ID=v2.REFERENCE_ID
join VERT3 v3 on v2.sid=v3.sid
there are 2 "main" options in DSE for adding edge data, plus one if you're also using DSE Analytics.
One is to use Gremlin, like what's documented here - https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/using/insertTraversalAPI.html
This approach would be a traversal based approach and may not be the best/fastest choice for bulk operations
Another solution is to use the Graph Loader, check out the example with the .asEdge code sample here - https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/dgl/dglCSV.html#dglCSV
If you have DSE Analytics enabled, you can also use DataStax's DSE GraphFrame implementation, which leverages Spark, to preform this task as well. Here's an example - https://docs.datastax.com/en/dse/6.0/dse-dev/datastax_enterprise/graph/graphAnalytics/dseGraphFrameImport.html

Neo4j: How to pass a variable to Neo4j Apoc (apoc.path.subgraphAll) Property

Am new to Neo4j and trying to do a POC by implementing a graph DB for Enterprise Reference / Integration Architecture (Architecture showing all enterprise applications as Nodes, Underlying Tables / APIs - logically grouped as Nodes, integrations between Apps as Relationships.
Objective is to achieve seamlessly 'Impact Analysis' using the strength of Graph DB (Note: I understand this may be an incorrect approach to achieve whatever am trying to achieve, so suggestions are welcome)
Let me come brief my question now,
There are four Apps - A1, A2, A3, A4; A1 has set of Tables (represented by a node A1TS1) that's updated by Integration 1 (relationship in this case) and the same set of tables are read by Integration 2. So the Data model looks like below
(A1TS1)<-[:INT1]-(A1)<-[:INT1]-(A2)
(A1TS1)-[:INT2]->(A1)-[:INT2]->(A4)
I have the underlying application table names captured as a List property in A1TS1 node.
Let's say one of the app table is altered for a new column or Data type and I wanted to understand all impacted Integrations and Applications. Now am trying to write a query as below to retrieve all nodes & relationships that are associated/impacted because of this table alteration but am not able to achieve this
Expected Result is - all impacted nodes (A1TS1, A1, A2, A4) and relationships (INT1, INT2)
Option 1 (Using APOC)
MATCH (a {TCName:'A1TS1',AppName:'A1'})-[r]-(b)
WITH a as STRTND, Collect(type(r)) as allr
CALL apoc.path.subgraphAll(STRTND, {relationshipFilter:allr}) YIELD nodes, relationships
RETURN nodes, relationships
This faile with error Failed to invoke procedure 'apoc.path.subgraphAll': Caused by: java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.String
Option 2 (Using with, unwind, collect clause)
MATCH (a {TCName:'A1TS1',AppName:'A1'})-[r]-(b)
WITH a as STRTND, Collect(r) as allr
UNWIND allr as rels
MATCH p=()-[rels]-()-[rels]-()
RETURN p
This fails with error "Cannot use the same relationship variable 'rels' for multiple patterns" but if I use the [rels] once like p=()-[rels]=() it works but not yielding me all nodes
Any help/suggestion/lead is appreciated. Thanks in advance
Update
Trying to give more context
Showing the Underlying Data
MATCH (TC:TBLCON) RETURN TC
"TC"
{"Tables":["TBL1","TBL2","TBL3"],"TCName":"A1TS1","AppName":"A1"}
{"Tables":["TBL4","TBL1"],"TCName":"A2TS1","AppName":"A2"}
MATCH (A:App) RETURN A
"A"
{"Sponsor":"XY","Platform":"Oracle","TechOwnr":"VV","Version":"12","Tags":["ERP","OracleEBS","FinanceSystem"],"AppName":"A1"}
{"Sponsor":"CC","Platform":"Teradata","TechOwnr":"RZ","Tags":["EDW","DataWarehouse"],"AppName":"A2"}
MATCH ()-[r]-() RETURN distinct r.relname
"r.relname"
"FINREP" │ (runs between A1 to other apps)
"UPFRNT" │ (runs between A2 to different Salesforce App)
"INVOICE" │ (runs between A1 to other apps)
With this, here is what am trying to achieve
Assume "TBL3" is getting altered in App A1, I wanted to write a query specifying the table "TBL3" in match pattern, get all associated relationships and connected nodes (upstream)
May be I need to achieve in 3 steps,
Step 1 - Write a match pattern to find the start node and associated relationship(s)
Step 2 - Store that relationship(s) from step 1 in a Array variable / parameter
Step 3 - Pass the start node from step 1 & parameter from step 2 to apoc.path.subgraphAll to see all the impacted nodes
This may conceptually sound valid but how to do that technically in neo4j Cypher query is the question.
Hope this helps
This query may do what you want:
MATCH (tc:TBLCON)
WHERE $table IN tc.Tables
MATCH p=(tc)-[:Foo*]-()
WITH tc,
REDUCE(s = [], x IN COLLECT(NODES(p)) | s + x) AS ns,
REDUCE(t = [], y IN COLLECT(RELATIONSHIPS(p)) | t + y) AS rs
UNWIND ns AS n
WITH tc, rs, COLLECT(DISTINCT n) AS nodes
UNWIND rs AS rel
RETURN tc, nodes, COLLECT(DISTINCT rel) AS rels;
It assumes that you provide the name of the table of interest (e.g., "TBL3") as the value of a table parameter. It also assumes that the relationships of interest all have the Foo type.
It first finds tc, the TBLCON node(s) containing that table name. It then uses a variable-length non-directional search for all paths (with non-repeating relationships) that include tc. It then uses COLLECT twice: to aggregate the list of nodes in each path, and to aggregate the list of relationships in each path. Each aggregation result would be a list of lists, so it uses REDUCE on each outer list to merge the inner lists. It then uses UNWIND and COLLECT(DISTINCT x) on each list to produce a list with unique elements.
[UPDATE]
If you differentiate between your relationships by type (rather than by property value), your Cypher code can be a lot simpler by taking advantage of APOC functions. The following query assumes that the desired relationship types are passed via a types parameter:
MATCH (tc:TBLCON)
WHERE $table IN tc.Tables
CALL apoc.path.subgraphAll(
tc, {relationshipFilter: apoc.text.join($types, '|')}) YIELD nodes, relationships
RETURN nodes, relationships;
WIth some lead from cybersam's response, the below query gets me what I want. Only constraint is, this result is limited to 3 layers (3rd layer through Optional Match)
MATCH (TC:TBLCON) WHERE 'TBL3' IN TC.Tables
CALL apoc.path.subgraphAll(TC, {maxLevel:1}) YIELD nodes AS invN, relationships AS invR
WITH TC, REDUCE (tmpL=[], tmpr IN invR | tmpL+type(tmpr)) AS impR
MATCH FLP=(TC)-[]-()-[FLR]-(SL) WHERE type(FLR) IN impR
WITH FLP, TC, SL,impR
OPTIONAL MATCH SLP=(SL)-[SLR]-() WHERE type(SLR) IN impR RETURN FLP,SLP
This works for my needs, hope this might also help someone.
Thanks everyone for the responses and suggestions
****Update****
Enhanced the query to get rid of Optional Match criteria and other given limitations
MATCH (initTC:TBLCON) WHERE $TL IN initTC.Tables
WITH Reduce(O="",OO in Reduce (I=[], II in collect(apoc.node.relationship.types(initTC)) | I+II) | O+OO+"|") as RF
MATCH (TC:TBLCON) WHERE $TL IN TC.Tables
CALL apoc.path.subgraphAll(TC,{relationshipFilter:RF}) YIELD nodes, relationships
RETURN nodes, relationships
Thanks all (especially cybersam)