how to "join" two vertices on Gremlin? - graph-databases

I meet some trouble with Gremlin console; here is my schema.
Knowing:
ID 1 (vertex)
ID 3 (vertex)
Label: "created" (edge)
I would like to get ID 9 (edge)
v = g.v(1)
v.outE("created").id
only works if there is only one "created" edge

You can do:
g.e(9)
or, filtering from v[1]:
g.v(1).outE('created')[[id:9]]
or, if you mean getting the created edges between vertex 1 and 3:
g.v(1).outE('created').as('x').inV[[id:3]].back('x').id
g.v(1).outE('created').inV[[id:3]].back(2).id
Hope that helps,
Marko.
http://markorodriguez.com

Thanks Marko, it works fine (but I have to use id:'3' instead of id:3).
And by the way, is this code:
g.v(1).outE('created').as('x').inV[[id:'3']].back('x').id
more efficient than this one:
g.v(1).outE.as('x').inV[[id:'3']].back('x').id

Related

Laravel query for multiple arrays

I have collection in Laravel-Mongodb for Comments and this is the structure :
this is one comment with no reply but one comment may have multiple replies and as u can see count will be the reply numbers and edges field will have different arrays of replies like this :
this picture has 3 replies , i want to write a query which could be able to go through all 3 elements and get specific "id" values, i don't know how to do this!
$getUser = \App\Instacomment::where('comment.edge_threaded_comments.edges.node.owner.id' , $request->cm_thread)->get();
I wrote this query, but not working though, returns null

Cypher returns exponential count result on 'join'

I am learning Cypher on Neo4j and I am having trouble in understanding how to perform an efficient 'join' equivalent in Cypher.
I am using the standard Matrix character example and I have added some nodes to the mix called 'Gun' with a relation of ':GIVEN_TO'. You can see the console with my query result here:
http://console.neo4j.org/r/rog2hv
The query I am using is:
MATCH (Neo:Crew { name: 'Neo' })-[:KNOWS*..]->(other:Crew),(other)<-[:GIVEN_TO]-(g:Gun),(Neo)<-[:GIVEN_TO]-(g2:Gun)
RETURN count(g2);
I have given Neo 4 guns, but when I perform the above I get a count of '12'. This seems to be the case because there are 3 'others' and 3*4 = 12. So I get some exponential result.
What should my query look like to get the correct count ('4') from the example?
Edit:
The reason I am not querying through Guns directly as suggested by #ceej is because in my real use case I have to do this traversal as described above. Adding DISTINCT does not do anything for my result.
The reason you get 12 guns instead of 4 is because your query produces a cartesian product. This is because you have asked for items in the same match statement without joining them. #ceej rightly pointed out if you want to find Neo's guns you would do as he suggested in his first query.
If you wanted to get a list of the crew members and their guns then you could do something like this...
MATCH (crew:Crew)<-[:GIVEN_TO]-(g:Gun)
RETURN crew.name, collect(g.name)
Which finds all of the crew members with guns and returns their name and the guns that they were given.
If you wanted to invert it and get a list of the guns and the respective crew members they were give to you could do the following...
MATCH (crew:Crew)<-[:GIVEN_TO]-(g:Gun)
RETURN g.name, collect(crew.name)
If you wanted to find all of the crew that knew Neo multiple levels deep that were given a gun you could write the query like this...
MATCH (crew:Crew)<-[:GIVEN_TO]-(g:Gun)
WITH crew, g
MATCH (neo:Crew {name: 'Neo'})-[:KNOWS*0..]->(crew)
RETURN crew.name, collect(g.name)
That finds all the crew that were given guns and then determines which of them have a :KNOWS path to Neo.
Forgive me, but I am am unclear why you have the initial MATCH in your query. From your explanation it would appear that you are trying to get the number of :Gun nodes linked to Neo by the :GIVEN_TO relationship. In which case all you need is the latter part of your query. Which would give you something like
MATCH (neo:Crew { name: 'Neo' })<-[:GIVEN_TO]-(g:Gun)
RETURN count(g)
Furthermore, to make sure that you are only counting distinct :Gun nodes you can add DISTINCT to the RETURN statement.
MATCH (neo:Crew { name: 'Neo' })<-[:GIVEN_TO]-(g:Gun)
RETURN count( DISTINCT g )
This is possibly unnecessary in your case but can be helpful when the pattern that you are matching on can arrive at the same node by different traversals.
Have I misunderstood your requirement?

How to query for multiple vertices and counts of their relationships in Gremlin/Tinkerpop 3?

