My permissions graph looks like this:
In this situation,
user1 has permission on folder1 through Group1.
user2 has direct permissions without any group, though the user is part of group2 where group2 doesn't have access over folder1.
user3 has permission through group hierarchy, not the direct group to folder access.
I was able to write separate gremlin queries to determine whether a user has permission through one of the groups and user direct permission.
Checking permission through group
g.V().has('user','userId','user1').emit().repeat(out('member_of'))
.outE('has_permission').has('permission','p1').inV()
.has('folder','folderId','folder1').hasNext()
User-direct permission
g.V().has('user','userId','user2')
.outE('has_permission').has('permission','p1').inV()
.has('folder','folderId','folder1').hasNext()
But I couldn't figure out the logic in a single query which can check both direct and group to see whether the user has permission or not.
Can someone help me out here?
Your graph:
g = TinkerGraph.open().traversal()
g.addV('user').property('userId','user1').as('u1').
addV('user').property('userId','user2').as('u2').
addV('user').property('userId','user3').as('u3').
addV('group').property('groupId','group1').as('g1').
addV('group').property('groupId','group2').as('g2').
addV('group').property('groupId','group3').as('g3').
addV('folder').property('folderId','folder1').as('f1').
addE('member_of').from('u1').to('g1').
addE('member_of').from('u2').to('g2').
addE('member_of').from('u3').to('g3').
addE('member_of').from('g3').to('g1').
addE('has_permission').from('g1').to('f1').
addE('has_permission').from('u2').to('f1').iterate()
A general solution to your problem:
g.V().has('user','userId',<userId>).
emit().
until(__.not(outE('member_of'))).
repeat(out('member_of')).
filter(out('has_permission').has('folder','folderId',<folderId>)).hasNext()
Traversal executed on the sample graph:
gremlin> g.V().has('user','userId','user1').
emit().
until(__.not(outE('member_of'))).
repeat(out('member_of')).
filter(out('has_permission').has('folder','folderId','folder1')).hasNext()
==>true
gremlin> g.V().has('user','userId','user2').
emit().
until(__.not(outE('member_of'))).
repeat(out('member_of')).
filter(out('has_permission').has('folder','folderId','folder1')).hasNext()
==>true
gremlin> g.V().has('user','userId','user3').
emit().
until(__.not(outE('member_of'))).
repeat(out('member_of')).
filter(out('has_permission').has('folder','folderId','folder1')).hasNext()
==>true
Thanks Daniel.
just to complicate the above query to check whether user have given permission or not.
below is the answer for any one like me looking for
gremlin> g.V().has('user','userId','user3').
emit().
until(__.not(outE('member_of'))).
repeat(out('member_of')).
filter(outE('has_permission').has('permission','V').inV().has('folder','folderId','folder1')).hasNext()
==>true
Related
I am trying to retrieve all the node and properties details in parent-child hierarchy.
Nested within each other.
Since I am new with gremlin, graphDB I am having really tough time to get it done.
Please suggest a solution and if you could walk me through it, it will be great.
Following is my structure
And I am trying to keep the response as clean as possible.
I am using cosmosDB and Gremlin.
NET api for this.
I tried the following but it gave me response in key value,
g.V("some_id").repeat(out()).emit().tree().path()
g.V("some_id").emit().repeat(both().simplePath()).dedup()
please any kind of suggestion would be great.
I"m not sure what format you want your result, but use of path(), tree() or subgraph() would typically give you the graph structure. Since you are using CosmosDB, you're only options are path() and tree() as subgraph() does not appear to be supported.
Using this sample graph as a simple tree:
g.addV().property(id, '1').as('1').
addV().property(id, '2a').as('2a').
addV().property(id, '2b').as('2b').
addV().property(id, '3a').as('3a').
addV().property(id, '4a').as('4a').
addE('child').from('1').to('2a').
addE('child').from('1').to('2b').
addE('child').from('2a').to('3a').
addE('child').from('3a').to('4a')
you can see the effect of path() which basically gathers the contents of each step Gremlin took:
gremlin> g.V('1').repeat(out()).emit().path()
==>[v[1],v[2a]]
==>[v[1],v[2b]]
==>[v[1],v[2a],v[3a]]
==>[v[1],v[2a],v[3a],v[4a]]
Since I used out() we don't see the edges, but that is easily remedied by adding making a small adjustment to directly consume edges into the path history:
gremlin> g.V('1').repeat(outE().inV()).emit().path()
==>[v[1],e[0][1-child->2a],v[2a]]
==>[v[1],e[1][1-child->2b],v[2b]]
==>[v[1],e[0][1-child->2a],v[2a],e[2][2a-child->3a],v[3a]]
==>[v[1],e[0][1-child->2a],v[2a],e[2][2a-child->3a],v[3a],e[3][3a-child->4a],v[4a]]
Taken together with duplication removed on your application side you have a complete graph with path().
Replacing path() with tree() will essentially do that deduplication by maintaining the tree structure of the path history:
gremlin> g.V('1').repeat(out()).emit().tree()
==>[v[1]:[v[2b]:[],v[2a]:[v[3a]:[v[4a]:[]]]]]
gremlin> g.V('1').repeat(outE().inV()).emit().tree()
==>[v[1]:[e[0][1-child->2a]:[v[2a]:[e[2][2a-child->3a]:[v[3a]:[e[3][3a-child->4a]:[v[4a]:[]]]]]],e[1][1-child->2b]:[v[2b]:[]]]]
The Tree is just represented as a Map where each key represents a like a root and value is another Tree (i.e. the branches from it). It is perhaps better visualized this way:
gremlin> g.V('1').repeat(out()).emit().tree().unfold()
==>v[1]={v[2b]={}, v[2a]={v[3a]={v[4a]={}}}}
gremlin> g.V('1').repeat(out()).emit().tree().unfold().next().value
==>v[2b]={}
==>v[2a]={v[3a]={v[4a]={}}}
If neither of these structures are suitable and subgraph() is not available you can technically just capture and return the edges you traverse as the low level elements of your subgraph as described in this blog post.
Given the comments on this answer I also present the following option which used group():
gremlin> g.V('1').emit().
......1> repeat(outE().group('a').by(outV()).by(inV().fold()).inV()).cap('a').unfold()
==>v[1]=[v[2a], v[2b]]
==>v[3a]=[v[4a]]
==>v[2a]=[v[3a]]
It's not exactly a "tree" but if you know the root (in this case v[1]) you can find its key in the Map. The values are the children. You can then look up each of those keys in the Map to find if they have children and so on. For example, we can lookup v[2b] and find that it has no children while looking up [v2a] reveals a single child of [v3a]. Gremlin can be pretty flexible in getting answers if you can be sorta flexible in how you deal with the results.
In this very simple example I am trying to add a new vertex which should be labeled like an existing vertex but with some prefix attached:
g.V(1).addV('prefix_' + label()).valueMap(true)
What am I missing here? It's clearly not a String, but how would I serialize that?
gremlin> g.V(1).label()
==>Person
gremlin> g.V(1).constant(label())
==>[LabelStep]
Gremlin today does not provide a built in string concatenation function. It would be nice if it did. That means your best alternative today is to use an in line closure/lambda. Here is an example using TinkerGraph and the air-routes graph.
gremlin> g.V(3).map {"prefix_" + it.get().label}.as('a').addV(select('a'))
==>v[60867]
gremlin> g.V(60867).label()
==>prefix_airport
Note that not all graph databases allow closures so this cannot be assumed to work universally on any TinkerPop enabled Graph DB backend.
my ACL graph
In Summary every user or group who have access to Folder1 will have access to File1
usecase #1 - checking access for user1 on Folder1, which works fine with below gremlin
g.V().has('user','userId','user1').
emit().
until(__.not(outE('member_of'))).
repeat(out('member_of')).
filter(outE('has_permission').has('permission','VS_F').
inV().has('folder','folderId','Folder1')).hasNext()
usecase #2 - checking access for user1 on File1, how can modify above gremlin to achieve this ? im pretty much new to gremlin and doing a POC on janusgraph for my employer.
First things first: You should always start with a script that people can run to create your sample graph. Also, formatting the code in your question wouldn't hurt.
With that said, here's the script that creates your graph:
g = TinkerGraph.open().traversal()
g.addV('user').property('userId','user1').as('u1').
addV('user').property('userId','user2').as('u2').
addV('user').property('userId','user3').as('u3').
addV('group').property('groupId','group1').as('g1').
addV('group').property('groupId','group2').as('g2').
addV('group').property('groupId','group3').as('g3').
addV('folder').property('folderId','folder1').as('f1').
addV('file').property('fileId','file1').
addE('in_folder').to('f1').
addE('member_of').from('u1').to('g1').
addE('member_of').from('u2').to('g2').
addE('member_of').from('u3').to('g3').
addE('member_of').from('g3').to('g1').
addE('has_permission').from('g1').to('f1').
addE('has_permission').from('u2').to('f1').iterate()
...and the query you're looking for:
g.V().has('file','fileId','file1').
until(inE('has_permission')).
repeat(out('in_folder')).as('folder').
V().has('user','userId','user1').
emit().
until(__.not(outE('member_of'))).
repeat(out('member_of')).
filter(out('has_permission').where(eq('folder'))).hasNext()
In gremlin-console, is there a way to show all the methods available for a specific object?
For example, In gremlin-console if I type g.V().hasLabel("person") and I want to see what methods I can chain/call for the object returned by g.V().hasLabel("person"). How do you do that?
The answer is to use the <Tab> key.
gremlin> "test".c
capitalize() center( charAt( chars() codePointAt( codePointBefore( codePointCount( codePoints() collectReplacements( compareTo(
compareToIgnoreCase( concat( contains( contentEquals( count(
However, I'm finding that it is not working for something like g.V().o which I'd hoped would have shown out(). Apparently, the groovy shell (which is what the Gremlin Console is based on) doesn't seem to want to do the auto-complete on a fluent API. It seems to only work on the first object on which you are calling the method:
gremlin> g.
E( V( addV( addV() close() inject( tx() withBindings( withBulk(
withComputer( withComputer() withPath() withRemote( withSack( withSideEffect( withStrategies( withoutStrategies( anonymousTraversalClass
bytecode graph strategies
gremlin> x = g.V();[]
gremlin> x.o
option( optional( or( order( order() otherV() out( outE( outV()
gremlin> x.o
That stinks...that's not really a TinkerPop issue - we rely on the groovysh for that functionality. Not much we can do there I don't think....
Of course, you are using DSE Graph which means you have access to DataStax Studio which not only has the auto-complete that you're looking for but also schema support (and more!). I'd suggest that you switch to that.
I'm running Titan 0.3.2 with Cassandra as a data store. I'm also using rexpro-python for interacting with Titan over RexPro.
Issue & Question:
If I run this Python code:
>>> import rexpro
>>> conn = rexpro.RexProConnection('localhost', 8184, 'graph')
>>> conn.execute('g.addVertex(null, node_dict)', {'node_dict':{'my_dict':{}}})
{'_type': 'vertex', '_id': '2280164', '_properties': {'my_dict': {}}}
>>> conn.execute('g.commit()')
I can look up the resulting node in the Gremlin console:
gremlin> g.v(2280164).map
==>{my_dict={}}
And it looks like the my_dict map is created properly:
gremlin> g.v(2280164).my_dict.getClass()
==>class java.util.HashMap
However, I'm unable to update my_dict with a new key & value:
gremlin> g.v(2280164).my_dict['abc'] = 123
==>123
gremlin> g.commit()
==>null
gremlin> g.v(2280164).map
==>{my_dict={}}
If I first reset my_dict to a new object in the console, my attempt to add key abc works as expected:
gremlin> g.v(2280164).my_dict = [:]
gremlin> g.v(2280164).my_dict['abc'] = 123
==>123
gremlin> g.v(2280164).map
==>{my_dict={abc=123}}
My question: how can I update my_dict with a new KV pair on a vertex created via RexPro?
Attempted workarounds/solutions:
This same issue happens when the vertex is created with a non-parameterized version of the python script:
>>> conn.execute('g.addVertex([my_dict:[:]])')
Also, not sure if relevant for this issue, but it looks like the new map created in the console is a LinkedHashMap (whereas the python/rexpro code created a HashMap):
gremlin> g.v(2280164).my_dict.getClass()
==>class java.util.LinkedHashMap
Updating the dictionary/map that comes off a vertex property circumvents the database level since you are directly modifying the value on the heap.
In other words, Titan does not know that you updated the map and therefore does not persist the change.
Always think of property values as immutable even though they might be mutable java objects because those mutations are invisible to the database.
This will work:
newdict = v.my_dict.clone()
newdict['hello']='other'
v.setProperty('my_dict',newdict)
graph.commit()
v.map
I tried to recreate this entirely in the REPL and couldn't. I even explicitly created a java.util.HashMap and it seemed to work fine with Titan/Cassandra. I think LinkedHashMap is the default for groovy when you do [:].
gremlin> g = TitanFactory.open('bin/cassandra.local')
==>titangraph[cassandrathrift:127.0.0.1]
gremlin> g.addVertex()
==>v[4]
gremlin> g.v(4).my_dict = new java.util.HashMap()
gremlin> g.v(4).map
==>{my_dict={}}
gremlin> g.v(4).my_dict['abc'] = 123
==>123
gremlin> g.v(4).map
==>{my_dict={abc=123}}
gremlin> g.v(4).my_dict.getClass()
==>class java.util.HashMap
gremlin> g.commit()
==>null
gremlin> g.v(4).map
==>{my_dict={abc=123}}
What happens if you don't parameterize your RexPro request? In other words, do you get different results if you do:
>>> conn.execute('g.addVertex([my_dict:[:]])')
If that works that might be a workaround for you. I know the recommendation is to "parameterize requests" via RexPro but since this script is basically static, it will cache nicely in the scriptengine at not much additional cost per request.