Z Jones
Z Jones

Reputation: 2035

Is this query possible in neo4j / gremlin?

if i have a graph that looks like:

N3->member_of->N1
N2->knows->N1
N3->likes->N2
N4->member_of->N1
N5->likes->N2

Is there a way to do a single query that will do the following:

  1. If started at N3 will return N2
  2. And that same query started at N4 will return N2
  3. And that same query started at N5 will return N2

(preferably in gremlin)

EDIT: Clarification: I can go through up to a 2nd degree connection, as long as the first degree relationship is "member_of".

Upvotes: 2

Views: 992

Answers (5)

Daniel Kuppitz
Daniel Kuppitz

Reputation: 10904

Pretty old question, but since nobody came up with a Gremlin solution, here it is:

I took Bobbys initialization script:

g = new TinkerGraph()
(1..5).each { g.addVertex(it) }
g.addEdge(g.v(3), g.v(1), "member_of") 
g.addEdge(g.v(2), g.v(1), "knows")
g.addEdge(g.v(3), g.v(2), "likes")
g.addEdge(g.v(5), g.v(2), "likes") 
g.addEdge(g.v(4), g.v(1), "member_of")

And here's your Gremlin query:

gremlin> g.v(3).copySplit(_().out('likes'), _().out('member_of').loop('start'){true}{true}.in('knows')).exhaustMerge().dedup()
==>v[2]
gremlin> g.v(4).copySplit(_().out('likes'), _().out('member_of').loop('start'){true}{true}.in('knows')).exhaustMerge().dedup()
==>v[2]
gremlin> g.v(5).copySplit(_().out('likes'), _().out('member_of').loop('start'){true}{true}.in('knows')).exhaustMerge().dedup()
==>v[2]

Cheers, Daniel

Upvotes: 3

Matt Luongo
Matt Luongo

Reputation: 14849

Is the idea that you want to return all incoming and outgoing relationships of a node (person?), and all related nodes of any group of which a person is a member? So "groups" commute their relationships on "members"?

If so, and assuming recursive groups aren't allowed, I've come up with an alternative graph that might illustrate your use case (as I understand it) more clearly -> http://console.neo4j.org/?id=wyr207

If you run

start n=node(5) match n-[?:knows|likes]-related, n-[?:member_of]->group-[:knows|likes]-other_related return related, other_related

on the graph, related would return all directly related nodes, and other_related all other nodes returned from a group, if the node is a member of a group. Combining those is beyond my Cypher ability, but they will be de-duped AFAIK (no nodes in related will be included in other_related).

Try the query in the console link with a few different node ids (N5 has a node id of 1) and see if that's what you were thinking. It would be simple to add relationship direction, etc.

Translating this to Gremlin is a tad bit tedious (pattern matching in Cypher is more natural), but LMK if this is in the right direction and I'll do it.

Upvotes: 0

Bobby Norton
Bobby Norton

Reputation: 1504

First create your graph in a Gremlin Groovy shell using a TinkerGraph:

g = new TinkerGraph()
(1..5).each { g.addVertex(it) }
g.addEdge(g.v(3), g.v(1), "member_of") 
g.addEdge(g.v(2), g.v(1), "knows")
g.addEdge(g.v(3), g.v(2), "likes")
g.addEdge(g.v(5), g.v(2), "likes") 
g.addEdge(g.v(4), g.v(1), "member_of")

It sounds like you want a query that starts at vertices 3, 4, or 5 and returns vertex 2. The queries below use the algorithm:

  • Get vertex 'x'
  • Get both incoming and outgoing adjacent vertices
  • Loop over both again until we either loop 3 times or find a vertex with id "2"
  • Dedup results by getting the next() member of the pipe
gremlin> g.v(3).both.loop(1) {it.loops < 3}{it.object.id == "2"}.next()
==>v[2]
gremlin> g.v(4).both.loop(1) {it.loops < 3}{it.object.id == "2"}.next()
==>v[2]
gremlin> g.v(5).both.loop(1) {it.loops < 3}{it.object.id == "2"}.next()
==>v[2]

You might also find the Gremlin documentation on the path pattern to be useful.

Upvotes: 0

Peter Neubauer
Peter Neubauer

Reputation: 6331

not sure your setup is correct, tried to do it here: http://tinyurl.com/d2mjkj2 - the setup correct?

If the first relationship type needs to be member_of then N5 should not return N2. Otherwise, you can do something like

start s=node(3,4,5) match s-[r1:member_of]->()<-[r2*0..1]-end return s,end

to return patterns that start with a member_of relationship, and then have 0 or 1 relationships of any type. Tighten this up if you want, see http://docs.neo4j.org/chunked/snapshot/query-match.html#match-variable-length-relationships for details.

Upvotes: 0

ulkas
ulkas

Reputation: 5918

this is how it would look in cypher:

1: start n=node(3) match n-[:LIKES]->m return m;
2: start n=node(4) match n-[:MEMBER_OF]-m-[]-k return k;  (will return n2,n3. if you want n2 only match n-[:MEMBER_OF]-m-[:KNOWS]-k )
3: the same as 1)

Upvotes: 0

Related Questions