Gremlin
Gremlin is a query language and domain specific language for traversing property graphs. This language has application in the areas of graph query, analysis, and manipulation.Gremlin is an open source project maintained by TinkerPop.
You can use sample Tinker graph database for practice.
Nodes represent entities such as people, businesses, accounts, or any other item you might want to keep track of.
Properties are pertinent information that relate to nodes. For instance, if "Wikipedia" were one of the nodes, one might have it tied to properties such as "website", "reference material", or "word that starts with the letter 'w'", depending on which aspects of "Wikipedia" are pertinent to the particular database.
Edges are the lines that connect nodes to nodes or nodes to properties and they represent the relationship between the two. Most of the important information is really stored in the edges. Meaningful patterns emerge when one examines the connections and interconnections of nodes, properties, and edges.
Below command is loading graph database.
gremlin> g = TinkerGraphFactory.createTinkerGraph()
Load TestData into TitanDB through gremlin
1.Checkout Wellaware project and Build it
2.After build you will get nori-0.16.0 in prj\target\jar folder ,copy it and place into \titan\ext folder
3.Open conf/titan-cassandra.properties file and change storage.hostname
4.Open gremlin.bat file from titan\bin and set CP=d:\titan\ext\prj
4.Start TitanDB
./bin/titan.sh start
4.Start gremlin from console mode.
D:\titan\bin>gremlin.bat
you will get gremlin> mode after run gremlin.bat
5.Excute below steps to load data into TitanDB
gremlin>g=TitanFactory.open('../conf/titan-cassandra.properties')
gremlin>import com.xxx.xxx.util.*
gremlin>loader = new BulkLoader(g)
gremlin>loader.bootstrap("D:\\welltest\\test_load.json")
gremlin>loader.loadCsvFile("D:\\welltest\\demo.csv")
gremlin>loader.loadSeriesData("D:\\welltest\\tsdata.csv")
gremlin>GraphIndexFactory.createTypes(g)
gremlin>g.commit()
Sample JSON
Sample Graph Database JSON
{
"vertices":[
{"name":"marko","age":29,"_id":1,"_type":"vertex"},
{"name":"vadas","age":27,"_id":2,"_type":"vertex"},
{"name":"lop","lang":"java","_id":3,"_type":"vertex"},
{"name":"josh","age":32,"_id":4,"_type":"vertex"},
{"name":"ripple","lang":"java","_id":5,"_type":"vertex"},
{"name":"peter","age":35,"_id":6,"_type":"vertex"}
],
"edges":[
{"weight":0.5,"_id":7,"_type":"edge","_outV":1,"_inV":2,"_label":"knows"},
{"weight":1.0,"_id":8,"_type":"edge","_outV":1,"_inV":4,"_label":"knows"},
{"weight":0.4,"_id":9,"_type":"edge","_outV":1,"_inV":3,"_label":"created"},
{"weight":1.0,"_id":10,"_type":"edge","_outV":4,"_inV":5,"_label":"created"},
{"weight":0.4,"_id":11,"_type":"edge","_outV":4,"_inV":3,"_label":"created"},
{"weight":0.2,"_id":12,"_type":"edge","_outV":6,"_inV":3,"_label":"created"}
]
}
SQL Commands
gremlin> g = TinkerGraphFactory.createTinkerGraph()
gremlin> g.class
// lets look at all the vertices
gremlin> g.V
// lets look at all the names of those vertices
gremlin> g.V.name
// lets look at all the properties of those vertices
gremlin> g.V.map
// lets look at all the edges
gremlin> g.E
gremlin> v = g.v(1)
gremlin> v.name + ' is ' + v.age + ' years old.'
// lets do a traversal from the '1' marko vertex to the adjacent outgoing vertices.
gremlin> v.out
// lets only take 'knows' labeled edges
gremlin> v.out('knows')
// lets do a traversal from the '1' marko vertex to its outgoing edges.
// in the property graph world, edges are first class citizens that can be traversed to.
gremlin> v.outE
gremlin> g
gremlin> g.V('name','hercules')
gremlin> g.V('name','hercules').out('father')
gremlin> g.V('name','hercules').out('father').out('father')
gremlin> g.V('name','hercules').out('father').out('father').name
gremlin> g.V('name','hercules').name
gremlin> g.V('name','hercules').out('father').name
gremlin> g.V('name','hercules').out('father').out('father').name
// lets only traverse to the head vertices of those edges
// that have a weight that is less than 1.0
gremlin> v.outE.has('weight', T.lt, 1.0f).inV
// what are the weight values on all outgoing edges
gremlin> v.outE.weight
// lets do the same, but with a more general "filter closure"
gremlin> v.outE.filter{it.weight < 1.0}.inV
// lets get the property maps of these vertices.
gremlin> v.outE.filter{it.weight < 1.0}.inV.map
// lets traverse to marko's 30+ year old friends' created projects
gremlin> v.out('knows').filter{it.age > 30}.out('created').name
g.V('name','hercules').out('father').loop(1){true}{true}.name
gremlin> hercules = g.V('name','hercules').next()
gremlin> hercules.out('father','mother').type
gremlin> hercules.out('battled').type
gremlin> hercules.out('battled').map
gremlin> theseus = g.addVertex([name:'theseus',type:'human'])
gremlin> cerberus = g.V('name','cerberus').next()
gremlin> g.addEdge(theseus,cerberus,'battled')
gremlin> hercules.out('battled').in('battled').except([hercules]).name
Gremlin is a query language and domain specific language for traversing property graphs. This language has application in the areas of graph query, analysis, and manipulation.Gremlin is an open source project maintained by TinkerPop.
You can use sample Tinker graph database for practice.
Nodes represent entities such as people, businesses, accounts, or any other item you might want to keep track of.
Properties are pertinent information that relate to nodes. For instance, if "Wikipedia" were one of the nodes, one might have it tied to properties such as "website", "reference material", or "word that starts with the letter 'w'", depending on which aspects of "Wikipedia" are pertinent to the particular database.
Edges are the lines that connect nodes to nodes or nodes to properties and they represent the relationship between the two. Most of the important information is really stored in the edges. Meaningful patterns emerge when one examines the connections and interconnections of nodes, properties, and edges.
Below command is loading graph database.
gremlin> g = TinkerGraphFactory.createTinkerGraph()
Load TestData into TitanDB through gremlin
1.Checkout Wellaware project and Build it
2.After build you will get nori-0.16.0 in prj\target\jar folder ,copy it and place into \titan\ext folder
3.Open conf/titan-cassandra.properties file and change storage.hostname
4.Open gremlin.bat file from titan\bin and set CP=d:\titan\ext\prj
4.Start TitanDB
./bin/titan.sh start
4.Start gremlin from console mode.
D:\titan\bin>gremlin.bat
you will get gremlin> mode after run gremlin.bat
5.Excute below steps to load data into TitanDB
gremlin>g=TitanFactory.open('../conf/titan-cassandra.properties')
gremlin>import com.xxx.xxx.util.*
gremlin>loader = new BulkLoader(g)
gremlin>loader.bootstrap("D:\\welltest\\test_load.json")
gremlin>loader.loadCsvFile("D:\\welltest\\demo.csv")
gremlin>loader.loadSeriesData("D:\\welltest\\tsdata.csv")
gremlin>GraphIndexFactory.createTypes(g)
gremlin>g.commit()
Sample JSON
Sample Graph Database JSON
{
"vertices":[
{"name":"marko","age":29,"_id":1,"_type":"vertex"},
{"name":"vadas","age":27,"_id":2,"_type":"vertex"},
{"name":"lop","lang":"java","_id":3,"_type":"vertex"},
{"name":"josh","age":32,"_id":4,"_type":"vertex"},
{"name":"ripple","lang":"java","_id":5,"_type":"vertex"},
{"name":"peter","age":35,"_id":6,"_type":"vertex"}
],
"edges":[
{"weight":0.5,"_id":7,"_type":"edge","_outV":1,"_inV":2,"_label":"knows"},
{"weight":1.0,"_id":8,"_type":"edge","_outV":1,"_inV":4,"_label":"knows"},
{"weight":0.4,"_id":9,"_type":"edge","_outV":1,"_inV":3,"_label":"created"},
{"weight":1.0,"_id":10,"_type":"edge","_outV":4,"_inV":5,"_label":"created"},
{"weight":0.4,"_id":11,"_type":"edge","_outV":4,"_inV":3,"_label":"created"},
{"weight":0.2,"_id":12,"_type":"edge","_outV":6,"_inV":3,"_label":"created"}
]
}
SQL Commands
gremlin> g = TinkerGraphFactory.createTinkerGraph()
gremlin> g.class
// lets look at all the vertices
gremlin> g.V
// lets look at all the names of those vertices
gremlin> g.V.name
// lets look at all the properties of those vertices
gremlin> g.V.map
// lets look at all the edges
gremlin> g.E
gremlin> v = g.v(1)
gremlin> v.name + ' is ' + v.age + ' years old.'
// lets do a traversal from the '1' marko vertex to the adjacent outgoing vertices.
gremlin> v.out
// lets only take 'knows' labeled edges
gremlin> v.out('knows')
// lets do a traversal from the '1' marko vertex to its outgoing edges.
// in the property graph world, edges are first class citizens that can be traversed to.
gremlin> v.outE
gremlin> g
gremlin> g.V('name','hercules')
gremlin> g.V('name','hercules').out('father')
gremlin> g.V('name','hercules').out('father').out('father')
gremlin> g.V('name','hercules').out('father').out('father').name
gremlin> g.V('name','hercules').name
gremlin> g.V('name','hercules').out('father').name
gremlin> g.V('name','hercules').out('father').out('father').name
// lets only traverse to the head vertices of those edges
// that have a weight that is less than 1.0
gremlin> v.outE.has('weight', T.lt, 1.0f).inV
// what are the weight values on all outgoing edges
gremlin> v.outE.weight
// lets do the same, but with a more general "filter closure"
gremlin> v.outE.filter{it.weight < 1.0}.inV
// lets get the property maps of these vertices.
gremlin> v.outE.filter{it.weight < 1.0}.inV.map
// lets traverse to marko's 30+ year old friends' created projects
gremlin> v.out('knows').filter{it.age > 30}.out('created').name
g.V('name','hercules').out('father').loop(1){true}{true}.name
gremlin> hercules = g.V('name','hercules').next()
gremlin> hercules.out('father','mother').type
gremlin> hercules.out('battled').type
gremlin> hercules.out('battled').map
gremlin> theseus = g.addVertex([name:'theseus',type:'human'])
gremlin> cerberus = g.V('name','cerberus').next()
gremlin> g.addEdge(theseus,cerberus,'battled')
gremlin> hercules.out('battled').in('battled').except([hercules]).name
SQL and Gremlin SQL
SELECT * FROM Categories
g.V('type','category').map()
SELECT CategoryName FROM Categories
g.V('type','category')..categoryName
SELECT CategoryName, Description FROM Categories
g.V('type','category').transform({ [ 'name' : it.getProperty('categoryName') , 'desc' : it.getProperty('description') ] })
SELECT LENGTH(CategoryName) FROM Categories
g.V('type','category').categoryName.transform({it.length()})
SELECT DISTINCT LENGTH(CategoryName) FROM Categories
g.V('type','category').categoryName.transform({it.length()}).dedup()
SELECT MAX(LENGTH(CategoryName)) FROM Categories
g.V('type','category').categoryName.transform({it.length()}).max()
SELECT * FROM Products WHERE UnitsInStock = 0
g.V('type','product').has('unitsInStock', 0).map()
SELECT * FROM Products WHERE NOT(UnitPrice > 10)
g.V('type','product').hasNot('unitPrice', T.gt, 10f).map()
SELECT * FROM Products WHERE UnitPrice >= 5 AND UnitPrice < 10
g.V('type','product').interval('unitPrice', 5f, 10f).map()
SELECT * FROM Products WHERE Discontinued = 1 AND UnitsInStock <> 0
g.V('type','product').has('discontinued', true) \ .hasNot('unitsInStock', 0).map()
SELECT * FROM Products ORDER BY UnitPrice ASC
g.V('type','product').order({ it.a.getProperty('unitPrice') <=> it.b.getProperty('unitPrice') }).map()
SELECT * FROM Products ORDER BY UnitPrice DESC
g.V('type','product').order({ it.b.getProperty('unitPrice') <=> it.a.getProperty('unitPrice') }).map()
SELECT TOP (5) * FROM Products ORDER BY UnitPrice
g.V('type','product').order({ it.b.getProperty('unitPrice') <=> it.a.getProperty('unitPrice') })[0..<5].map()
SELECT Products.* FROM (SELECT ROW_NUMBER() OVER ( ORDER BY UnitPrice) AS [ROW_NUMBER], ProductID FROM Products) AS SortedProducts INNER JOIN Products ON Products.ProductID = SortedProducts.ProductID WHERE [ROW_NUMBER] BETWEEN 6 AND 10 ORDER BY [ROW_NUMBER]
g.V('type','product').order({ it.b.getProperty('unitPrice') <=> it.a.getProperty('unitPrice') })[5..<10].map()
SELECT TOP(1) UnitPrice FROM (SELECT Products.UnitPrice, COUNT(*) AS [Count] FROM Products GROUP BY Products.UnitPrice) AS T ORDER BY [Count] DESC
g.V('type','product').property('unitPrice').groupCount().cap() \ .orderMap(T.decr).next()
SELECT Products.* FROM Products INNER JOIN Categories ON Categories.CategoryID = Products.CategoryID WHERE Categories.CategoryName = 'Beverages'
g.V('categoryName','Beverages').in('inCategory').map()
SELECT Customers.CustomerID, COUNT(Orders.OrderID) FROM Customers LEFT JOIN Orders ON Orders.CustomerID = Customers.CustomerID GROUP BY Customers.CustomerID
g.V('type','customer').transform({ [ 'customerId' : it.getProperty('customerId') , 'orders' : it.out('ordered').count() ] })
SELECT [customer].[CompanyName] FROM [Customers] AS [customer] WHERE [customer].[CompanyName] LIKE 'A%' UNION ALL SELECT [customer].[CompanyName] FROM [Customers] AS [customer] WHERE [customer].[CompanyName] LIKE 'E%'
g.V('type','customer').copySplit( _().filter({ it.getProperty('companyName')[0] == "A" }), _().filter({ it.getProperty('companyName')[0] == "E" }) ).exhaustMerge().companyName
Create,Update and Delete
INSERT INTO [Categories] ([CategoryName], [Description]) VALUES (N'Merchandising', N'Cool products to promote Gremlin')
INSERT INTO [Products] ([ProductName], [CategoryID]) SELECT TOP (1) N'Red Gremlin Jacket', [CategoryID] FROM [Categories] WHERE [CategoryName] = N'Merchandising'
UPDATE [Products] SET [Products].[ProductName] = N'Green Gremlin Jacket' WHERE [Products].[ProductName] = N'Red Gremlin Jacket'
DELETE FROM [Products] WHERE [Products].[ProductName] = N'Green Gremlin Jacket'
DELETE FROM [Categories] WHERE [Categories].[CategoryName] = N'Merchandising'
Gremlin - Create,Update and Delete
c = g.addVertex([ 'type' : 'category'
, 'categoryName' : 'Merchandising'
, 'description' : 'Cool products to promote Gremlin'])
p = g.addVertex([ 'type' : 'product'
, 'productName' : 'Red Gremlin Jacket'])
g.addEdge(p, c, 'inCategory')
g.V().has('productName', 'Red Gremlin Jacket').sideEffect({
it.setProperty('productName', 'Green Gremlin Jacket')
}).iterate()
p.remove()
g.V('categoryName', 'Merchandising').remove()
SELECT * FROM Categories
g.V('type','category').map()
SELECT CategoryName FROM Categories
g.V('type','category')..categoryName
SELECT CategoryName, Description FROM Categories
g.V('type','category').transform({ [ 'name' : it.getProperty('categoryName') , 'desc' : it.getProperty('description') ] })
SELECT LENGTH(CategoryName) FROM Categories
g.V('type','category').categoryName.transform({it.length()})
SELECT DISTINCT LENGTH(CategoryName) FROM Categories
g.V('type','category').categoryName.transform({it.length()}).dedup()
SELECT MAX(LENGTH(CategoryName)) FROM Categories
g.V('type','category').categoryName.transform({it.length()}).max()
SELECT * FROM Products WHERE UnitsInStock = 0
g.V('type','product').has('unitsInStock', 0).map()
SELECT * FROM Products WHERE NOT(UnitPrice > 10)
g.V('type','product').hasNot('unitPrice', T.gt, 10f).map()
SELECT * FROM Products WHERE UnitPrice >= 5 AND UnitPrice < 10
g.V('type','product').interval('unitPrice', 5f, 10f).map()
SELECT * FROM Products WHERE Discontinued = 1 AND UnitsInStock <> 0
g.V('type','product').has('discontinued', true) \ .hasNot('unitsInStock', 0).map()
SELECT * FROM Products ORDER BY UnitPrice ASC
g.V('type','product').order({ it.a.getProperty('unitPrice') <=> it.b.getProperty('unitPrice') }).map()
SELECT * FROM Products ORDER BY UnitPrice DESC
g.V('type','product').order({ it.b.getProperty('unitPrice') <=> it.a.getProperty('unitPrice') }).map()
SELECT TOP (5) * FROM Products ORDER BY UnitPrice
g.V('type','product').order({ it.b.getProperty('unitPrice') <=> it.a.getProperty('unitPrice') })[0..<5].map()
SELECT Products.* FROM (SELECT ROW_NUMBER() OVER ( ORDER BY UnitPrice) AS [ROW_NUMBER], ProductID FROM Products) AS SortedProducts INNER JOIN Products ON Products.ProductID = SortedProducts.ProductID WHERE [ROW_NUMBER] BETWEEN 6 AND 10 ORDER BY [ROW_NUMBER]
g.V('type','product').order({ it.b.getProperty('unitPrice') <=> it.a.getProperty('unitPrice') })[5..<10].map()
SELECT TOP(1) UnitPrice FROM (SELECT Products.UnitPrice, COUNT(*) AS [Count] FROM Products GROUP BY Products.UnitPrice) AS T ORDER BY [Count] DESC
g.V('type','product').property('unitPrice').groupCount().cap() \ .orderMap(T.decr).next()
SELECT Products.* FROM Products INNER JOIN Categories ON Categories.CategoryID = Products.CategoryID WHERE Categories.CategoryName = 'Beverages'
g.V('categoryName','Beverages').in('inCategory').map()
SELECT Customers.CustomerID, COUNT(Orders.OrderID) FROM Customers LEFT JOIN Orders ON Orders.CustomerID = Customers.CustomerID GROUP BY Customers.CustomerID
g.V('type','customer').transform({ [ 'customerId' : it.getProperty('customerId') , 'orders' : it.out('ordered').count() ] })
SELECT [customer].[CompanyName] FROM [Customers] AS [customer] WHERE [customer].[CompanyName] LIKE 'A%' UNION ALL SELECT [customer].[CompanyName] FROM [Customers] AS [customer] WHERE [customer].[CompanyName] LIKE 'E%'
g.V('type','customer').copySplit( _().filter({ it.getProperty('companyName')[0] == "A" }), _().filter({ it.getProperty('companyName')[0] == "E" }) ).exhaustMerge().companyName
Create,Update and Delete
INSERT INTO [Categories] ([CategoryName], [Description]) VALUES (N'Merchandising', N'Cool products to promote Gremlin')
INSERT INTO [Products] ([ProductName], [CategoryID]) SELECT TOP (1) N'Red Gremlin Jacket', [CategoryID] FROM [Categories] WHERE [CategoryName] = N'Merchandising'
UPDATE [Products] SET [Products].[ProductName] = N'Green Gremlin Jacket' WHERE [Products].[ProductName] = N'Red Gremlin Jacket'
DELETE FROM [Products] WHERE [Products].[ProductName] = N'Green Gremlin Jacket'
DELETE FROM [Categories] WHERE [Categories].[CategoryName] = N'Merchandising'
Gremlin - Create,Update and Delete
c = g.addVertex([ 'type' : 'category'
, 'categoryName' : 'Merchandising'
, 'description' : 'Cool products to promote Gremlin'])
p = g.addVertex([ 'type' : 'product'
, 'productName' : 'Red Gremlin Jacket'])
g.addEdge(p, c, 'inCategory')
g.V().has('productName', 'Red Gremlin Jacket').sideEffect({
it.setProperty('productName', 'Green Gremlin Jacket')
}).iterate()
p.remove()
g.V('categoryName', 'Merchandising').remove()
Gremlin Advanced Commands
// load empty in-memory graph
g = new TinkerGraph()
// ==>tinkergraph[vertices:0 edges:0]
// create a user
bob = g.addVertex([
type: 'user',
email: '[email protected]',
name: 'Robert', password: 'asdf'])
// ==>v[0]
// create a post
bob_post_1 = g.addVertex(
[type: 'post',
guid: '21EC2020-3AEA-1069-A2DD-08002B30309D',
title: 'Hello World',
text: 'My first post!',
userDisplayName: 'Bob'])
// ==>v[1]
// create an authorship edge for the post to the user
g.addEdge(bob, bob_post_1, 'postAuthor')
// ==>e[3][0-postAuthor->1]
// get all posts for the user '[email protected]'
g.V.has('type', 'post').as('posts') \
.inE('postAuthor') \
.outV.has('email', '[email protected]') \
.back('posts').map()
// ==>{guid=21EC2020-3AEA-1069-A2DD-08002B30309D, text=My first post!, title=Hello World, userDisplayName=Bob, }
// add a timestamp property to the post
g.V \
.has('guid', bob_post_1.guid) \
.has('type', 'post').sideEffect( \
{it.createTimestamp = 1383726500});
// ==>v[1]
// query to get posts in a specific time range
g.V \
.has('createTimestamp', T.gt, 1383726400) \
.has('createTimestamp', T.lt, 1383726600) \
.map()
// ==>{guid=21EC2020-3AEA-1069-A2DD-08002B30309D, createTimestamp=1383726500, text=My first post!, title=Hello World, userDisplayName=Bob, }
// create a post comment
sally_post_1_comment = g.addVertex([
type: 'comment',
guid: '3F2504E0-4F89-11D3-9A0C-0305E82C3301',
text: 'I like it!',
userDisplayName: 'Sally',
createTimestamp: 1383736500])
// ==>v[3]
// create an edge linking the comment to the post
g.addEdge(
bob_post_1, sally_post_1_comment, 'postComment')
// ==>e[5][1-postComment->3]
// create the user who created the post
sally = g.addVertex([type: 'user', email: '[email protected]', name: 'Sally', password: 'qwerty'])
// ==>v[5]
// link that user as the author of the comment
g.addEdge(sally, sally_post_1_comment, 'commentAuthor')
// ==>e[7][6-commentAuthor->3]
// query to get all comments for the user '[email protected]'
g.V.has('type', 'comment').as('comments') \
.inE('commentAuthor').outV.has( \
'email', sally.email) \
.back('comments').map()
// ==>{guid=3F2504E0-4F89-11D3-9A0C-0305E82C3301, createTimestamp=1383736500, text=I like it!, userDisplayName=Sally, }
// add a vote between a user (sally) and a post
g.addEdge(sally, bob_post_1, 'postVote', [date: 1383726600])
// ==>e[8][5-postVote->1]
// set the number of votes for that post (de-normalization)
g.V.has('type','post').has('guid', bob_post_1.guid).sideEffect({it.votes = 1})
// ==>v[1]
// add another post (note, seeding it with votes)
bob_post_2 = g.addVertex([
type: 'post',
guid: '21EC2020-3AEA-1069-A2DD-08002B30309E',
createTimestamp: 1383726600,
title: 'Learning Gremlin',
text: 'Gremlin is neat.',
userDisplayName: 'Bob',
votes: 2])
// ==>v[9]
// add author edge
g.addEdge(bob, bob_post_2, 'postAuthor')
// get top 5 posts sorted by votes (descending)
g.V('type', 'post').order({it.b.getProperty('votes') <=> it.a.getProperty('votes')}).transform({['title' : it.getProperty('title'), 'votes' : it.getProperty('votes')]})[0..5]
// ==>{title=Learning Gremlin, votes=2}
// ==>{title=Hello World, votes=1}
// add an edge for a vote on a comment
g.addEdge(bob, sally_post_1_comment, 'commentVote', [date: 1383726700])
// ==>e[10][0-commentVote->3]
// set the number of votes on the comment
g.V.has('type','comment').has('guid',sally_post_1_comment.guid).sideEffect({it.votes = 1})
// ==>v[3]
// add another comment
bob_post_1_comment = g.addVertex([
type: 'comment',
guid: '3F2504E0-4F89-11D3-9A0C-0305E82C3302',
text: 'Thanks.',
userDisplayName: 'Bob',
createTimestamp: 1383736500])
// ==>v[10]
// link the comment to the post
g.addEdge(bob_post_1, bob_post_1_comment, 'postComment')
// ==>e[12][1-postComment->10]
// and link the user to the comment
g.addEdge(bob, bob_post_1_comment, 'commentAuthor')
// ==>e[13][0-commentAuthor->10]
// get all of a post's comments sorted by vote (descending)
g.v(1).outE('postComment').inV.order({it.b.getProperty('votes') <=> it.a.getProperty('votes')}).map()
// ==>{guid=3F2504E0-4F89-11D3-9A0C-0305E82C3301, createTimestamp=1383736500, text=I like it!, votes=1, userDisplayName=Sally, }
// ==>{guid=3F2504E0-4F89-11D3-9A0C-0305E82C3302, createTimestamp=1383736500, text=Thanks., userDisplayName=Bob, }
// in order to enforce no duplicate votes, we need some controlling logic
post = bob_post_1
user = bob
// run it once and it will increment the votes count
if (g.v(post.id).inE('postVote').outV.has( \
'email', user.email).count() == 0) {
g.addEdge(user, post, 'postVote',
[date: new Date().getTime()]);
if (post.getProperty('votes') != null){
post.votes++;
}
else {
post.votes = 1;
}
}
// ==>1
g.v(post.id).map
// ==>{guid=21EC2020-3AEA-1069-A2DD-08002B30309D, createTimestamp=1383726500, text=My first post!, title=Hello World, votes=2, userDisplayName=Bob, }
// run it again and it doesn't match anything and doesn't add a vote
if (g.v(post.id).inE('postVote').outV.has( \
'email', user.email).count() == 0) {
g.addEdge(user, post, 'postVote',
[date: new Date().getTime()]);
if (post.getProperty('votes') != null){
post.votes++;
}
else {
post.votes = 1;
}
}
// ==>null
g.v(post.id).map
// ==>{guid=21EC2020-3AEA-1069-A2DD-08002B30309D, createTimestamp=1383726500, text=My first post!, title=Hello World, votes=2, userDisplayName=Bob, }
// load empty in-memory graph
g = new TinkerGraph()
// ==>tinkergraph[vertices:0 edges:0]
// create a user
bob = g.addVertex([
type: 'user',
email: '[email protected]',
name: 'Robert', password: 'asdf'])
// ==>v[0]
// create a post
bob_post_1 = g.addVertex(
[type: 'post',
guid: '21EC2020-3AEA-1069-A2DD-08002B30309D',
title: 'Hello World',
text: 'My first post!',
userDisplayName: 'Bob'])
// ==>v[1]
// create an authorship edge for the post to the user
g.addEdge(bob, bob_post_1, 'postAuthor')
// ==>e[3][0-postAuthor->1]
// get all posts for the user '[email protected]'
g.V.has('type', 'post').as('posts') \
.inE('postAuthor') \
.outV.has('email', '[email protected]') \
.back('posts').map()
// ==>{guid=21EC2020-3AEA-1069-A2DD-08002B30309D, text=My first post!, title=Hello World, userDisplayName=Bob, }
// add a timestamp property to the post
g.V \
.has('guid', bob_post_1.guid) \
.has('type', 'post').sideEffect( \
{it.createTimestamp = 1383726500});
// ==>v[1]
// query to get posts in a specific time range
g.V \
.has('createTimestamp', T.gt, 1383726400) \
.has('createTimestamp', T.lt, 1383726600) \
.map()
// ==>{guid=21EC2020-3AEA-1069-A2DD-08002B30309D, createTimestamp=1383726500, text=My first post!, title=Hello World, userDisplayName=Bob, }
// create a post comment
sally_post_1_comment = g.addVertex([
type: 'comment',
guid: '3F2504E0-4F89-11D3-9A0C-0305E82C3301',
text: 'I like it!',
userDisplayName: 'Sally',
createTimestamp: 1383736500])
// ==>v[3]
// create an edge linking the comment to the post
g.addEdge(
bob_post_1, sally_post_1_comment, 'postComment')
// ==>e[5][1-postComment->3]
// create the user who created the post
sally = g.addVertex([type: 'user', email: '[email protected]', name: 'Sally', password: 'qwerty'])
// ==>v[5]
// link that user as the author of the comment
g.addEdge(sally, sally_post_1_comment, 'commentAuthor')
// ==>e[7][6-commentAuthor->3]
// query to get all comments for the user '[email protected]'
g.V.has('type', 'comment').as('comments') \
.inE('commentAuthor').outV.has( \
'email', sally.email) \
.back('comments').map()
// ==>{guid=3F2504E0-4F89-11D3-9A0C-0305E82C3301, createTimestamp=1383736500, text=I like it!, userDisplayName=Sally, }
// add a vote between a user (sally) and a post
g.addEdge(sally, bob_post_1, 'postVote', [date: 1383726600])
// ==>e[8][5-postVote->1]
// set the number of votes for that post (de-normalization)
g.V.has('type','post').has('guid', bob_post_1.guid).sideEffect({it.votes = 1})
// ==>v[1]
// add another post (note, seeding it with votes)
bob_post_2 = g.addVertex([
type: 'post',
guid: '21EC2020-3AEA-1069-A2DD-08002B30309E',
createTimestamp: 1383726600,
title: 'Learning Gremlin',
text: 'Gremlin is neat.',
userDisplayName: 'Bob',
votes: 2])
// ==>v[9]
// add author edge
g.addEdge(bob, bob_post_2, 'postAuthor')
// get top 5 posts sorted by votes (descending)
g.V('type', 'post').order({it.b.getProperty('votes') <=> it.a.getProperty('votes')}).transform({['title' : it.getProperty('title'), 'votes' : it.getProperty('votes')]})[0..5]
// ==>{title=Learning Gremlin, votes=2}
// ==>{title=Hello World, votes=1}
// add an edge for a vote on a comment
g.addEdge(bob, sally_post_1_comment, 'commentVote', [date: 1383726700])
// ==>e[10][0-commentVote->3]
// set the number of votes on the comment
g.V.has('type','comment').has('guid',sally_post_1_comment.guid).sideEffect({it.votes = 1})
// ==>v[3]
// add another comment
bob_post_1_comment = g.addVertex([
type: 'comment',
guid: '3F2504E0-4F89-11D3-9A0C-0305E82C3302',
text: 'Thanks.',
userDisplayName: 'Bob',
createTimestamp: 1383736500])
// ==>v[10]
// link the comment to the post
g.addEdge(bob_post_1, bob_post_1_comment, 'postComment')
// ==>e[12][1-postComment->10]
// and link the user to the comment
g.addEdge(bob, bob_post_1_comment, 'commentAuthor')
// ==>e[13][0-commentAuthor->10]
// get all of a post's comments sorted by vote (descending)
g.v(1).outE('postComment').inV.order({it.b.getProperty('votes') <=> it.a.getProperty('votes')}).map()
// ==>{guid=3F2504E0-4F89-11D3-9A0C-0305E82C3301, createTimestamp=1383736500, text=I like it!, votes=1, userDisplayName=Sally, }
// ==>{guid=3F2504E0-4F89-11D3-9A0C-0305E82C3302, createTimestamp=1383736500, text=Thanks., userDisplayName=Bob, }
// in order to enforce no duplicate votes, we need some controlling logic
post = bob_post_1
user = bob
// run it once and it will increment the votes count
if (g.v(post.id).inE('postVote').outV.has( \
'email', user.email).count() == 0) {
g.addEdge(user, post, 'postVote',
[date: new Date().getTime()]);
if (post.getProperty('votes') != null){
post.votes++;
}
else {
post.votes = 1;
}
}
// ==>1
g.v(post.id).map
// ==>{guid=21EC2020-3AEA-1069-A2DD-08002B30309D, createTimestamp=1383726500, text=My first post!, title=Hello World, votes=2, userDisplayName=Bob, }
// run it again and it doesn't match anything and doesn't add a vote
if (g.v(post.id).inE('postVote').outV.has( \
'email', user.email).count() == 0) {
g.addEdge(user, post, 'postVote',
[date: new Date().getTime()]);
if (post.getProperty('votes') != null){
post.votes++;
}
else {
post.votes = 1;
}
}
// ==>null
g.v(post.id).map
// ==>{guid=21EC2020-3AEA-1069-A2DD-08002B30309D, createTimestamp=1383726500, text=My first post!, title=Hello World, votes=2, userDisplayName=Bob, }