Titan : Filter connected vertices - titan

I am using Titan using JAVA. I have following situation:
There is post vertex,many user write comments on this post same user can post multiple comments on it.
U(email, name, sex)
What I have to do is, I have to send notification to all commenter if any new comment is posted.
Now the thing is how can i filter users i.e if there is situation like
U1 ------COMMENTED ----------> POST
U2 ------COMMENTED ----------> POST
U3 ------COMMENTED ----------> POST
U1 ------COMMENTED ----------> POST
If a new comment is posted, notification should be sent to U1 U2 U3. Now if i iterate through incoming edge COMMENTED it fetch U1 twice. But i need U1 only once just to get their email. How can I achieve that

I know your question was about Java, but the Gremlin Groovy sessions below demonstrate the approach. One way would be to use the dedup step.
http://gremlindocs.com/#filter/dedup
That will ensure that U1 exists only once after that step as shown here:
gremlin> g = TinkerGraphFactory.createTinkerGraph()
==>tinkergraph[vertices:6 edges:6]
gremlin> g.V.out.in
==>v[4]
==>v[6]
==>v[1]
==>v[1]
==>v[1]
==>v[4]
==>v[6]
==>v[1]
==>v[4]
==>v[4]
==>v[6]
==>v[1]
gremlin> g.V.out.in.dedup
==>v[4]
==>v[6]
==>v[1]
Alternatively you could write all users to a Set:
gremlin> x = [] as Set
gremlin> g.V.out.in.fill(x);null
==>null
gremlin> x
==>v[4]
==>v[6]
==>v[1]

Related

Graph Traversal & Filtering with Gremlin using OrientDB

Group[code=a]->Choice[selected=true]
Group[code=a]->Choice[selected=false]
Group[code=a]->Choice[selected=false]
Group[code=b]->Choice[selected=false]
Group[code=b]->Choice[selected=false]
Group[code=c]->Choice[selected=false]
Group[code=c]->Choice[selected=true]
Given the above Vertices, I'm looking to query for Group Vertices, where a group does not have any Choice vertices, with a selected attribute as true.
Hence the result should return only Group b
Group[code=b]
Any help is appreciated.
Here's your graph - when asking questions about Gremlin it's always helpful to provide your sample data in this way:
graph = TinkerGraph.open()
g = graph.traversal()
g.addV('group').property('code','a').as('a').
addV('group').property('code','b').as('b').
addV('group').property('code','c').as('c').
addV('choice').property('selected',true).
addE('link').from('a').
addV('choice').property('selected',false).
addE('link').from('a').
addV('choice').property('selected',false).
addE('link').from('a').
addV('choice').property('selected',false).
addE('link').from('b').
addV('choice').property('selected',false).
addE('link').from('b').
addV('choice').property('selected',false).
addE('link').from('c').
addV('choice').property('selected',true).
addE('link').from('c').iterate()
One way to get the answer you want is to do a traversal like this:
gremlin> g.V().hasLabel('group').
......1> where(__.not(out('link').has('selected',true))).
......2> values('code')
==>b
The above answer is for TinkerPop 3.x. In TinkerPop 2.x the pattern is the same. You would basically do:
g.V().has('label','group').filter{ it._().out('link').has('selected',true).hasNext() }

gremlin query if-else-then in the graph traversal

I have been trying to figure this if-else in a Gremlin query.
Assume g.V({0}) is the group vertex below.
var q = "g.V({0}).as('groupName', 'groupId', 'ownerId').inE(eIsAdminOf, eIsMemberOf).as('rel', 'joinDate').outV().hasLabel(userLabel).as('memberId')";
//TODO:var q = "g.V({0}).as('groupName', 'groupId', 'ownerId').inE(eIsAdminOf";
//if .has('mCanList',true).inE(eIsAdminOf, eIsMemberOf)
//if .has('mCanList',false).inE(eIsAdminOf)
//, eIsMemberOf).as('rel', 'joinDate').outV().hasLabel(userLabel).as('memberId')";
I want the .inE(eIsAdminOf, eIsMemberOf) to be based on property value mCanList of true or false as in the comments above.
Have been trying a choose to no avail:
var q = "g.V({0}).as('groupName', 'groupId', 'ownerId','mCanList');
q += ".by(values('mCanList').choose(is(true),.inE(eIsAdminOf, eIsMemberOf), .inE(eIsAdminOf))";
q += '.as('rel', 'joinDate').outV().hasLabel(userLabel).as('memberId')”;
I am using node.js to build the gremlin query with the gremlin library. The worst option for me is to build 2 separate async queries which build the results separately based on
if .has('mCanList',true).inE(eIsAdminOf, eIsMemberOf) or
if .has('mCanList',false).inE(eIsAdminOf)
TIA
I'm not sure that I follow the reasoning behind all the step labeling that you have so I've mostly omitted that to demonstrate use of choose() which seems to be the focus of your question. I roughly approximated what I think your graph structure is based on how you described the problem (if you have future questions, please consider providing some sample graph creation code that can be easily cut/paste into the a Gremlin Console session). In any case, here's what I think you need:
gremlin> g = TinkerGraph.open().traversal()
==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
gremlin> g.addV(id,1).property("mCanList",true).as('a').
......1> addV(id,2).as('b').
......2> addV(id,3).as('c').
......3> addE("isAdminOf").from("b").to("a").
......4> addE("isMemberOf").from("c").to("a").iterate()
gremlin> g.V(1).choose(has('mCanList',true),inE("isAdminOf","isMemberOf"),inE("isAdminOf"))
==>e[1][2-isAdminOf->1]
==>e[2][3-isMemberOf->1]
gremlin>
gremlin> g.V(1).property('mCanList',false)
==>v[1]
gremlin> g.V(1).choose(has('mCanList',true),inE("isAdminOf","isMemberOf"),inE("isAdminOf"))
==>e[1][2-isAdminOf->1]
If I try to directly edit your Gremlin I think your traversal basically just needs to look like this:
var q = "g.V({0});
q += ".choose(has('mCanList',true),inE(eIsAdminOf, eIsMemberOf), inE(eIsAdminOf))";
q += ".outV().hasLabel(userLabel)";
I presume that "eIsAdminOf", "eIsMemberOf" and "userLabel" are JS variables - if not they would need quotes around them if they happen to be actual label names. Again, I'm not clear on what you were doing with all the uses of as() - none of that seemed relevant to your traversal based on your question.