I am using Gremlin/Tinkerpop 3 to query a graph stored in TitanDB.
The graph contains user vertices with properties, for example, "description", and edges denoting relationships between users.
I want to use Gremlin to obtain 1) users by properties and 2) the number of relationships (in this case of any kind) to some other user (e.g., with id = 123). To realize this, I make use of the match operation in Gremlin 3 like so:
g.V().match('user',__.as('user').has('description',new P(CONTAINS,'developer')),
__.as('user').out().hasId(123).values('name').groupCount('a').cap('a').as('relationships'))
.select()
This query works fine, unless there are multiple user vertices returned, for example, because multiple users have the word "developer" in their description. In this case, the count in relationships is the sum of all relationships between all returned users and the user with id 123, and not, as desired, the individual count for every returned user.
Am I doing something wrong or is this maybe an error?
PS: This question is related to one I posted some time ago about a similar query in Tinkerpop 2, where I had another issue: How to select optional graph structures with Gremlin?
Here's the sample data I used:
graph = TinkerGraph.open()
g = graph.traversal()
v123=graph.addVertex(id,123,"description","developer","name","bob")
v124=graph.addVertex(id,124,"description","developer","name","bill")
v125=graph.addVertex(id,125,"description","developer","name","brandy")
v126=graph.addVertex(id,126,"description","developer","name","beatrice")
v124.addEdge('follows',v125)
v124.addEdge('follows',v123)
v124.addEdge('likes',v126)
v125.addEdge('follows',v123)
v125.addEdge('likes',v123)
v126.addEdge('follows',v123)
v126.addEdge('follows',v124)
My first thought, was: "Do we really need match step"? Secondarily, of course, I wanted to write this in TP3 fashion and not use a lambda/closure. I tried all manner of things in the first iteration and the closest I got was stuff like this from Daniel Kuppitz:
gremlin> g.V().as('user').local(out().hasId(123).values('name')
.groupCount()).as('relationships').select()
==>[relationships:[:]]
==>[relationships:[bob:1]]
==>[relationships:[bob:2]]
==>[relationships:[bob:1]]
so here we used local step to restrict the traversal within local to the current element. This works, but we lost the "user" tag in the select. Why? groupCount is a ReducingBarrierStep and paths are lost after those steps.
Well, let's go back to match. I figured I could try to make the match step traverse using local:
gremlin> g.V().match('user',__.as('user').has('description','developer'),
gremlin> __.as('user').local(out().hasId(123).values('name').groupCount()).as('relationships')).select()
==>[relationships:[:], user:v[123]]
==>[relationships:[bob:1], user:v[124]]
==>[relationships:[bob:2], user:v[125]]
==>[relationships:[bob:1], user:v[126]]
Ok - success - that's what we wanted: no lambdas and local counts. But, it still left me feeling like: "Do we really need match step"? That's when Mr. Kuppitz closed in on the final answer which makes copious use of the by step:
gremlin> g.V().has('description','developer').as("user","relationships").select().by()
.by(out().hasId(123).values("name").groupCount())
==>[user:v[123], relationships:[:]]
==>[user:v[124], relationships:[bob:1]]
==>[user:v[125], relationships:[bob:2]]
==>[user:v[126], relationships:[bob:1]]
As you can see, by can be chained (on some steps). The first by groups by vertex and the second by processes the grouped elements with a "local" groupCount.

Conditionally creating vertex in Titan

I have a situation where I need to check if a vertex with three satisfying properties property1='a',property2='b',property3='c' already exists in a graph and if it does not exist, I need to create it. Basically there should be a unique vertex in the graph with the combination of these three properties. I have tried out this snippet of gremlin code to check based on one property 'id'
getOrCreate = { id ->
def p = g.V('userId', id)
if (p.hasNext()) ? p.next() : g.addVertex([userId:id])
Not very clear about the best way to modify this to achieve what i need with gremlin since I'm a beginner. All I can think of is nesting more if's and else's in the last statement. Any help is appreciated, thank you.
There are several approaches. One way would be to extend your traversal a bit:
getOrCreate = { one, two, three ->
def p = g.V('prop1', one).has('prop2',two).has('prop3',three)
p.hasNext() ? p.next() : g.addVertex([prop1:one,prop2:two,prop3:three])
In the above code, prop1 represents an indexed property, then you just filter on the rest. That prop should be the most selective property in that it should filter out the most results.
If for some reason prop is not selective enough then this solution might not be fast enough. In other words, if you have 1 billion vertices and g.V('prop1', one) returns 100000 then you will be in-memory filtering those, which will be kinda slow. If this is your case, I would consider creating a "poor-man's" composite index, by adding a fourth property to index on that combines all three properties into one. Then just do your lookups on that.
You're almost there.
getOrCreate = { p1, p2, p3 ->
def p = g.V().has('property1', p1).has('property2', p2).has('property3', p3)
p.hasNext() ? p.next() : g.addVertex(['property1':p1,'property2':p2,'property3':p3])
}
Cheers,
Daniel

Can I find all vertices that have no connected edges in OrientDB?

Is there an easy way to query a cluster for all vertices that have no incoming edges?
This is more complete because also covers the case the collection exists but it's empty:
select from the_cluster where in().size() = 0
The following SQL seems to work (as edges are stored as fields in and out on the vertices):
select from the_cluster where in is null
Should it be this?
select from the_cluster where in_edgename is null
I know it's an old question but figured for anyone else who was wondering the same thing.
You can do something like this:
for a vertex of a class say Vtex and the Edge of class say Edg
select from Vtex where in('Edg').size() =0
This will return all the vertices of Vtex class which have no incoming edge of type Edg.

Resources