How do I update a specific edge property using Gremlin/Titan/TinkerPop3?

The goal
I have a simple enough task to accomplish: Set the weight of a specific edge property. Take this scenario as an example:
What I would like to do is update the value of weight.
Additional Requirements
If the edge does not exist, it should be created.
There may only exist at most one edge of the same type between the two nodes (i.e., there can't be multiple "votes_for" edges of type "eat" between Joey and Pizza.
The task should be solved using the Java API of Titan (which includes Gremlin as part of TinkerPop 3).
What I know
I have the following information:
The Vertex labeled "user"
The edge label votes_for
The value of the edge property type (in this case, "eat")
The value of the property name of the vertex labeled "meal" (in this case "pizza"), and hence also its Vertex.
What I thought of
I figured I would need to do something like the following:
Start at the Joey vertex
Find all outgoing edges (which should be at most 1) labeled votes_for having type "eat" and an outgoing vertex labeled "meal" having name "pizza".
Update the weight value of the edge.
This is what I've messed around with in code:
//vertex is Joey in this case
g.V(vertex.id())
.outE("votes_for")
.has("type", "eat")
//... how do I filter by .outV so that I can check for "pizza"?
.property(Cardinality.single, "weight", 0.99);
//... what do I do when the edge doesn't exist?
As commented in code there are still issues. Would explicitly specifying a Titan schema help? Are there any helper/utility methods I don't know of? Would it make more sense to have several vote_for labels instead of one label + type property, like vote_for_eat?
Thanks for any help!
You are on the right track. Check out the vertex steps documentation.
Label the edge, then traverse from the edge to the vertex to check, then jump back to the edge to update the property.
g.V(vertex.id()).
outE("votes_for").has("type", "eat").as("e").
inV().has("name", "pizza").
select("e").property("weight", 0.99d).
iterate()
Full Gremlin console session:
gremlin> Titan.version()
==>1.0.0
gremlin> Gremlin.version()
==>3.0.1-incubating
gremlin> graph = TitanFactory.open('inmemory'); g = graph.traversal()
==>graphtraversalsource[standardtitangraph[inmemory:[127.0.0.1]], standard]
gremlin> vertex = graph.addVertex(T.label, 'user', 'given_name', 'Joey', 'family_name', 'Tribbiani')
==>v[4200]
gremlin> pizza = graph.addVertex(T.label, 'meal', 'name', 'pizza')
==>v[4104]
gremlin> votes = vertex.addEdge('votes_for', pizza, 'type', 'eat', 'weight', 0.8d)
==>e[1zh-38o-4r9-360][4200-votes_for->4104]
gremlin> g.E(votes).valueMap(true)
==>[label:votes_for, weight:0.8, id:2rx-38o-4r9-360, type:eat]
gremlin> g.V(vertex.id()).outE('votes_for').has('type','eat').as('e').inV().has('name','pizza').select('e').property('weight', 0.99d).iterate(); g.E(votes).valueMap(true)
==>[label:votes_for, weight:0.99, id:2rx-38o-4r9-360, type:eat]
Would explicitly specifying a Titan schema help?
If you wanted to start from the Joey node without having a reference to the vertex or its id, this would be a good use case for a Titan composite index. The traversal would start with:
g.V().has("given_name", "Joey")
Are there any helper/utility methods I don't know of?
In addition to the TinkerPop reference documentation, there are several tutorials that you can read through:
Getting Started
The Gremlin Console
Recipes
Would it make more sense to have several vote_for labels instead of one label + type property, like vote_for_eat?
Depends on what your graph model or query patterns are, but more granular labels like vote_for_eat can work out fine. You can pass multiple edge labels on the traversal step:
g.V(vertex.id()).outE('vote_for_eat', 'vote_for_play', 'vote_for_sleep')
Update
There may only exist at most one edge of the same type between the two nodes
You can use the Titan schema to help with this, specifically define an edge label with multiplicity ONE2ONE. An exception will be thrown if you create more than one votes_for_eat between Joey and pizza.
Jason already answered nearly all of your questions. The only aspect missing is:
If the edge does not exist, it should be created.
So I'll try to answer this point with a slightly different query. This query adds a new edge if it doesn't exist already and then updates / adds the weight property:
g.V(vertex.id()).outE('votes_for').has('type', 'eat')
.where(__.inV().hasLabel('meal').has('name','pizza')) // filter for the edge to update
.tryNext() // select the edge if it exists
.orElseGet({g.V(vertex.id()).next()
.addEdge('votes_for', g.V(pizzaId).next(), 'type', 'eat')}) // otherwise, add the edge
.property('weight', 0.99) // finally, update / add the 'weight' property

Return certain vertices and whether they share an edge with a particular vertex

I'm trying to model follower relationships between certain users in my app:
user----follows----user
(think Twitter)
Given a set of userIds I need to return all those user vertices and a boolean if a particular user (currentUser) has a follows edge to those users. So I need to know whether or not currentUser is following each of these users:
user1: true
user2: true
user3: false
user4: true
I'm stuck on how to fetch that follow status. If I return each user vertex like so:
currentUser = g.V(1);
g.V().hasLabel("appUser").or(__.has("userId","123869681319429"),
__.has("userId","103659593341656")).valueMap();
what would be an efficient command to determine if each of those had an incoming follows edge from currentUser?
TitanDB 1.0.0 running on DynamoDB.
Edit- Adding My full working traversal:
g.V().hasLabel('appUser').or(__.has('cId', '1232'),__.has('cId', '1116')).group().by().by(__.in('follows').hasId(hasLabel('appUser').has('pId', 'd13dfa6').id()).count())
Edit 2 -
I wound up rewriting this traversal to better capture the data I needed by using as() and select(). Leaving here for reference:
g.V().hasLabel('appUser').or(__.has('cId', '1232'),__.has('cId', '1116')).as('user','followCount').select('user','followCount').by(__.valueMap()).by(__.in('follows').hasId(hasLabel('appUser').has('pId', 'd13dfa6').id()).count())
Here's one way to do it. Assume this sample graph:
gremlin> graph = TinkerGraph.open()
==>tinkergraph[vertices:0 edges:0]
gremlin> vUser1 = graph.addVertex(id,1)
==>v[1]
gremlin> vUser2 = graph.addVertex(id,2)
==>v[2]
gremlin> vUser3 = graph.addVertex(id,3)
==>v[3]
gremlin> vUser1.addEdge('follows',vUser2)
==>e[0][1-follows->2]
gremlin> vUser3.addEdge('follows',vUser3)
==>e[1][3-follows->3]
Your code snippet above demonstrates that you will have the "current user" vertex and the vertices of the users you want to compare to that current user to see if there are any follows relationships. Given that assumption, you could approach it this way:
gremlin> g = graph.traversal()
==>graphtraversalsource[tinkergraph[vertices:3 edges:2], standard]
gremlin> g.V(vUser2,vUser3).group().by().by(__.in("follows").hasId(vUser1.id()).count())
==>[v[2]:1, v[3]:0]
In this case, you iterate the list of user vertices you want to compare against, then group on them. The traversal will output a Map where a value greater than 0 represents a follows relationship and a value of zero represents the opposite of no follow relationship. So, in the example above, user 1 follows 2 but doesn't follow 3.

traversing orientdb graph, sql-traverse vs gremlin

I want to model linked nodes data set:
Node(A)----next---->Node(B)----next---->Node(C)
applying SQL-Traverse:
traverse out('next') from Node(A)
will include Node(A) in result; A,B,C ,and this is the desired output,
where as using gremlin:
g.('Node(A)').as('start').out('next').loop('start')
will only returns B,C ,
my question is how to emit Node A in gremlin , followed by other nodes, in the same order they were linked in, and i prefer the end result to be pipline; i.e. i tried aggregate(), but the problem with it is that it will make me use the aggregated collection as a start point for a new pipline with new traverse, and i dont want this behavior, any ideas? thanks.
I think path will do what you want:
gremlin> g = TinkerGraphFactory.createTinkerGraph()
==>tinkergraph[vertices:6 edges:6]
gremlin> g.v(1).as('s').out().loop('s'){true}{true}.path()
==>[v[1], v[3]]
==>[v[1], v[2]]
==>[v[1], v[4]]
==>[v[1], v[4], v[3]]
==>[v[1], v[4], v[5]]