├── book ├── CoverArt.png ├── make-book.sh └── README.md ├── images ├── README.md ├── BookCover.PNG ├── map-snip.PNG ├── map-snip2.PNG ├── GremlinEasel.png ├── Sample app - 1.png ├── Sample app - 2.png └── GremlinEaselNoText.png ├── .gitignore ├── CONTRIBUTORS ├── demos └── README.md ├── sample-data ├── edges.csv ├── load-air-routes-graph.groovy ├── tinkergraph-empty.properties ├── load-air-routes-graph-34.groovy ├── air-routes.groovy ├── README.md ├── gremlin-server-air-routes.yaml ├── aircraft.csv ├── README-air-routes.txt └── README-air-routes-latest.txt ├── sample-code ├── quick-social.groovy ├── gremlin-client-http.rb ├── sack-example.groovy ├── quick-airmap.groovy ├── README.md ├── basic-client.py ├── bootstrap-console.py ├── janus-composite-2key.groovy ├── route-counts.groovy ├── quick-btree.groovy ├── glv-client.py ├── janus-geoshape.groovy ├── RemoteClient.java ├── RemoteSubgraphStrategy.java ├── CreateGraph.groovy ├── GraphRegion.groovy ├── ShortestRoutes.groovy ├── RemoteAddBatch.java ├── add-aircraft.groovy ├── GraphSearch.java ├── GraphRegion.java ├── RemotePartitionStrategy.java ├── RemoteReadOnlyStrategy.java ├── StdDev.java ├── JanusCassandra.java ├── strategies.py ├── TinkerGraphTest.java ├── TinkerGraphTest.groovy ├── GraphSearch3.java ├── GroupCounts.java ├── GraphSearch2.java ├── GraphFromCSV.java ├── glv-client.js ├── RouteSearch.java ├── CreateGraph.java ├── ListAirports.java ├── Iterate.java ├── glv-client-2.py ├── quick-social2.groovy ├── graph-stats.groovy ├── TestImports.java ├── nested-repeat.groovy ├── RemoteStats.java ├── GraphStats.java ├── janus-cassandra.groovy └── janus-inmemory.groovy ├── NOTICE └── README.md /book/CoverArt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexott/graph/master/book/CoverArt.png -------------------------------------------------------------------------------- /images/README.md: -------------------------------------------------------------------------------- 1 | This folder contains images used by other parts of this project. 2 | -------------------------------------------------------------------------------- /images/BookCover.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexott/graph/master/images/BookCover.PNG -------------------------------------------------------------------------------- /images/map-snip.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexott/graph/master/images/map-snip.PNG -------------------------------------------------------------------------------- /images/map-snip2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexott/graph/master/images/map-snip2.PNG -------------------------------------------------------------------------------- /images/GremlinEasel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexott/graph/master/images/GremlinEasel.png -------------------------------------------------------------------------------- /images/Sample app - 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexott/graph/master/images/Sample app - 1.png -------------------------------------------------------------------------------- /images/Sample app - 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexott/graph/master/images/Sample app - 2.png -------------------------------------------------------------------------------- /images/GremlinEaselNoText.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexott/graph/master/images/GremlinEaselNoText.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | book/Gremlin-Graph-Guide.epub 2 | book/Gremlin-Graph-Guide.html 3 | book/Gremlin-Graph-Guide.mobi 4 | book/Gremlin-Graph-Guide.pdf 5 | book/Gremlin-Graph-Guide.xml 6 | -------------------------------------------------------------------------------- /CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This is the official list of people who have contributed to the book and/or other sample materials contained on this site. 2 | 3 | Kelvin R. Lawrence 4 | Jason Plurad 5 | Adam Holley 6 | Graham Wallis 7 | -------------------------------------------------------------------------------- /demos/README.md: -------------------------------------------------------------------------------- 1 | 2 | ![sample1](https://github.com/krlawrence/graph/raw/master/images//Sample%20app%20-%201.png?raw=true?raw=true, "sample picture") 3 | 4 | 5 | This folder contains larger full demo applications that are not really suitable for the /sample-code folder. 6 | -------------------------------------------------------------------------------- /sample-data/edges.csv: -------------------------------------------------------------------------------- 1 | Tom,knows,Bill 2 | Bill,knows,Allie 3 | Mary,knows,Peter 4 | Mary,knows,Bill 5 | Kelvin,knows,Jack 6 | Jack,knows,Baxter 7 | Baxter,knows,Tom 8 | Robyn,knows,Jack 9 | Alex,likes,Dogs 10 | Jack,likes,Cats 11 | Alex,knows,Mary 12 | Mary,likes,Horses 13 | Mary,likes,Dogs 14 | -------------------------------------------------------------------------------- /sample-code/quick-social.groovy: -------------------------------------------------------------------------------- 1 | graph=TinkerGraph.open() 2 | g=graph.traversal() 3 | 4 | g.addV("A").as("a"). 5 | addV("B").as("b"). 6 | addV("C").as("c"). 7 | addV("D").as("d"). 8 | addV("E").as("e"). 9 | addV("F").as("f"). 10 | addE("knows").from("a").to("b"). 11 | addE("knows").from("a").to("c"). 12 | addE("knows").from("a").to("d"). 13 | addE("knows").from("c").to("d"). 14 | addE("knows").from("c").to("e"). 15 | addE("knows").from("d").to("f") 16 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | ============================================================== 2 | Graph Databeses, Gremlin and TinkerPop - A Tutorial 3 | Copyright 2017 and onwards the author(s), 4 | ============================================================== 5 | 6 | This book and releated sample programs and data was created by Kelvin R. Lawrence and other contributors listed 7 | in the CONTRIBUTORS file 8 | 9 | Any derivative usage of the Book text or other sample materials should include this notice. 10 | 11 | See the LICENSE file for details of the Apache 2 license under which this work is released. 12 | -------------------------------------------------------------------------------- /book/make-book.sh: -------------------------------------------------------------------------------- 1 | echo "*** Producing HTML ***" 2 | asciidoctor Gremlin-Graph-Guide.adoc 3 | echo "*** Producing DOCBOOK ***" 4 | asciidoctor -n -b docbook -d book Gremlin-Graph-Guide.adoc -o krltemp.xml 5 | sed -e s/language=\"groovy\"/language=\"java\"/ krltemp.xml > Gremlin-Graph-Guide.xml 6 | rm krltemp.xml 7 | echo "*** Producing EPUB ***" 8 | pandoc -f docbook -t epub -N --number-sections --chapters --toc --toc-depth=4 Gremlin-Graph-Guide.xml -o Gremlin-Graph-Guide.epub 9 | echo "*** Producing MOBI ***" 10 | ebook-convert Gremlin-Graph-Guide.epub Gremlin-Graph-Guide.mobi 11 | echo "*** Producing PDF ***" 12 | asciidoctor-pdf Gremlin-Graph-Guide.adoc 13 | -------------------------------------------------------------------------------- /sample-data/load-air-routes-graph.groovy: -------------------------------------------------------------------------------- 1 | // You can use this file to load the air-routes graph from the Gremlin Console 2 | // 3 | // To execute use the console command ":load load-air-routes-graph.groovy" 4 | // 5 | 6 | conf = new BaseConfiguration() 7 | conf.setProperty("gremlin.tinkergraph.vertexIdManager","LONG") 8 | conf.setProperty("gremlin.tinkergraph.edgeIdManager","LONG") 9 | conf.setProperty("gremlin.tinkergraph.vertexPropertyIdManager","LONG") 10 | graph = TinkerGraph.open(conf) 11 | 12 | // Change the path below to point to wherever you put the graphml file 13 | graph.io(graphml()).readGraph('/mydata/air-routes.graphml') 14 | 15 | g=graph.traversal() 16 | :set max-iteration 1000 17 | -------------------------------------------------------------------------------- /sample-code/gremlin-client-http.rb: -------------------------------------------------------------------------------- 1 | # Simple example of how you can connect to a Gremlin Server and 2 | # issue queries from a Ruby application. 3 | 4 | require 'net/http' 5 | require 'uri' 6 | require 'json' 7 | 8 | uri = URI.parse("http://localhost:8182") 9 | 10 | request = Net::HTTP::Post.new(uri) 11 | req_options = { use_ssl: uri.scheme == "https", } 12 | 13 | #query = {"gremlin" => "g.V().has('code','AUS')"} 14 | query = {"gremlin" => "g.V().has('code','AUS').out().count()"} 15 | request.body = JSON.dump(query) 16 | 17 | response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http| 18 | http.request(request) 19 | end 20 | 21 | puts "Response code from the server was #{response.code}" 22 | puts response.body 23 | -------------------------------------------------------------------------------- /sample-code/sack-example.groovy: -------------------------------------------------------------------------------- 1 | []; // Display up to 20 routes, with one stop, from Austin to London Heathrow. 2 | []; // The output for each route will include the codes for each airport and the 3 | []; // total distance. The results will be sorted by shortest overall distance. 4 | 5 | println "\n\nShortest routes from AUS to LHR with one stop";[] 6 | println "---------------------------------------------";[] 7 | 8 | routes = g.withSack(0).V(). 9 | has('code','AUS'). 10 | outE().sack(sum).by('dist'). 11 | inV().outE().sack(sum).by('dist'). 12 | inV().has('code','LHR').sack(). 13 | order().by(incr).limit(20). 14 | path().by('code').by('dist').by('code').by('dist').by('code').by().toList();[] 15 | 16 | routes.each(){println "${it[0]} --> ${it[2]} --> ${it[4]} ${it[5]} miles"}[]; 17 | -------------------------------------------------------------------------------- /sample-code/quick-airmap.groovy: -------------------------------------------------------------------------------- 1 | graph=TinkerGraph.open() 2 | g=graph.traversal() 3 | g.addV('airport').property('code','AUS').as('aus'). 4 | addV('airport').property('code','DFW').as('dfw'). 5 | addV('airport').property('code','LAX').as('lax'). 6 | addV('airport').property('code','JFK').as('jfk'). 7 | addV('airport').property('code','ATL').as('atl'). 8 | addE('route').from('aus').to('dfw'). 9 | addE('route').from('aus').to('atl'). 10 | addE('route').from('atl').to('dfw'). 11 | addE('route').from('atl').to('jfk'). 12 | addE('route').from('dfw').to('jfk'). 13 | addE('route').from('dfw').to('lax'). 14 | addE('route').from('lax').to('jfk'). 15 | addE('route').from('lax').to('aus'). 16 | addE('route').from('lax').to('dfw') 17 | 18 | g.V().valueMap(true) 19 | g.V().outE().inV().path().by('code').by() 20 | -------------------------------------------------------------------------------- /sample-code/README.md: -------------------------------------------------------------------------------- 1 | This folder contains code snippets and samples referenced by the book as well as additional sample files. More samples will be added over time. 2 | 3 | 4 | Note that files with a ".groovy" extension but with all lowercase names are intended to be launched from within the Gremlin Console. Files with a ".groovy" extenstion and capitalized names, such as TinkerGraphTest.groovy, are stand alone groovy applications that should be run from outside of the console using the groovy runtime. 5 | 6 | Files with a ".java" extension are stand alone Java applications that need to be compiled and run using a Java JDK. 7 | 8 | Files with a ".py" extension are stand alone Python applications that require the Gremlin Python library to have been installed using PIP or an equivalent method. 9 | 10 | Some of the samples use data from CSV files that can be found in the *'/sample-data'* folder. 11 | -------------------------------------------------------------------------------- /sample-data/tinkergraph-empty.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | gremlin.graph=org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph 18 | gremlin.tinkergraph.vertexIdManager=LONG -------------------------------------------------------------------------------- /sample-data/load-air-routes-graph-34.groovy: -------------------------------------------------------------------------------- 1 | // You can use this file to load the air-routes graph from the Gremlin Console 2 | // 3 | // To execute use the console command ":load load-air-routes-graph-34.groovy" 4 | // 5 | // NOTE: This version is updated from the original load-air-routes-graph.groovy 6 | // to demonstrate the new (now preferred) way to load a GraphML file 7 | // using the g.io() approach introduced in Apache TinkerPop version 3.4. 8 | 9 | conf = new BaseConfiguration() 10 | conf.setProperty("gremlin.tinkergraph.vertexIdManager","LONG") 11 | conf.setProperty("gremlin.tinkergraph.edgeIdManager","LONG") 12 | conf.setProperty("gremlin.tinkergraph.vertexPropertyIdManager","LONG") 13 | graph = TinkerGraph.open(conf) 14 | g=graph.traversal() 15 | 16 | // Change the path below to point to wherever you put the graphml file. 17 | 18 | // We need to explicitly tell Gremlin which reader to use as it does not recognize the GraphML 19 | // file extension. It does recognize XML as an extension so an alternative would be to rename 20 | // the file. 21 | g.io("/mydata/air-routes.graphml"). with(IO.reader,IO.graphml).read().iterate() 22 | 23 | :set max-iteration 1000 24 | -------------------------------------------------------------------------------- /sample-code/basic-client.py: -------------------------------------------------------------------------------- 1 | # basic-client.py 2 | # 3 | # Connect to a Gremlin Server using a client connection. 4 | # 5 | # Note that in this case the Gremlin queries are sent to the server as text strings. 6 | # To see an example of using Gremlin byte code instead see the glv-client.py example. 7 | # 8 | # This example code assumes that the GremlinPython library has been installed using: 9 | # 10 | # pip install gremlinpython 11 | # 12 | 13 | # Import some classes we will need to talk to our graph 14 | from gremlin_python.driver import client 15 | 16 | # Path to our graph (this assumes a locally running Gremlin Server) 17 | # Note how the path is a Web Socket (ws) connection. 18 | client = client.Client('ws://localhost:8182/gremlin','g') 19 | 20 | query = """ 21 | g.V().hasLabel('airport'). 22 | sample(30). 23 | order().by('code'). 24 | local(__.values('code','city').fold()). 25 | toList() 26 | """ 27 | 28 | result = client.submit(query) 29 | future_results = result.all() 30 | results = future_results.result() 31 | 32 | 33 | client.close() 34 | 35 | # Print the results in a tabular form with a row index 36 | for i,c in enumerate(results,1): 37 | print("%3d %4s %s" % (i,c[0],c[1])) 38 | 39 | -------------------------------------------------------------------------------- /sample-code/bootstrap-console.py: -------------------------------------------------------------------------------- 1 | # Configure the environment so the Python Console can connect to 2 | # a Gremlin Server using gremlin-python and a web socket connection. 3 | # 4 | # To use this script start Python using: 5 | # python3 -i bootstrap-console.py 6 | 7 | from gremlin_python import statics 8 | from gremlin_python.structure.graph import Graph 9 | from gremlin_python.process.graph_traversal import __ 10 | from gremlin_python.process.strategies import * 11 | from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection 12 | from gremlin_python.process.traversal import * 13 | import os 14 | 15 | # This script assumes that two environment variables have been defined 16 | # containing the DNS name of the Gremlin Server and the port it is listening on. 17 | # If the environment variables are not found, defaults will be used. 18 | skey = "GREMLIN_SERVER_NAME" 19 | pkey = "GREMLIN_SERVER_PORT" 20 | 21 | server = os.environ[skey] if skey in os.environ else 'localhost' 22 | port = os.environ[pkey] if pkey in os.environ else '8182' 23 | 24 | endpoint = 'ws://' + server + ':' + port + '/gremlin' 25 | print(endpoint) 26 | 27 | graph=Graph() 28 | connection = DriverRemoteConnection(endpoint,'g') 29 | g = graph.traversal().withRemote(connection) 30 | -------------------------------------------------------------------------------- /sample-code/janus-composite-2key.groovy: -------------------------------------------------------------------------------- 1 | // This code is intended to be used within the Gremlin Console while using JanusGraph 2 | // You can invoke it using :load janus-composite-2key.groovy 3 | // 4 | // The code below will create an index that can help queries such as: 5 | // g.V().has('city','London').has('country','CA') 6 | 7 | // Make sure no other transactions are active 8 | graph.tx().rollback() 9 | 10 | // Start a new management transaction 11 | mgmt = graph.openManagement() 12 | 13 | // Find the property keys that we need to index 14 | city = mgmt.getPropertyKey('city') 15 | country = mgmt.getPropertyKey('country') 16 | 17 | // Create a new index and add our keys 18 | index = mgmt.buildIndex('byCityAndCountry', Vertex.class) 19 | index.addKey(country).addKey(city).buildCompositeIndex() 20 | 21 | // Wait for our new index to be ready 22 | mgmt.awaitGraphIndexStatus(graph, 'byCityAndCountry').call() 23 | 24 | // Force a re-index 25 | mgmt = graph.openManagement() 26 | mgmt.updateIndex(mgmt.getGraphIndex("byCityAndCountry"), SchemaAction.REINDEX).get() 27 | mgmt.commit() 28 | 29 | // All done 30 | mgmt.commit() 31 | 32 | // Test out our new index. The profile step will show us which index was used 33 | g.V().has('city','London').has('country','CA').profile() 34 | graph.tx().commit() 35 | -------------------------------------------------------------------------------- /sample-code/route-counts.groovy: -------------------------------------------------------------------------------- 1 | // Explore the distribution of routes in the graph 2 | // This code is intended to be :load-ed and run inside the Gremlin console 3 | 4 | EQ = [0,1,2,3,4,5,10];[] 5 | LTE = [5,10,15,20,25,30,40,50,75,100,150,200,400];[] 6 | GTE = [5,10,15,20,25,30,35,40,50,75,100,125,150,200,250,300];[] 7 | BTW = [0,1,0,2,0,5,0,10,1,2,1,5,1,10,1,25,1,50,1,100,5,10,10,15,10,20,20,25,20,30,25,50, 8 | 30,50,50,100,100,150,100,175,100,200,150,200,175,200,200,250,200,300,250,300];[] 9 | 10 | for (n in EQ) 11 | { 12 | print "EQ $n : " + 13 | g.V().hasLabel('airport').where(out('route').count().is(eq(n))).count().next() + "\n";[] 14 | // printf( "EQ %4d : %4d\n",n, 15 | // g.V().hasLabel('airport').where(out('route').count().is(eq(n))).count().next());[] 16 | 17 | };[] 18 | 19 | for (n in LTE) 20 | { 21 | print "LTE $n : " + 22 | g.V().hasLabel('airport').where(out('route').count().is(lte(n))).count().next() + "\n";[] 23 | 24 | };[] 25 | 26 | for (n in GTE) 27 | { 28 | print "GTE $n : " + 29 | g.V().hasLabel('airport').where(out('route').count().is(gte(n))).count().next() + "\n";[] 30 | 31 | };[] 32 | 33 | for (i=0; i < BTW.size; i+=2) 34 | { 35 | a = BTW[i]; b = BTW[i+1]; 36 | print "BTW $a,$b : " + 37 | g.V().hasLabel('airport').where(out('route').count().is(between(a,b+1))).count().next() + "\n";[] 38 | };[] 39 | -------------------------------------------------------------------------------- /sample-data/air-routes.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | // an init script that returns a Map allows explicit setting of global bindings. 21 | def globals = [:] 22 | 23 | // Generates the classic graph into an "empty" TinkerGraph via LifeCycleHook. 24 | // Note that the name of the key in the "global" map is unimportant. 25 | globals << [hook : [ 26 | onStartUp: { ctx -> 27 | ctx.logger.info("Loading 'air-routes' graph data.") 28 | graph.io(graphml()).readGraph('data/air-routes.graphml') 29 | } 30 | ] as LifeCycleHook] 31 | 32 | // define the default TraversalSource to bind queries to - this one will be named "g". 33 | globals << [g : graph.traversal()] 34 | -------------------------------------------------------------------------------- /sample-code/quick-btree.groovy: -------------------------------------------------------------------------------- 1 | // Builds a small ordered Binary (BST) Tree 2 | 3 | graph=TinkerGraph.open() 4 | g=graph.traversal() 5 | 6 | // Create the vertices and edges. Note how this is done in a single query 7 | // by chaining all of the steps together. 8 | g.addV('root').property('data',9).as('root'). 9 | addV('node').property('data',5).as('b'). 10 | addV('node').property('data',2).as('c'). 11 | addV('node').property('data',11).as('d'). 12 | addV('node').property('data',15).as('e'). 13 | addV('node').property('data',10).as('f'). 14 | addV('node').property('data',1).as('g'). 15 | addV('node').property('data',8).as('h'). 16 | addV('node').property('data',22).as('i'). 17 | addV('node').property('data',16).as('j'). 18 | addE('left').from('root').to('b'). 19 | addE('left').from('b').to('c'). 20 | addE('right').from('root').to('d'). 21 | addE('right').from('d').to('e'). 22 | addE('right').from('e').to('i'). 23 | addE('left').from('i').to('j'). 24 | addE('left').from('d').to('f'). 25 | addE('right').from('b').to('h'). 26 | addE('left').from('c').to('g').iterate() 27 | 28 | 29 | // Find the largest value in the graph (using max would be cheating!) 30 | g.V().hasLabel('root').repeat(out('right')).until(outE('right').count().is(0)).values('data') 31 | 32 | 33 | 34 | // Find the smallest value in the tree (using min would be cheating!) 35 | g.V().hasLabel('root').repeat(out('left')).until(outE('left').count().is(0)).values('data') 36 | 37 | 38 | -------------------------------------------------------------------------------- /sample-code/glv-client.py: -------------------------------------------------------------------------------- 1 | # glv-client.py 2 | # 3 | # Connect to a Gremlin Server using a remote connection and issue some basic queries. 4 | # 5 | # Unlike in the basic-client.py example, the queries sent to the server are sent using 6 | # Gremlin byte code and not sent as text strings. 7 | # 8 | # This example code assumes that the GremlinPython library has been installed using: 9 | # 10 | # pip install gremlinpython 11 | # 12 | 13 | # Import some classes we will need to talk to our graph 14 | from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection 15 | from gremlin_python.structure.graph import Graph 16 | from gremlin_python import statics 17 | from gremlin_python.process.graph_traversal import __ 18 | from gremlin_python.process.strategies import * 19 | from gremlin_python.process.traversal import * 20 | 21 | # Path to our graph (this assumes a locally running Gremlin Server) 22 | # Note how the path is a Web Socket (ws) connection. 23 | endpoint = 'ws://localhost:8182/gremlin' 24 | 25 | # Obtain a graph traversal source using a remote connection 26 | graph=Graph() 27 | connection = DriverRemoteConnection(endpoint,'g') 28 | g = graph.traversal().withRemote(connection) 29 | 30 | # Sample 30 airports and return their code and city values. 31 | # The returned values will be packaged as a list containing 30 small lists. 32 | sample = g.V().hasLabel('airport'). \ 33 | sample(30). \ 34 | order().by('code'). \ 35 | local(__.values('code','city').fold()). \ 36 | toList() 37 | 38 | # Print the results in a tabular form with a row index 39 | # for ctr, c in enumerate(sample,1): 40 | i = 1 41 | for c in sample: 42 | print("%3d %4s %s" % (i,c[0],c[1])) 43 | i += 1 44 | 45 | # All done so close the connetion 46 | connection.close() 47 | -------------------------------------------------------------------------------- /sample-code/janus-geoshape.groovy: -------------------------------------------------------------------------------- 1 | // Script that experiments with the JanusGraph GeoSpatial API 2 | // 3 | // This script is intended to be run from within the Gremlin Console 4 | // attached to a JanusGraph instance with the air-routes data loaded. 5 | 6 | // Create a 100km radius circle with LHR at the center 7 | 8 | lon_lhr = g.V().has('code','LHR').values('lon').next() 9 | lat_lhr = g.V().has('code','LHR').values('lat').next() 10 | 11 | lhr_circ = Geoshape.circle(lat_lhr,lon_lhr,100) 12 | 13 | // Create a 100km radius circle with MAN at the center 14 | 15 | lat_man = g.V().has('code','MAN').values('lat').next() 16 | lon_man = g.V().has('code','MAN').values('lon').next() 17 | 18 | man_circ = Geoshape.circle(lat_man,lon_man,100) 19 | 20 | // Find other airports that within 100km of LHR 21 | g.V().has('airport','region','GB-ENG'). 22 | where(map{a=it.get().value('lat'); 23 | b=it.get().value('lon'); 24 | Geoshape.point(a,b).within(lhr_circ)}.is(true)). 25 | valueMap('code','lat','lon') 26 | 27 | // Do any points in the two LHR and MAN circles intersect? 28 | 29 | lhr_circ.intersect(man_circ) 30 | 31 | // Create a 100km radius circle with LPL at the center 32 | 33 | lat_lpl = g.V().has('code','LPL').values('lat').next() 34 | lon_lpl = g.V().has('code','LPL').values('lon').next() 35 | 36 | lpl_circ = Geoshape.circle(lat_lpl,lon_lpl,100) 37 | 38 | 39 | // Do any points in the MAN and LPL circles intersect 40 | lpl_circ.intersect(man_circ) 41 | 42 | // Define a box around LHR with opposite diagonal corners 43 | // each one degree from LHR. 44 | box = Geoshape.box(lat_lhr-1,lon_lhr-1,lat_lhr+1,lon_lhr+1) 45 | 46 | // Find other airports that within the box 47 | g.V().has('airport','region','GB-ENG'). 48 | where(map{a=it.get().value('lat'); 49 | b=it.get().value('lon'); 50 | Geoshape.point(a,b).within(box)}.is(true)). 51 | valueMap('code','lat','lon') 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /sample-data/README.md: -------------------------------------------------------------------------------- 1 | This folder contains the GraphML file for the air-routes graph and other sample data. The `air-routes` graph is referenced throughout the book. 2 | 3 | ## About the data referenced in the book 4 | 5 | Two versions of the air-routes data set files are provided. The file `air-routes.graphml` contains the full graph containing over 40,000 routes and over 3,300 airports. The file `air-routes-small.graphml` just has routes between 46 airports all located in the US. 6 | All of the examples in the book are based on `air-routes.graphml`. 7 | 8 | The small script called *'load-air-routes-graph.groovy'* can be used to load the graph into a TinkerGraph from within the Gremlin Console. Edit the script before using it to adjust the location of where you put the GraphML file on your system. 9 | 10 | There is also a small Groovy script in the *'/sample-code'* folder called `graph-stats.groovy` that can be run from within the Gremlin console to produce some statistics about the graph similar to those found in the book and in the `README-air-routes.txt` file. 11 | 12 | The *'aircraft.csv'* file is intended to be used with the `add-aircraft.groovy` sample that is located in the *'/sample-code'* folder. 13 | 14 | The `edges.csv` file is intended to be used with the `GraphFromCSV.java` sample that is located in the *'/sample-code'* folder. 15 | 16 | ## Latest data 17 | 18 | The two files `air-routes-latest.graphml` and `air-routes-small-latest.graphml` contain additional routes and airports added since the original version was uploaded. They are provided in case anyone wants to experiment with some more recent data. The latest data set adds 63 additional airports and 5,838 additional routes to the original `air-routes.graphml` data set. 19 | 20 | I have also provided two CSV files to go along withe the GraphML files. Thery are called `air-routes-latest-nodes.csv` and `air-routes-latest-edges.csv`. The CSV files were produced using the open source [GraphML2CSV tool](https://github.com/awslabs/amazon-neptune-tools/tree/master/graphml2csv). You may need to edit the first line (header) of each CSV file depending on your graph database and toolset. 21 | 22 | Please check back periodically to find any additional updates. 23 | -------------------------------------------------------------------------------- /sample-code/RemoteClient.java: -------------------------------------------------------------------------------- 1 | // RemoteClient.java 2 | // 3 | // Simple example of using GremlinServer from a Java client 4 | // 5 | // This example does the following: 6 | // 1. Configure a new Cluster object 7 | // 2. Use that cluster to connect to a Gremlin Server 8 | // 3. Run a few queries against graph 9 | 10 | import org.apache.tinkerpop.gremlin.driver.Cluster; 11 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 12 | import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; 13 | import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection; 14 | import org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0; 15 | import java.util.Map; 16 | import java.util.List; 17 | import java.util.ArrayList; 18 | 19 | public class RemoteClient 20 | { 21 | public static void main( String[] args ) 22 | { 23 | Cluster.Builder builder = Cluster.build(); 24 | builder.addContactPoint("localhost"); 25 | builder.port(8182); 26 | builder.serializer(new GryoMessageSerializerV1d0()); 27 | 28 | Cluster cluster = builder.create(); 29 | 30 | GraphTraversalSource g = 31 | EmptyGraph.instance().traversal(). 32 | withRemote(DriverRemoteConnection.using(cluster)); 33 | 34 | List > vmaps = 35 | g.V().has("airport","region","GB-ENG").limit(10).valueMap().toList(); 36 | 37 | System.out.println("\n\nThe following airports were found\n"); 38 | for (Map m : vmaps) 39 | { 40 | ArrayList code = (ArrayList) m.get("code"); 41 | ArrayList desc = (ArrayList) m.get("desc"); 42 | System.out.println(code.get(0) + " , " + desc.get(0)); 43 | } 44 | 45 | cluster.close(); 46 | } 47 | } 48 | 49 | // The output should look something like this 50 | 51 | /* 52 | The following airports were found 53 | 54 | LEQ , Land's End Airport 55 | LGW , London Gatwick 56 | MAN , Manchester Airport 57 | LHR , London Heathrow 58 | LCY , London City Airport 59 | STN , London Stansted Airport 60 | EMA , East Midlands Airport 61 | LPL , Liverpool John Lennon Airport 62 | LBA , Leeds Bradford Airport 63 | NCL , Newcastle Airport 64 | */ 65 | -------------------------------------------------------------------------------- /sample-code/RemoteSubgraphStrategy.java: -------------------------------------------------------------------------------- 1 | // RemoteSubgraphStrategy.java 2 | // 3 | // Simple example of using GremlinServer from a Java client 4 | // 5 | // This example does the following: 6 | // 1. Configure a new Cluster object 7 | // 2. Use that cluster to connect to a Gremlin Server 8 | // 3. Run a few queries against graph that explore using a SubGraphStrategy 9 | 10 | import org.apache.tinkerpop.gremlin.driver.Cluster; 11 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 12 | import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; 13 | import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection; 14 | import org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0; 15 | import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.MutationListener; 16 | import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy; 17 | import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.EventStrategy; 18 | import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy; 19 | import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.*; 20 | import java.util.Map; 21 | import java.util.List; 22 | import java.util.ArrayList; 23 | 24 | public class RemoteSubgraphStrategy 25 | { 26 | public static void main( String[] args ) 27 | { 28 | Cluster.Builder builder = Cluster.build(); 29 | builder.addContactPoint("localhost"); 30 | builder.port(8182); 31 | builder.serializer(new GryoMessageSerializerV1d0()); 32 | 33 | Cluster cluster = builder.create(); 34 | 35 | GraphTraversalSource g = 36 | EmptyGraph.instance().traversal(). 37 | withRemote(DriverRemoteConnection.using(cluster)); 38 | 39 | // Create a new traversal source object 40 | GraphTraversalSource g2; 41 | 42 | // Create a strategy that filters out anything without 43 | // a region code of 'US-TX' 44 | g2 = g.withStrategies( 45 | SubgraphStrategy.build(). 46 | vertices(has("region","US-TX")).create()); 47 | 48 | // How many airports are there in Texas? 49 | System.out.println(g2.V().count().next()); 50 | 51 | cluster.close(); 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /sample-data/gremlin-server-air-routes.yaml: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | host: localhost 19 | port: 8182 20 | scriptEvaluationTimeout: 30000 21 | graphs: { 22 | graph: conf/tinkergraph-empty.properties} 23 | scriptEngines: { 24 | gremlin-groovy: { 25 | plugins: { org.apache.tinkerpop.gremlin.server.jsr223.GremlinServerGremlinPlugin: {}, 26 | org.apache.tinkerpop.gremlin.tinkergraph.jsr223.TinkerGraphGremlinPlugin: {}, 27 | org.apache.tinkerpop.gremlin.jsr223.ImportGremlinPlugin: {classImports: [java.lang.Math], methodImports: [java.lang.Math#*]}, 28 | org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin: {files: [scripts/air-routes.groovy]}}}} 29 | serializers: 30 | - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }} # application/vnd.gremlin-v3.0+gryo 31 | - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { serializeResultToString: true }} # application/vnd.gremlin-v3.0+gryo-stringd 32 | - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3d0] }} # application/json 33 | metrics: { 34 | slf4jReporter: {enabled: true, interval: 180000}} 35 | strictTransactionManagement: false 36 | idleConnectionTimeout: 0 37 | keepAliveInterval: 0 38 | maxInitialLineLength: 4096 39 | maxHeaderSize: 8192 40 | maxChunkSize: 8192 41 | maxContentLength: 65536 42 | maxAccumulationBufferComponents: 1024 43 | resultIterationBatchSize: 64 44 | -------------------------------------------------------------------------------- /sample-code/CreateGraph.groovy: -------------------------------------------------------------------------------- 1 | // CreateGraph.groovy 2 | // 3 | // Simple example of using TinkerGraph with Groovy (outside the Gremlin console) 4 | // 5 | // This example does the following: 6 | // 1. Create an empty TinkerGraph instance 7 | // 2. Create some nodes and vertices 8 | // 3. Run a few queries against the newly created graph 9 | 10 | // I have highlighted the places where the Gremlin is slightly different from the 11 | // Gremlin we can use in the Gremlin Console. 12 | 13 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 14 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; 15 | import org.apache.tinkerpop.gremlin.process.traversal.Path; 16 | import org.apache.tinkerpop.gremlin.process.traversal.*; 17 | import org.apache.tinkerpop.gremlin.structure.Edge; 18 | import org.apache.tinkerpop.gremlin.structure.Vertex; 19 | import org.apache.tinkerpop.gremlin.structure.io.IoCore; 20 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.*; 21 | import org.apache.tinkerpop.gremlin.structure.T; 22 | import org.apache.tinkerpop.gremlin.util.Gremlin; 23 | import java.io.IOException; 24 | import java.util.List; 25 | import java.util.ArrayList; 26 | import java.util.Map; 27 | import java.util.Set; 28 | 29 | // Create a new (empty) TinkerGrap 30 | TinkerGraph tg = TinkerGraph.open() 31 | 32 | // Create a Traversal source object 33 | GraphTraversalSource g = tg.traversal() 34 | 35 | // Add some nodes and vertices - Note the use of "iterate". 36 | g.addV("airport").property("code","AUS").as("aus"). 37 | addV("airport").property("code","DFW").as("dfw"). 38 | addV("airport").property("code","LAX").as("lax"). 39 | addV("airport").property("code","JFK").as("jfk"). 40 | addV("airport").property("code","ATL").as("atl"). 41 | addE("route").from("aus").to("dfw"). 42 | addE("route").from("aus").to("atl"). 43 | addE("route").from("atl").to("dfw"). 44 | addE("route").from("atl").to("jfk"). 45 | addE("route").from("dfw").to("jfk"). 46 | addE("route").from("dfw").to("lax"). 47 | addE("route").from("lax").to("jfk"). 48 | addE("route").from("lax").to("aus"). 49 | addE("route").from("lax").to("dfw").iterate() 50 | 51 | // Display the vertices created, note we have to use the "T." prefix 52 | // for label and id as they are not stored as regular strings. 53 | 54 | vm = g.V().valueMap(true).toList() 55 | vm.each {println("${it[T.id]} ${it.code[0]} ${it[T.label]}")} 56 | 57 | /* Just for fun! 58 | for (v in vm) 59 | { 60 | v.keySet().each {print "${v[it]} "} 61 | println() 62 | } 63 | */ 64 | 65 | edges = g.E().count().next() 66 | verts = g.V().count().next() 67 | 68 | println "The graph has $verts vertices" 69 | println "The graph has $edges edges" 70 | 71 | 72 | -------------------------------------------------------------------------------- /sample-code/GraphRegion.groovy: -------------------------------------------------------------------------------- 1 | // GraphRegion.groovy 2 | // 3 | // Simple example of using TinkerGraph with Groovy 4 | // 5 | // This example does the following: 6 | // 1. Create an empty TinkerGraph instance 7 | // 2. Load the air routes graph 8 | // 3. Run some tests that show the where...by and multiple V() constructs 9 | 10 | // I have highlighted the places where the Gremlin is slightly different from the 11 | // Gremlin we can use in the Gremlin Console. 12 | 13 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 14 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; 15 | import org.apache.tinkerpop.gremlin.process.traversal.Path; 16 | import org.apache.tinkerpop.gremlin.process.traversal.*; 17 | import org.apache.tinkerpop.gremlin.structure.Edge; 18 | import org.apache.tinkerpop.gremlin.structure.Vertex; 19 | import org.apache.tinkerpop.gremlin.structure.io.IoCore; 20 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.*; 21 | import org.apache.tinkerpop.gremlin.structure.T; 22 | import org.apache.tinkerpop.gremlin.util.Gremlin; 23 | import java.io.IOException; 24 | 25 | class RegionTest 26 | { 27 | private TinkerGraph tg 28 | private GraphTraversalSource g 29 | 30 | // Try to create a new graph and load the specified GraphML file 31 | def loadGraph(name) 32 | { 33 | tg = TinkerGraph.open() 34 | 35 | try 36 | { 37 | tg.io(IoCore.graphml()).readGraph(name) 38 | } 39 | catch( IOException e ) 40 | { 41 | println("GraphStats - GraphML file not found") 42 | return false 43 | } 44 | g = tg.traversal() 45 | return true 46 | } 47 | 48 | // Find all airports in the region of the specified airport 49 | // 50 | // Note that when used from an application we have to prefix eq with a "P." 51 | // Also select has to be prefixed by "__." 52 | def findByRegion(iata) 53 | { 54 | println("\nRegion code lookup for " + iata ) 55 | 56 | def list = 57 | g.V().has("code",iata).values("region").as("r"). 58 | V().hasLabel("airport").as("a").values("region"). 59 | where(P.eq("r")).by(). 60 | local(__.select("a").values("city","code","region").fold()).toList() 61 | 62 | list.each {println it} 63 | } 64 | } 65 | 66 | // If you want to check your Gremlin version, uncomment the next line 67 | println("Gremlin version is: ${Gremlin.version()}"); 68 | 69 | rt = new RegionTest() 70 | 71 | if (rt.loadGraph("air-routes.graphml")) 72 | { 73 | rt.findByRegion("NCE") // Nice 74 | rt.findByRegion("DEN") // Denver 75 | rt.findByRegion("GVA") // Geneva 76 | rt.findByRegion("NGS") // Nagasaki 77 | rt.findByRegion("CAN") // Guangzhou 78 | } 79 | -------------------------------------------------------------------------------- /sample-code/ShortestRoutes.groovy: -------------------------------------------------------------------------------- 1 | // ShortestRoutes.groovy 2 | // 3 | // Simple example of using TinkerGraph with Groovy 4 | // 5 | // This example does the following: 6 | // 1. Create an empty TinkerGraph instance 7 | // 2. Load the air routes graph 8 | // 3. Run some tests that how to calculate shortest routes using a sack. 9 | 10 | // I have highlighted the places where the Gremlin is slightly different from the 11 | // Gremlin we can use in the Gremlin Console. 12 | 13 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 14 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; 15 | import org.apache.tinkerpop.gremlin.process.traversal.Path; 16 | import org.apache.tinkerpop.gremlin.process.traversal.*; 17 | import org.apache.tinkerpop.gremlin.structure.Edge; 18 | import org.apache.tinkerpop.gremlin.structure.Vertex; 19 | import org.apache.tinkerpop.gremlin.structure.io.IoCore; 20 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.*; 21 | import org.apache.tinkerpop.gremlin.structure.T; 22 | import org.apache.tinkerpop.gremlin.util.Gremlin; 23 | import java.io.IOException; 24 | 25 | class Routes 26 | { 27 | private TinkerGraph tg 28 | private GraphTraversalSource g 29 | 30 | // Try to create a new graph and load the specified GraphML file 31 | def loadGraph(name) 32 | { 33 | tg = TinkerGraph.open() 34 | 35 | try 36 | { 37 | tg.io(IoCore.graphml()).readGraph(name) 38 | } 39 | catch( IOException e ) 40 | { 41 | println("GraphStats - GraphML file not found") 42 | return false 43 | } 44 | g = tg.traversal() 45 | return true 46 | } 47 | 48 | // Find the (maximum of 10) shortest routes with one stop 49 | // between the two specified airports. 50 | // 51 | // Note the use of the prefixes Operator and Order) 52 | def shortestRouteOneStop(from,to) 53 | { 54 | def list = 55 | g.withSack(0).V().has('code',from). 56 | outE().sack(Operator.sum).by('dist'). 57 | inV().outE().sack(Operator.sum).by('dist'). 58 | inV().has('code',to).sack(). 59 | order().by(Order.incr).limit(10). 60 | path().by('code').by('dist').by('code').by('dist').by('code').by(). 61 | toList() 62 | 63 | list.each {printf( "%3s %4d %3s %4d %3s %4d\n", 64 | it[0],it[1],it[2],it[3],it[4],it[5])} 65 | } 66 | 67 | } 68 | 69 | // If you want to check your Gremlin version, uncomment the next line 70 | //println("Gremlin version is: ${Gremlin.version()}"); 71 | 72 | rt = new Routes() 73 | 74 | if (rt.loadGraph("air-routes.graphml")) 75 | { 76 | rt.shortestRouteOneStop("AUS","LHR") 77 | println() 78 | rt.shortestRouteOneStop("CDG","BNE") 79 | println() 80 | rt.shortestRouteOneStop("HKG","SJC") 81 | } 82 | -------------------------------------------------------------------------------- /sample-code/RemoteAddBatch.java: -------------------------------------------------------------------------------- 1 | // RemoteAddBatch.java 2 | // 3 | // Simple example of using GremlinServer from a Java client 4 | // 5 | // This example does the following: 6 | // 1. Configure a new Cluster object 7 | // 2. Use that cluster to connect to a Gremlin Server 8 | // 3. Create a GraphTraversal and incrementally add to it before 9 | // sending the traversal to the server for execution. 10 | 11 | import org.apache.tinkerpop.gremlin.driver.Cluster; 12 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 13 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; 14 | import org.apache.tinkerpop.gremlin.process.traversal.P; 15 | import org.apache.tinkerpop.gremlin.structure.T; 16 | import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; 17 | import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection; 18 | import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0; 19 | 20 | import java.util.Map; 21 | import java.util.List; 22 | import java.util.ArrayList; 23 | 24 | public class RemoteAddBatch 25 | { 26 | public static void main( String[] args ) 27 | { 28 | Cluster.Builder builder = Cluster.build(); 29 | builder.addContactPoint("localhost"); 30 | builder.port(8182); 31 | builder.serializer(new GraphSONMessageSerializerV3d0()); 32 | 33 | Cluster cluster = builder.create(); 34 | 35 | GraphTraversalSource g = 36 | EmptyGraph.instance().traversal(). 37 | withRemote(DriverRemoteConnection.using(cluster)); 38 | 39 | // Instead of building the traversal all in one go, the example 40 | // below shows how to create a traversal and incrementally add to it. 41 | // This is extremely useful when building up batches of steps programmatically 42 | // to send to a server as a single query. 43 | GraphTraversal t = g.addV("person"); 44 | t.property(T.id,1000000).property("name","Stew").property("age",23); 45 | t.addV("person"); 46 | t.property(T.id,1000001).property("name","Stevie").property("age",28); 47 | t.addV("person"); 48 | t.property(T.id,1000002).property("name","Patrick").property("age",18); 49 | t.addV("person"); 50 | t.property(T.id,1000003).property("name","Patricia").property("age",41); 51 | 52 | // Now execute the traversal. 53 | t.iterate(); 54 | 55 | // Make sure the vertices and properties were successfully added to the graph. 56 | List> results = 57 | g.V().hasLabel("person").valueMap(true).toList(); 58 | 59 | for(Map m : results) 60 | { 61 | System.out.println(m); 62 | //m.forEach((k,v) -> System.out.println(k + ":" + v)); 63 | //System.out.println(); 64 | } 65 | 66 | // Delete the vertices we just created as this is only a test. 67 | g.V(1000000,1000001,1000002,1000003).drop().iterate(); 68 | 69 | // All done, close the connection. 70 | cluster.close(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /sample-code/add-aircraft.groovy: -------------------------------------------------------------------------------- 1 | ;[] // add-aircraft.groovy 2 | ;[] // 3 | ;[] // This script is intended to be run within the Gremlin Console. 4 | ;[] // 5 | ;[] // This script will try to read data from a CSV file (aircraft.csv) and add some 6 | ;[] // aircraft information to the graph. 7 | ;[] // 8 | ;[] // It is assumed, but not essential, that the air-routes graph data 9 | ;[] // has already been loaded. The first line of the CSV file contains the column 10 | ;[] // headers. This will be used as the names of the property keys. A vertex will be 11 | ;[] // created for each aircraft type found in the data. The script will 12 | ;[] // also create a vertex for each aircraft manufacturer found in the data and 13 | ;[] // create edges that connect the manufacturers to the planes they make. The main 14 | ;[] // Purpose of this script is to show a CSV file being used and to show queries 15 | ;[] // that also create vertices and edges without prior knowledge of exactly what 16 | ;[] // data will be loaded from the CSV data. 17 | ;[] // 18 | ;[] // The ";[]" notation is used to prevent unwanted output from the Gremlin 19 | ;[] // Console. 20 | 21 | ;[] // Open the CSV file setup a reader 22 | fis = new FileInputStream("aircraft.csv");[] 23 | 24 | reader = new BufferedReader(new InputStreamReader(fis));[] 25 | 26 | ;[] // The first line of the file is assumed to be the column headers that 27 | ;[] // will be used as property keys. 28 | pkeys = reader.readLine().toLowerCase().split(",");[] 29 | 30 | ;[] // Create a vertex for each aircraft type found in the CSV data 31 | reader.eachLine{line -> def values = line.split(","); 32 | g.addV("aircraft"). 33 | property(pkeys[0],values[0]). 34 | property(pkeys[1],values[1]). 35 | property(pkeys[2],values[2]). 36 | property(pkeys[3],values[3]).iterate() } 37 | 38 | ;[] // Display the vertices that were just created 39 | newverts = g.V().hasLabel("aircraft").valueMap(true).toList();[] 40 | newverts.each{println it};[] 41 | 42 | ;[] // Create a "maker" vertex for each unique plane maker we find 43 | g.V().hasLabel("aircraft").values("maker").dedup().as('a'). 44 | addV('maker').property('name',select('a')).iterate();[] 45 | 46 | ;[] // Verify that our new vertices look good 47 | newverts = g.V().hasLabel("maker").valueMap(true).toList();[] 48 | newverts.each{println it};[] 49 | 50 | ;[] // Add edges between the maker and the planes they make 51 | g.V().hasLabel('maker').as('m'). 52 | V().hasLabel('aircraft').as('a'). 53 | where('m',eq('a')).by('name').by('maker'). 54 | addE('makes').from('m').to('a').iterate();[] 55 | 56 | ;[] // Verify that our new edges look good 57 | g.V().hasLabel('maker'). 58 | order().by('name'). 59 | outE('makes').inV(). 60 | path().by('name').by(label).by('desc') 61 | 62 | ;[] // Review how the graph demographic looks now 63 | g.V().groupCount().by(label) 64 | g.E().groupCount().by(label) 65 | -------------------------------------------------------------------------------- /sample-data/aircraft.csv: -------------------------------------------------------------------------------- 1 | ICAO,IATA,MAKER,DESC 2 | A318,318,Airbus,A318 3 | A319,319,Airbus,A319 4 | A320,320,Airbus,A320 5 | A321,321,Airbus,A321 6 | A332,332,Airbus,A330-200 7 | A333,333,Airbus,A330-300 8 | A338,338,Airbus,A330-800neo 9 | A339,339,Airbus,A330-900neo 10 | A342,342,Airbus,A340-200 11 | A343,343,Airbus,A340-300 12 | A345,345,Airbus,A340-500 13 | A346,346,Airbus,A340-600 14 | A359,359,Airbus,A350-900 15 | A35K,351,Airbus,A350-1000 16 | B37M,7M7,Boeing,737 MAX 7 17 | B38M,7M8,Boeing,737 MAX 8 18 | B39M,7M9,Boeing,737 MAX 9 19 | B3JM,7MJ,Boeing,737 MAX 10 20 | B712,717,Boeing,717 21 | B721,721,Boeing,727-100 22 | B722,722,Boeing,727-200 23 | B732,732,Boeing,737-200 24 | B733,733,Boeing,737-300 25 | B734,734,Boeing,737-400 26 | B735,735,Boeing,737-500 27 | B736,736,Boeing,737-600 28 | B737,73G,Boeing,737-700 29 | B738,738,Boeing,737-800 30 | B739,739,Boeing,737-900 31 | B741,741,Boeing,747-100 32 | B742,742,Boeing,747-200 33 | B743,743,Boeing,747-300 34 | B744,744,Boeing,747-400 35 | B748,748,Boeing,747-8 36 | B752,752,Boeing,757-200 37 | B753,753,Boeing,757-300 38 | B762,762,Boeing,767-200 39 | B763,763,Boeing,767-300 40 | B764,764,Boeing,767-400 41 | B772,772,Boeing,777-200 42 | B77L,77L,Boeing,777-200LR 43 | B773,773,Boeing,777-300 44 | B77W,77W,Boeing,777-300ER 45 | B788,788,Boeing,787-8 46 | B789,789,Boeing,787-9 47 | B78X,78J,Boeing,787-10 48 | E120,EM2,Embraer,EMB 120 Brasilia 49 | E135,ER3,Embraer,RJ135 50 | E135,ERD,Embraer,RJ140 51 | E145,ER4,Embraer,RJ145 52 | E170,E70,Embraer,170 53 | E190,E90,Embraer,190 54 | E195,E95,Embraer,195 55 | E75L,E75,Embraer,175 (long wing) 56 | E75S,E75,Embraer,175 (short wing) 57 | DC91,D91,McDonnell Douglas,DC-9-10 58 | DC92,D92,McDonnell Douglas,DC-9-20 59 | DC93,D93,McDonnell Douglas,DC-9-30 60 | MD11,M11,McDonnell Douglas,MD-11 61 | MD81,M81,McDonnell Douglas,MD-81 62 | MD82,M82,McDonnell Douglas,MD-82 63 | MD83,M83,McDonnell Douglas,MD-83 64 | MD87,M87,McDonnell Douglas,MD-87 65 | MD88,M88,McDonnell Douglas,MD-88 66 | MD90,M90,McDonnell Douglas,MD-90 67 | DH8A,DH1,De Havilland Canada,DHC-8-100 Dash 8 / 8Q 68 | DH8B,DH2,De Havilland Canada,DHC-8-200 Dash 8 / 8Q 69 | DH8C,DH3,De Havilland Canada,DHC-8-300 Dash 8 / 8Q 70 | DH8D,DH4,De Havilland Canada,DHC-8-400 Dash 8Q 71 | DHC2,DHP,De Havilland Canada,DHC-2 Beaver 72 | DHC3,DHL,De Havilland Canada,DHC-3 Otter 73 | DHC4,DHC,De Havilland Canada,DHC-4 Caribou 74 | DHC5,DHC,De Havilland Canada,DHC-5 Buffalo 75 | DHC6,DHT,De Havilland Canada,DHC-6 Twin Otter 76 | DHC7,DH7,De Havilland Canada,DHC-7 Dash 7 77 | BCS1,CS1,Bombardier,CS100 78 | BCS3,CS3,Bombardier,CS300 79 | RJ1H,AR1,Avro,RJ100 80 | RJ70,AR7,Avro,RJ70 81 | RJ85,AR8,Avro,RJ85 82 | B461,141,BAe,146-100 83 | B462,142,BAe,146-200 84 | B463,143,BAe,146-300 85 | CRJ1,CR1,Canadair,Regional Jet 100 86 | CRJX,CRK,Canadair,Regional Jet 1000 87 | CRJ2,CR2,Canadair,Regional Jet 200 88 | CRJ7,CR7,Canadair,Regional Jet 700 89 | CRJ9,CR9,Canadair,Regional Jet 900 90 | F100,100,Fokker,F100 91 | F70,F70,Fokker,F70 92 | IL96,I93,Ilyushin,IL96 93 | -------------------------------------------------------------------------------- /sample-code/GraphSearch.java: -------------------------------------------------------------------------------- 1 | // GraphSearch.java 2 | // 3 | // Simple example of using TinkerGraph with Java 4 | // 5 | // This example does the following: 6 | // 1. Create an empty TinkerGraph instance 7 | // 2. Load the air-routes graph 8 | // 3. Perform some searches against the graph 9 | 10 | // I have highlighted any places where the Gremlin is slightly different from the 11 | // Gremlin we can use in the Gremlin Console. 12 | 13 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 14 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; 15 | import org.apache.tinkerpop.gremlin.process.traversal.Path; 16 | import org.apache.tinkerpop.gremlin.process.traversal.*; 17 | import org.apache.tinkerpop.gremlin.structure.Edge; 18 | import org.apache.tinkerpop.gremlin.structure.Vertex; 19 | import org.apache.tinkerpop.gremlin.structure.io.IoCore; 20 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.*; 21 | import org.apache.tinkerpop.gremlin.structure.T; 22 | import java.io.IOException; 23 | import java.util.List; 24 | import java.util.ArrayList; 25 | import java.util.Map; 26 | import java.util.Set; 27 | 28 | public class GraphSearch 29 | { 30 | private TinkerGraph tg; 31 | private GraphTraversalSource g; 32 | 33 | // Try to create a new graph and load the specified GraphML file 34 | public boolean loadGraph(String name) 35 | { 36 | tg = TinkerGraph.open() ; 37 | 38 | try 39 | { 40 | tg.io(IoCore.graphml()).readGraph(name); 41 | } 42 | catch( IOException e ) 43 | { 44 | System.out.println("GraphStats - Air routes GraphML file not found"); 45 | return false; 46 | } 47 | g = tg.traversal(); 48 | return true; 49 | } 50 | 51 | // Return the distance between two airports. 52 | // Input parameters are the airport IATA codes. 53 | public Integer getDistance(String from, String to) 54 | { 55 | Integer d = (Integer) 56 | g.V().has("code",from).outE().as("edge").inV().has("code",to). 57 | select("edge").by("dist").next(); 58 | 59 | return(d); 60 | } 61 | 62 | // Run some tests 63 | public static void main(String[] args) 64 | { 65 | GraphSearch gs = new GraphSearch(); 66 | boolean loaded = gs.loadGraph("air-routes.graphml"); 67 | 68 | if (loaded) 69 | { 70 | String[][] places = {{"AUS","LHR"},{"JFK","PHX"},{"SYD","LAX"}, 71 | {"PEK","HND"},{"HKG","MEL"},{"MIA","SFO"}, 72 | {"MNL","BKK"},{"DXB","DFW"},{"DOH","JNB"}, 73 | {"NRT","FRA"},{"AMS","GVA"},{"CDG","SIN"}}; 74 | 75 | System.out.println("\n\nFrom To Distance"); 76 | System.out.println("====================="); 77 | 78 | Integer dist; 79 | 80 | for (String[] p : places) 81 | { 82 | dist = gs.getDistance(p[0],p[1]); 83 | System.out.format("%4s %4s %5d\n",p[0],p[1],dist) ; 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /sample-code/GraphRegion.java: -------------------------------------------------------------------------------- 1 | // GraphRegion.java 2 | // 3 | // Simple example of using TinkerGraph with Java 4 | // 5 | // This example does the following: 6 | // 1. Create an empty TinkerGraph instance 7 | // 2. Load the air routes graph 8 | // 3. Run some tests that show the where...by and multiple V() constructs 9 | 10 | // I have highlighted the places where the Gremlin is slightly different from the 11 | // Gremlin we can use in the Gremlin Console. 12 | 13 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 14 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; 15 | import org.apache.tinkerpop.gremlin.process.traversal.Path; 16 | import org.apache.tinkerpop.gremlin.process.traversal.*; 17 | import org.apache.tinkerpop.gremlin.structure.Edge; 18 | import org.apache.tinkerpop.gremlin.structure.Vertex; 19 | import org.apache.tinkerpop.gremlin.structure.io.IoCore; 20 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.*; 21 | import org.apache.tinkerpop.gremlin.structure.T; 22 | import org.apache.tinkerpop.gremlin.util.Gremlin; 23 | import java.io.IOException; 24 | import java.util.List; 25 | import java.util.ArrayList; 26 | import java.util.Map; 27 | import java.util.HashMap; 28 | import java.util.Set; 29 | 30 | public class GraphRegion 31 | { 32 | private TinkerGraph tg; 33 | private GraphTraversalSource g; 34 | 35 | // Try to create a new graph and load the specified GraphML file 36 | public boolean loadGraph(String name) 37 | { 38 | tg = TinkerGraph.open() ; 39 | 40 | try 41 | { 42 | tg.io(IoCore.graphml()).readGraph(name); 43 | } 44 | catch( IOException e ) 45 | { 46 | System.out.println("GraphStats - GraphML file not found"); 47 | return false; 48 | } 49 | g = tg.traversal(); 50 | return true; 51 | } 52 | 53 | // Find all airports in the region of the specified airport 54 | // 55 | // Note that when used from Java we have to prefix eq with a "P." 56 | // Also select has to be prefixed by "__." 57 | public void findByRegion(String iata) 58 | { 59 | System.out.println("\nRegion code lookup for " + iata ); 60 | 61 | List> list = 62 | g.V().has("code",iata).values("region").as("r"). 63 | V().hasLabel("airport").as("a").values("region"). 64 | where(P.eq("r")).by(). 65 | local(__.select("a").values("city","code","region").fold()).toList(); 66 | 67 | for(List t : list) 68 | { 69 | System.out.println(t); 70 | } 71 | } 72 | 73 | public static void main(String[] args) 74 | { 75 | // If you want to check your Gremlin version, uncomment the next line 76 | //System.out.println("Gremlin version is: " + Gremlin.version()); 77 | 78 | GraphRegion gr = new GraphRegion() ; 79 | 80 | if (gr.loadGraph("air-routes.graphml")) 81 | { 82 | gr.findByRegion("NCE"); // Nice 83 | gr.findByRegion("DEN"); // Denver 84 | gr.findByRegion("GVA"); // Geneva 85 | gr.findByRegion("NGS"); // Nagasaki 86 | gr.findByRegion("CAN"); // Guangzhou 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /sample-code/RemotePartitionStrategy.java: -------------------------------------------------------------------------------- 1 | // RemotePartitionStrategy.java 2 | // 3 | // Simple example of using GremlinServer from a Java client 4 | // 5 | // This example does the following: 6 | // 1. Configure a new Cluster object 7 | // 2. Use that cluster to connect to a Gremlin Server 8 | // 3. Run a few queries against graph that explore using a PartitionStrategy 9 | 10 | import org.apache.tinkerpop.gremlin.driver.Cluster; 11 | import org.apache.tinkerpop.gremlin.structure.Edge; 12 | import org.apache.tinkerpop.gremlin.structure.Vertex; 13 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 14 | import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; 15 | import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection; 16 | import org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0; 17 | import org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0; 18 | import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.PartitionStrategy; 19 | import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.*; 20 | import java.util.Map; 21 | import java.util.List; 22 | import java.util.ArrayList; 23 | 24 | public class RemotePartitionStrategy 25 | { 26 | public static void main( String[] args ) 27 | { 28 | String host = "localhost"; 29 | Cluster.Builder builder = Cluster.build(); 30 | builder.addContactPoint(host); 31 | builder.port(8182); 32 | builder.serializer(new GryoMessageSerializerV3d0()); 33 | 34 | Cluster cluster = builder.create(); 35 | 36 | // Create a new traversal source object 37 | GraphTraversalSource g = 38 | EmptyGraph.instance().traversal(). 39 | withRemote(DriverRemoteConnection.using(cluster)); 40 | 41 | // Make sure our connection is working. 42 | System.out.println(g.V().count().next()); 43 | 44 | PartitionStrategy strategyP1 = 45 | PartitionStrategy.build(). 46 | partitionKey("partition"). 47 | writePartition("p1"). 48 | readPartitions("p1").create(); 49 | 50 | // Test adding elements one by one 51 | GraphTraversalSource g2 = g.withStrategies(strategyP1); 52 | Object v1 = g2.addV("person").id().next(); 53 | Object v2 = g2.addV("person").id().next(); 54 | Object e1 = g2.addE("knows").from(V(v1)).to(V(v2)).id().next(); 55 | 56 | // Test adding all the elements in one query. 57 | g2.addV("person").as("a").addV("person").addE("knows").to("a").iterate(); 58 | 59 | // Add a vertex without a partition key 60 | g.addV("person").id().iterate(); 61 | 62 | // Should be 4, not 5. 63 | System.out.println(g.V().has("partition","p1").count().next()); 64 | 65 | // Inspect the elements we created. 66 | List> verts = g2.V().hasLabel("person").valueMap(true).toList(); 67 | verts.forEach((m) -> System.out.println(m)); 68 | 69 | List> edges = g2.E().hasLabel("knows").valueMap(true).toList(); 70 | edges.forEach((m) -> System.out.println(m)); 71 | 72 | // All done, close the connection. 73 | cluster.close(); 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /sample-code/RemoteReadOnlyStrategy.java: -------------------------------------------------------------------------------- 1 | // RemoteReadOnlyStrategy.java 2 | // 3 | // Simple example of using GremlinServer from a Java client 4 | // 5 | // This example does the following: 6 | // 1. Configure a new Cluster object 7 | // 2. Use that cluster to connect to a Gremlin Server 8 | // 3. Run a few queries against graph that explore using a ReadOnlyStrategy 9 | // 10 | // With a ReadOnly strategy in place, any attempt to mutate the graph should 11 | // cause an exception to be thrown. 12 | 13 | import org.apache.tinkerpop.gremlin.driver.Cluster; 14 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 15 | import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; 16 | import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection; 17 | import org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0; 18 | import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy; 19 | import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.*; 20 | import java.util.Map; 21 | import java.util.List; 22 | import java.util.ArrayList; 23 | 24 | public class RemoteReadOnlyStrategy 25 | { 26 | public static void main( String[] args ) 27 | { 28 | String host = "localhost"; 29 | Cluster.Builder builder = Cluster.build(); 30 | builder.addContactPoint(host); 31 | builder.port(8182); 32 | builder.serializer(new GryoMessageSerializerV3d0()); 33 | 34 | Cluster cluster = builder.create(); 35 | 36 | GraphTraversalSource g = 37 | EmptyGraph.instance().traversal(). 38 | withRemote(DriverRemoteConnection.using(cluster)); 39 | 40 | // Create a new traversal source object 41 | GraphTraversalSource g2; 42 | 43 | // Any attempt to mutate the graph using 'g2' should now 44 | // cause an exception to be thrown but using 'g' should 45 | // continue to allow mutations. 46 | g2 = g.withStrategies(ReadOnlyStrategy.instance()); 47 | 48 | Object v1 = g.addV("ROTest").property("p1",1).next(); 49 | Object v2 = g.addV("ROTest").property("p1",1).next(); 50 | g.addE("ROEdgeTest").from(V(v2)).to(V(v1)).iterate(); 51 | 52 | try 53 | { 54 | g2.addV("shouldfail").iterate(); 55 | } 56 | catch(Exception e) 57 | { 58 | System.out.println("Unable to add a vertex"); 59 | } 60 | try 61 | { 62 | g2.V().hasLabel("ROTest").property("p1",2).iterate(); 63 | } 64 | catch(Exception e) 65 | { 66 | System.out.println("Unable update a property"); 67 | } 68 | try 69 | { 70 | g2.V().hasLabel("ROTest").drop().iterate(); 71 | } 72 | catch(Exception e) 73 | { 74 | System.out.println("Unable drop a vertex"); 75 | } 76 | try 77 | { 78 | g2.V().addE("ROEdgeTest2").from(V(v1)).to(V(v2)).iterate(); 79 | } 80 | catch(Exception e) 81 | { 82 | System.out.println("Unable to add an edge"); 83 | } 84 | try 85 | { 86 | g2.E().hasLabel("ROEdgeTest").drop().iterate(); 87 | } 88 | catch(Exception e) 89 | { 90 | System.out.println("Unable to drop an edge"); 91 | } 92 | // Clean up before we exit. 93 | g.V().hasLabel("ROTest").drop().iterate(); 94 | g.E().hasLabel("ROTest").drop().iterate(); 95 | cluster.close(); 96 | } 97 | } 98 | 99 | -------------------------------------------------------------------------------- /sample-code/StdDev.java: -------------------------------------------------------------------------------- 1 | // StdDev.java 2 | // 3 | // Simple example of using TinkerGraph with Java 4 | // 5 | // This example does the following: 6 | // 1. Creates an empty TinkerGraph instance 7 | // 2. Loads the air-routes.graphml file 8 | // 3. Runs a few experiments that use the math step. 9 | // 10 | // NOTE: This code requires a TinkerPop version of at least 3.3.1 11 | // 12 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 13 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; 14 | import org.apache.tinkerpop.gremlin.process.traversal.Path; 15 | import org.apache.tinkerpop.gremlin.process.traversal.*; 16 | import org.apache.tinkerpop.gremlin.structure.Edge; 17 | import org.apache.tinkerpop.gremlin.structure.Vertex; 18 | import org.apache.tinkerpop.gremlin.structure.io.IoCore; 19 | import org.apache.tinkerpop.gremlin.structure.T; 20 | import org.apache.tinkerpop.gremlin.structure.Column; 21 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.*; 22 | import org.apache.tinkerpop.gremlin.util.Gremlin; 23 | import java.io.IOException; 24 | import java.util.Map; 25 | import java.util.HashMap; 26 | 27 | public class StdDev 28 | { 29 | private TinkerGraph tg; 30 | private GraphTraversalSource g; 31 | 32 | // ------------------------------------------------------------- 33 | // Try to create a new graph and load the specified GraphML file 34 | // ------------------------------------------------------------- 35 | public boolean loadGraph(String name) 36 | { 37 | tg = TinkerGraph.open() ; 38 | 39 | System.out.println("Loading " + name); 40 | long t1 = System.currentTimeMillis(); 41 | System.out.println(t1); 42 | 43 | try 44 | { 45 | tg.io(IoCore.graphml()).readGraph(name); 46 | } 47 | catch( IOException e ) 48 | { 49 | System.out.println("ERROR - GraphML file not found or invalid."); 50 | return false; 51 | } 52 | 53 | long t2 = System.currentTimeMillis(); 54 | System.out.println(t2 + "(" + (t2-t1) +")"); 55 | System.out.println("Graph loaded\n"); 56 | g = tg.traversal(); 57 | return true; 58 | } 59 | 60 | // --------------------- 61 | // Run a few experiments 62 | // --------------------- 63 | public void runTests() 64 | { 65 | // Calculate the average number of runways per airport. 66 | Number mean=g.V().hasLabel("airport").values("runways").mean().next(); 67 | 68 | // Calculate number of airports in the graph. 69 | Long count = g.V().hasLabel("airport").count().next(); 70 | 71 | // Calculate the standard deviation from the mean for runways 72 | Double stddev = 73 | g.withSideEffect("m",mean). 74 | withSideEffect("c",count). 75 | V().hasLabel("airport").values("runways"). 76 | math("(_ - m)^2").sum().math("_ / c").math("sqrt(_)").next(); 77 | 78 | System.out.println("Number of airports : " + count); 79 | System.out.println("Average number of runways : " + mean); 80 | System.out.println("Standard deviation : " + stddev); 81 | } 82 | 83 | // --------------------------------------- 84 | // Try to load a graph and run a few tests 85 | // --------------------------------------- 86 | public static void main(String[] args) 87 | { 88 | StdDev sd = new StdDev(); 89 | 90 | if ( sd.loadGraph("air-routes.graphml")) 91 | { 92 | sd.runTests(); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /sample-code/JanusCassandra.java: -------------------------------------------------------------------------------- 1 | // JanusCassandra.java 2 | // 3 | // Simple example of using JanusGraph with Java (outside the Gremlin console) 4 | // 5 | // This example does the following: 6 | // 1. Connects to an existing JanusGraph/Cassandra instance 7 | // 2. Runs a few queries against graph 8 | 9 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 10 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; 11 | import org.apache.tinkerpop.gremlin.process.traversal.Path; 12 | import org.apache.tinkerpop.gremlin.process.traversal.*; 13 | import org.apache.tinkerpop.gremlin.structure.Edge; 14 | import org.apache.tinkerpop.gremlin.structure.Vertex; 15 | import org.apache.tinkerpop.gremlin.structure.io.IoCore; 16 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.*; 17 | import org.janusgraph.core.*; 18 | import java.io.IOException; 19 | import java.util.List; 20 | import java.util.ArrayList; 21 | import java.util.Map; 22 | import java.util.Set; 23 | 24 | public class JanusCassandra 25 | { 26 | public static void main(String[] args) 27 | { 28 | System.out.println(" --------------------------"); 29 | System.out.println(" Connecting to Graph "); 30 | System.out.println(" --------------------------"); 31 | //JanusGraph jg = JanusGraphFactory.open("janusgraph-cassandra.properties") ; 32 | JanusGraph jg = JanusGraphFactory.open("janusgraph-cql.properties") ; 33 | 34 | GraphTraversalSource g = jg.traversal(); 35 | 36 | System.out.println(" --------------------------"); 37 | System.out.println(" Sending queries "); 38 | System.out.println(" --------------------------"); 39 | Map aus = g.V().has("code","AUS").valueMap().next(); 40 | System.out.println(aus); 41 | 42 | List city = (List)(aus.get("city")); 43 | System.out.println("The AUS airport is in " + city.get(0)); 44 | 45 | aus.forEach( (k,v) -> System.out.println(k + ": "+ v)); 46 | 47 | Long n = g.V().has("code","DFW").out().count().next(); 48 | System.out.println("There are " + n + " routes from Dallas"); 49 | 50 | List fromAus = (g.V().has("code","AUS").out().values("code").toList()); 51 | System.out.println(fromAus); 52 | 53 | List lhrToUsa = g.V().has("code","LHR").outE().inV(). 54 | has("country","US").limit(5). 55 | path().by("code").by("dist").toList(); 56 | 57 | lhrToUsa.forEach((k) -> System.out.println(k)); 58 | 59 | ArrayList routes = new ArrayList<>(); 60 | g.V().has("code","SAT").out().path().by("icao").fill(routes); 61 | System.out.println(routes); 62 | 63 | System.out.println("*******************"); 64 | Vertex v = g.V().has("code","FRA").next(); 65 | System.out.println(v.keys()); 66 | Set s = v.keys(); 67 | for (String k : s) 68 | { 69 | System.out.println( k + "\t: " + v.property(k).value()); 70 | } 71 | System.out.println("*******************"); 72 | 73 | List eng = g.V().has("code","AUS").repeat(__.out()).times(2). 74 | has("region","GB-ENG").dedup().values("code").toList(); 75 | 76 | System.out.println(eng); 77 | 78 | System.out.println(" --------------------------"); 79 | System.out.println(" Shutting down "); 80 | System.out.println(" --------------------------"); 81 | jg.tx().commit(); 82 | jg.close(); 83 | System.exit(0); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /sample-code/strategies.py: -------------------------------------------------------------------------------- 1 | # strategies.py 2 | # 3 | # Connect to a Gremlin Server using a remote connection and issue some basic queries. 4 | # Note the way that certain Gremlin steps that share the same name as Python reserved words 5 | # or method names are handled by postfixing an underscore after them as in the case of "as_". 6 | # 7 | # Unlike in the basic-client.py example, the queries sent to the server are sent using 8 | # Gremlin byte code and not sent as text strings. 9 | # 10 | # This example code assumes that the GremlinPython library has been installed using: 11 | # 12 | # pip install gremlinpython 13 | # 14 | # This sample experiments with the following strategies: 15 | # SubgraphStrategy 16 | # ReadOnlyStrategy 17 | # PartitionStrategy 18 | # 19 | # Import some classes we will need to talk to our graph 20 | from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection 21 | from gremlin_python.structure.graph import Graph 22 | from gremlin_python import statics 23 | from gremlin_python.process.graph_traversal import __ 24 | from gremlin_python.process.strategies import * 25 | from gremlin_python.process.traversal import * 26 | import sys 27 | 28 | # Path to our graph (this assumes a locally running Gremlin Server) 29 | # Note how the path is a Web Socket (ws) connection. 30 | endpoint = 'ws://localhost:8182/gremlin' 31 | 32 | # Obtain a graph traversal source using a remote connection 33 | graph=Graph() 34 | connection = DriverRemoteConnection(endpoint,'g') 35 | g = graph.traversal().withRemote(connection) 36 | 37 | # Helper method to pretty print some headings. 38 | def heading(s): 39 | print("\n{}".format(s)) 40 | for i in range(len(s)): 41 | print("-",end="") 42 | print("") 43 | 44 | # Create a SubgraphStrategy that only picks up airports in Texas 45 | # and routes between them. 46 | heading('SubgraphStrategy - just Texas airports') 47 | strategy = SubgraphStrategy(vertices=__.has("region","US-TX"), edges=__.hasLabel('route')) 48 | g2 = g.withStrategies(strategy) 49 | verts = g2.V().count().next() 50 | edges = g2.E().count().next() 51 | 52 | routes = g2.V().\ 53 | order().\ 54 | by(__.out().count()).\ 55 | group().\ 56 | by('code').\ 57 | by(__.out().count()).\ 58 | order(Scope.local).by(Column.values).\ 59 | next() 60 | 61 | print("Found {} airports and {} routes.".format(verts,edges)) 62 | for k,v in routes.items(): 63 | print(k,v) 64 | 65 | 66 | # Create a ReadOnlyStrategy - any attempt to add or change an element 67 | # using this traversal source should cause an exception to be thrown. 68 | heading('ReadOnlyStrateggy') 69 | g3 = g.withStrategies(ReadOnlyStrategy()) 70 | try: 71 | g3.addV('should_fail').property('p1',1).iterate() 72 | except: 73 | print('Not allowed to add a new vertex') 74 | print(sys.exc_info()[0]) 75 | print(sys.exc_info()[1]) 76 | 77 | 78 | # Create a PartitionStrategy that adds a property called "partition" 79 | # to all new elements that are created. 80 | heading('PartitionStrateggy') 81 | g4 = g.withStrategies(PartitionStrategy( 82 | partition_key="partition", 83 | write_partition="a", 84 | read_partitions=["a"])) 85 | 86 | 87 | try: 88 | x = g4.addV('test').property("p1",1).toList() 89 | except: 90 | print("Exception trying to add a vertex") 91 | print(sys.exc_info()[0]) 92 | print(sys.exc_info()[1]) 93 | finally: 94 | heading('Closing connection') 95 | connection.close() 96 | 97 | -------------------------------------------------------------------------------- /sample-code/TinkerGraphTest.java: -------------------------------------------------------------------------------- 1 | // TinkereGraphTest.java 2 | // 3 | // Simple example of using TinkerGraph with Java 4 | // 5 | // This example does the following: 6 | // 1. Creates an empty TinkerGraph instance 7 | // 2. Loads the air-routes.graphml file 8 | // 3. Runs a few queries against the newly created graph . 9 | // 10 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 11 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; 12 | import org.apache.tinkerpop.gremlin.process.traversal.Path; 13 | import org.apache.tinkerpop.gremlin.process.traversal.*; 14 | import org.apache.tinkerpop.gremlin.structure.Edge; 15 | import org.apache.tinkerpop.gremlin.structure.Vertex; 16 | import org.apache.tinkerpop.gremlin.structure.io.IoCore; 17 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.*; 18 | import java.io.IOException; 19 | import java.util.List; 20 | import java.util.ArrayList; 21 | import java.util.Map; 22 | import java.util.Set; 23 | 24 | public class TinkerGraphTest 25 | { 26 | public static void main(String[] args) 27 | { 28 | // If you want to check your gremlin version, uncomment the following line 29 | //System.out.println("Gremlin version is " + Gremlin.version()); 30 | 31 | // Create a new TinkerGraph instance and try to load the air-routes data 32 | 33 | TinkerGraph tg = TinkerGraph.open() ; 34 | 35 | try 36 | { 37 | tg.io(IoCore.graphml()).readGraph("air-routes.graphml"); 38 | } 39 | catch( IOException e ) 40 | { 41 | System.out.println("TinkerGraphTest - Air routes GraphML file not found"); 42 | System.exit(0); 43 | } 44 | 45 | // Create our graph traversal source 46 | 47 | GraphTraversalSource g = tg.traversal(); 48 | 49 | // Run a few simple tests 50 | 51 | // Get a value map for the properties associated with the AUS airport 52 | Map aus = g.V().has("code","AUS").valueMap().next(); 53 | System.out.println(aus); 54 | 55 | // Which city is the AUS airport located in? 56 | List city = (List)(aus.get("city")); 57 | System.out.println("\nThe AUS airport is in " + city.get(0) + "\n"); 58 | 59 | // Display the property keys and values 60 | aus.forEach( (k,v) -> System.out.println(k + ": "+ v)); 61 | 62 | // How many routes are there from DFW? 63 | Long n = g.V().has("code","DFW").out().count().next(); 64 | System.out.println("\nThere are " + n + " routes from Dallas\n"); 65 | 66 | // Where do the routes go to? 67 | List fromDfw = g.V().has("code","DFW").out().values("code").toList(); 68 | System.out.println(fromDfw); 69 | 70 | // Where in the USA can I fly to from LHR? 71 | List lhrToUsa = g.V().has("code","LHR").outE().inV(). 72 | has("country","US"). 73 | path().by("code").by("dist").toList(); 74 | 75 | System.out.println("\nRoutes from LHR to the USA\n"); 76 | 77 | lhrToUsa.forEach((k) -> System.out.println(k)); 78 | 79 | // If I start in AUS, and only stop once on the way, where in 80 | // England can I get to? Note the use of "__." to prefix the 81 | // call to the out() step. 82 | List eng = 83 | g.V().has("code","AUS").repeat(__.out()).times(2). 84 | has("region","GB-ENG").values("city").dedup().toList(); 85 | 86 | System.out.println("\nPlaces in England I can get to with one stop from AUS.\n"); 87 | eng.forEach( (p) -> System.out.print(p + " ")); 88 | System.out.println(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /sample-code/TinkerGraphTest.groovy: -------------------------------------------------------------------------------- 1 | // TinkerGraphTest.groovy 2 | // 3 | // Simple example of using TinkerGraph with Groovy 4 | // 5 | // This example does the following: 6 | // 1. Create a TinkerGraph instance 7 | // 2. Load the air routes graph 8 | // 3. Run a few queries against the graph. 9 | 10 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 11 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; 12 | import org.apache.tinkerpop.gremlin.process.traversal.Path; 13 | import org.apache.tinkerpop.gremlin.process.traversal.*; 14 | import org.apache.tinkerpop.gremlin.structure.Edge; 15 | import org.apache.tinkerpop.gremlin.structure.Vertex; 16 | import org.apache.tinkerpop.gremlin.structure.io.IoCore; 17 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.*; 18 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph; 19 | import org.apache.tinkerpop.gremlin.util.Gremlin; 20 | import java.io.IOException; 21 | 22 | // Query the version of Gremlin/TinkerPop that we are using 23 | println "Gremlin version is ${Gremlin.version()}" 24 | 25 | // Create a new, empty, TinkerGraph instance 26 | def tg = TinkerGraph.open() 27 | 28 | // Try to load the air routes data 29 | println "Loading the air-routes graph...\n" 30 | 31 | try 32 | { 33 | tg.io(IoCore.graphml()).readGraph("air-routes.graphml"); 34 | } 35 | catch (IOException e) 36 | { 37 | println "Could not load the graph file" 38 | System.exit(1); 39 | } 40 | 41 | // Get our graph traversal source object 42 | def g = tg.traversal() 43 | 44 | // Now let's run some queries 45 | 46 | // Retrieve the properties associated with the AUS airport 47 | def aus = g.V().has('code','AUS').valueMap().next() 48 | 49 | println aus 50 | 51 | // What city is AUS located in? 52 | def city = aus['city'] 53 | println "\nThe AUS airport is in ${city[0]}\n" 54 | 55 | aus.each {println "${it.key} : ${it.value[0]}"} 56 | 57 | // How many outgoing routes are there from DFW? 58 | def n = g.V().has("code","DFW").out().count().next() 59 | println "\nThere are ${n} routes from Dallas" 60 | 61 | // Where can I fly to from DFW? 62 | def fromDfw = g.V().has("code","DFW").out().values("code").toList() 63 | println "\nHere are the places you can fly to from DFW\n" 64 | println fromDfw 65 | 66 | // Where in the USA can I fly to from LHR? 67 | def lhrToUsa = g.V().has("code","LHR").outE().inV(). 68 | has("country","US").limit(10). 69 | path().by("code").by("dist").toList() 70 | 71 | println "\nFrom LHR to airports in the USA (only 10 shown)\n" 72 | //println lhrToUsa 73 | lhrToUsa.each {println it} 74 | 75 | // Selected routes from San Antonio 76 | def routes = [] 77 | g.V().has("code","SAT").out().path().by("icao").limit(10).fill(routes); 78 | println "\nRoutes from San Antonio (only 10 shown)\n" 79 | routes.each {println it} 80 | 81 | // Retrieve the vertex representing the FRA airport. 82 | // Then display the keys and values contained in the vertex. 83 | def v = g.V().has('code','FRA').next() 84 | println "\nKeys found in the FRA vertex" 85 | println v.keys() 86 | println "\nValues found in the FRA vertex" 87 | v.values().each{println it} 88 | 89 | // If I start in AUS, and only stop at most once on the way, where in 90 | // England can I get to? Note the use of "__." to prefix the 91 | // call to the out() step. 92 | 93 | def eng = g.V().has("code","AUS").repeat(__.out()).emit().times(2). 94 | has("region","GB-ENG").dedup().values("code").toList(); 95 | 96 | println "\nAirports in England reachable with no more than one stop from AUS" 97 | println "\n${eng}\n" 98 | 99 | 100 | -------------------------------------------------------------------------------- /sample-code/GraphSearch3.java: -------------------------------------------------------------------------------- 1 | // GraphSearch3.java 2 | // 3 | // Simple example of using TinkerGraph with Java 4 | // This code builds upon the examples shown in GraphSearch and GraphSearch2 5 | // and adds the findLongestRoute method to the class. 6 | // 7 | // This example does the following: 8 | // 1. Create an empty TinkerGraph instance 9 | // 2. Load the air-routes graph 10 | // 3. Perform some searches against the graph 11 | 12 | // I have highlighted any places where the Gremlin is slightly different from the 13 | // Gremlin we can use in the Gremlin Console. 14 | 15 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 16 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; 17 | import org.apache.tinkerpop.gremlin.process.traversal.Path; 18 | import org.apache.tinkerpop.gremlin.process.traversal.*; 19 | import org.apache.tinkerpop.gremlin.structure.Edge; 20 | import org.apache.tinkerpop.gremlin.structure.Vertex; 21 | import org.apache.tinkerpop.gremlin.structure.io.IoCore; 22 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.*; 23 | import org.apache.tinkerpop.gremlin.structure.T; 24 | import org.apache.tinkerpop.gremlin.util.Gremlin; 25 | import java.io.IOException; 26 | import java.util.List; 27 | import java.util.ArrayList; 28 | import java.util.Map; 29 | import java.util.Set; 30 | 31 | public class GraphSearch3 32 | { 33 | private TinkerGraph tg; 34 | private GraphTraversalSource g; 35 | 36 | // Try to create a new graph and load the specified GraphML file 37 | public boolean loadGraph(String name) 38 | { 39 | tg = TinkerGraph.open() ; 40 | 41 | try 42 | { 43 | tg.io(IoCore.graphml()).readGraph(name); 44 | } 45 | catch( IOException e ) 46 | { 47 | System.out.println("GraphStats - GraphML file not found"); 48 | return false; 49 | } 50 | g = tg.traversal(); 51 | return true; 52 | } 53 | 54 | // Return the distance between two airports. 55 | // Input parameters are the airport IATA codes. 56 | // If no route exists between the specified airports return -1 57 | public Integer getDistance(String from, String to) 58 | { 59 | List result = 60 | g.V().has("code",from).outE().as("edge").inV().has("code",to). 61 | select("edge").by("dist").toList(); 62 | 63 | Integer d = ((result.isEmpty()) ? -1 : (Integer)(result.get(0))); 64 | 65 | return(d); 66 | } 67 | 68 | // Find the distance of the longest route in the graph 69 | // Returns a map with keys of from,distance and to 70 | public Map findLongestRoute() 71 | { 72 | // Note how we need to prefix certain things that we would not have to 73 | // when using the Gremlin console with "__." and "Order." 74 | Map result = 75 | g.V().hasLabel("airport").outE("route"). 76 | order().by("dist",Order.decr).limit(1). 77 | project("from","distance","to"). 78 | by(__.inV().values("code")).by("dist").by(__.outV().values("code")).next(); 79 | 80 | return(result); 81 | } 82 | 83 | 84 | // Run some tests 85 | public static void main(String[] args) 86 | { 87 | // If you want to check your Gremlin version, uncomment the next line 88 | //System.out.println("Gremlin version is: " + Gremlin.version()); 89 | 90 | GraphSearch3 gs = new GraphSearch3(); 91 | boolean loaded = gs.loadGraph("air-routes.graphml"); 92 | 93 | if (loaded) 94 | { 95 | Map longest = gs.findLongestRoute() ; 96 | String s = "The longest route in the graph is between " + longest.get("from"); 97 | s += " and " + longest.get("to") + " covering a distance of "; 98 | s += longest.get("distance") + " miles." ; 99 | 100 | System.out.println(s); 101 | 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /sample-code/GroupCounts.java: -------------------------------------------------------------------------------- 1 | // GroupCounts.java 2 | // 3 | // Simple example of using TinkerGraph with Java 4 | // 5 | // This example does the following: 6 | // 1. Creates an empty TinkerGraph instance 7 | // 2. Loads the air-routes.graphml file 8 | // 3. Runs a few queries that use the groupCount step 9 | // against the newly created graph. 10 | // 11 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 12 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; 13 | import org.apache.tinkerpop.gremlin.process.traversal.Path; 14 | import org.apache.tinkerpop.gremlin.process.traversal.*; 15 | import org.apache.tinkerpop.gremlin.structure.Edge; 16 | import org.apache.tinkerpop.gremlin.structure.Vertex; 17 | import org.apache.tinkerpop.gremlin.structure.io.IoCore; 18 | import org.apache.tinkerpop.gremlin.structure.T; 19 | import org.apache.tinkerpop.gremlin.structure.Column; 20 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.*; 21 | import org.apache.tinkerpop.gremlin.util.Gremlin; 22 | import java.io.IOException; 23 | import java.util.Map; 24 | import java.util.HashMap; 25 | 26 | public class GroupCounts 27 | { 28 | private TinkerGraph tg; 29 | private GraphTraversalSource g; 30 | 31 | // ------------------------------------------------------------- 32 | // Try to create a new graph and load the specified GraphML file 33 | // ------------------------------------------------------------- 34 | public boolean loadGraph(String name) 35 | { 36 | tg = TinkerGraph.open() ; 37 | 38 | System.out.println("Loading " + name); 39 | long t1 = System.currentTimeMillis(); 40 | System.out.println(t1); 41 | 42 | try 43 | { 44 | tg.io(IoCore.graphml()).readGraph(name); 45 | } 46 | catch( IOException e ) 47 | { 48 | System.out.println("ERROR - GraphML file not found or invalid."); 49 | return false; 50 | } 51 | 52 | // Calculate how long it took to load the graph 53 | long t2 = System.currentTimeMillis(); 54 | System.out.println(t2 + "(" + (t2-t1) +")"); 55 | System.out.println("Graph loaded\n"); 56 | g = tg.traversal(); 57 | return true; 58 | } 59 | 60 | // --------------------- 61 | // Run a few experiments 62 | // --------------------- 63 | public void runTests() 64 | { 65 | // Count vertices and edges grouped by labels. 66 | // This example shows how a HashMap can be passed to a query 67 | // using a side effect. 68 | final Map map = new HashMap<>(); 69 | g.withSideEffect("m", map).V().groupCount("m").by(T.label).iterate(); 70 | g.withSideEffect("m", map).E().groupCount("m").by(T.label).iterate(); 71 | map.forEach((k,v)->System.out.format("%10s :%5d\n",k,v)); 72 | 73 | // Count airports in the UK and Ireland by region also 74 | // using a side effect. 75 | System.out.println(); 76 | final Map eumap = new HashMap<>(); 77 | g.withSideEffect("m", eumap). 78 | V().has("code",P.within("UK","IE")).out(). 79 | groupCount("m").by("region").iterate(); 80 | 81 | eumap.forEach((k,v)->System.out.format("%10s :%3d\n",k,v)); 82 | 83 | // Count airports in the US by region and sort the results 84 | // by descending counts. This time the map is populated 85 | // using the query result rather than as a side effect. 86 | System.out.println(); 87 | Map usmap = new HashMap<>(); 88 | usmap = g.V().has("code","US").out(). 89 | groupCount().by("region").order(Scope.local). 90 | by(Column.values, Order.decr).next(); 91 | 92 | usmap.forEach((k,v)->System.out.format("%10s :%3d\n",k,v)); 93 | 94 | } 95 | 96 | // --------------------------------------- 97 | // Try to load a graph and run a few tests 98 | // --------------------------------------- 99 | public static void main(String[] args) 100 | { 101 | GroupCounts grp = new GroupCounts(); 102 | 103 | if ( grp.loadGraph("air-routes.graphml")) 104 | { 105 | grp.runTests(); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /sample-code/GraphSearch2.java: -------------------------------------------------------------------------------- 1 | // GraphSearch2.java 2 | // 3 | // Simple example of using TinkerGraph with Java 4 | // 5 | // This example does the following: 6 | // 1. Create an empty TinkerGraph instance 7 | // 2. Load the air-routes graph 8 | // 3. Perform some searches against the graph 9 | // 4. Handle error conditions where graph elements are not found 10 | 11 | // I have highlighted any places where the Gremlin is slightly different from the 12 | // Gremlin we can use in the Gremlin Console. 13 | 14 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 15 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; 16 | import org.apache.tinkerpop.gremlin.process.traversal.Path; 17 | import org.apache.tinkerpop.gremlin.process.traversal.*; 18 | import org.apache.tinkerpop.gremlin.structure.Edge; 19 | import org.apache.tinkerpop.gremlin.structure.Vertex; 20 | import org.apache.tinkerpop.gremlin.structure.io.IoCore; 21 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.*; 22 | import org.apache.tinkerpop.gremlin.structure.T; 23 | import org.apache.tinkerpop.gremlin.util.Gremlin; 24 | import java.io.IOException; 25 | import java.util.List; 26 | import java.util.ArrayList; 27 | import java.util.Map; 28 | import java.util.Set; 29 | 30 | public class GraphSearch2 31 | { 32 | private TinkerGraph tg; 33 | private GraphTraversalSource g; 34 | 35 | // Try to create a new graph and load the specified GraphML file 36 | public boolean loadGraph(String name) 37 | { 38 | tg = TinkerGraph.open() ; 39 | 40 | try 41 | { 42 | tg.io(IoCore.graphml()).readGraph(name); 43 | } 44 | catch( IOException e ) 45 | { 46 | System.out.println("GraphStats - GraphML file not found"); 47 | return false; 48 | } 49 | g = tg.traversal(); 50 | return true; 51 | } 52 | 53 | // Return the distance between two airports. 54 | // Input parameters are the airport IATA codes. 55 | // If no route exists between the specified airports return -1 56 | public Integer getDistance(String from, String to) 57 | { 58 | //The coalesce step avoids an exception when no result is found 59 | //Integer d = (Integer) 60 | // g.V().has("code",from).outE().as("edge").inV().has("code",to). 61 | // select("edge").by("dist").fold(). 62 | // coalesce(__.unfold(),__.constant(-1)).next(); 63 | 64 | // Using toList() is another way to check for no result 65 | List result = 66 | g.V().has("code",from).outE().as("edge").inV().has("code",to). 67 | select("edge").by("dist").toList(); 68 | 69 | Integer d = ((result.isEmpty()) ? -1 : (Integer)(result.get(0))); 70 | 71 | /* 72 | if (result.isEmpty()) 73 | { 74 | System.out.println("No results were found"); 75 | } 76 | else 77 | { 78 | System.out.println("The distance is " + result.get(0)); 79 | } 80 | */ 81 | return(d); 82 | } 83 | 84 | // Run some tests 85 | public static void main(String[] args) 86 | { 87 | // If you want to check your Gremlin version, uncomment the next line 88 | //System.out.println("Gremlin version is: " + Gremlin.version()); 89 | 90 | GraphSearch2 gs = new GraphSearch2(); 91 | boolean loaded = gs.loadGraph("air-routes.graphml"); 92 | 93 | // The data below contains a non existent route between XXX and YYY to test the 94 | // error handling when a query returns no data. 95 | if (loaded) 96 | { 97 | String[][] places = {{"AUS","LHR"},{"JFK","PHX"},{"SYD","LAX"}, 98 | {"PEK","HND"},{"HKG","MEL"},{"MIA","SFO"}, 99 | {"MNL","BKK"},{"XXX","YYY"},{"DOH","JNB"}, 100 | {"NRT","FRA"},{"AMS","GVA"},{"CDG","SIN"}}; 101 | 102 | System.out.println("\n\nFrom To Distance"); 103 | System.out.println("====================="); 104 | 105 | Integer dist; 106 | 107 | for (String[] p : places) 108 | { 109 | dist = gs.getDistance(p[0],p[1]); 110 | System.out.format("%4s %4s %5d\n",p[0],p[1],dist) ; 111 | } 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /sample-code/GraphFromCSV.java: -------------------------------------------------------------------------------- 1 | 2 | // GraphFromCSV.java 3 | // 4 | // Simple example of using TinkerGraph with Java 5 | // 6 | // This example does the following: 7 | // 1. Create an empty TinkerGraph instance 8 | // 2. Reads simple edge lists from a CSV file 9 | // 3. Creates a graph - avoiding creating any duplicate vertices or edges 10 | // 4. Displays information about the graph that was created 11 | 12 | // The csv file is expected to be of the form: 13 | // Kelvin,knows,Jack 14 | // Jack,knows,Baxter 15 | // 16 | // Each name in the CSV file is assumed to be unique for this simple examplei, so for 17 | // example only one node will be created for Jack in the example above. 18 | 19 | // I have highlighted any places where the Gremlin is slightly different from the 20 | // Gremlin we can use in the Gremlin Console. 21 | 22 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 23 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; 24 | import org.apache.tinkerpop.gremlin.process.traversal.Path; 25 | import org.apache.tinkerpop.gremlin.process.traversal.*; 26 | import org.apache.tinkerpop.gremlin.structure.Edge; 27 | import org.apache.tinkerpop.gremlin.structure.Vertex; 28 | import org.apache.tinkerpop.gremlin.structure.io.IoCore; 29 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.*; 30 | import org.apache.tinkerpop.gremlin.structure.T; 31 | import org.apache.tinkerpop.gremlin.util.Gremlin; 32 | import java.io.IOException; 33 | import java.util.List; 34 | import java.util.ArrayList; 35 | import java.util.Map; 36 | import java.util.Set; 37 | import java.io.*; 38 | 39 | public class GraphFromCSV 40 | { 41 | 42 | private TinkerGraph tg; 43 | private GraphTraversalSource g; 44 | 45 | // Try to create a new empty graph instance 46 | public boolean createGraph() 47 | { 48 | tg = TinkerGraph.open() ; 49 | g = tg.traversal(); 50 | 51 | if (tg == null || g==null) 52 | { 53 | return false; 54 | } 55 | return true; 56 | } 57 | 58 | // Add the specified vertices and edge. Do not add anything that 59 | // already exists. 60 | public boolean addElements(String name1, String label, String name2) 61 | { 62 | if (tg == null || g==null) 63 | { 64 | return false; 65 | } 66 | 67 | // Create a node for 'name1' unless it exists already 68 | Vertex v1 = 69 | g.V().has("name",name1).fold(). 70 | coalesce(__.unfold(),__.addV().property("name",name1)).next(); 71 | 72 | // Create a node for 'name2' unless it exists already 73 | Vertex v2 = 74 | g.V().has("name",name2).fold(). 75 | coalesce(__.unfold(),__.addV().property("name",name2)).next(); 76 | 77 | // Create an edge between 'name1' and 'name2' unless it exists already 78 | g.V().has("name",name1).out(label).has("name",name2).fold(). 79 | coalesce(__.unfold(), 80 | __.addE(label).from(__.V(v1)).to(__.V(v2))).iterate(); 81 | 82 | return true; 83 | } 84 | 85 | public void displayGraph() 86 | { 87 | Long c; 88 | c = g.V().count().next(); 89 | System.out.println("Graph contains " + c + " vertices"); 90 | c = g.E().count().next(); 91 | System.out.println("Graph contains " + c + " edges"); 92 | 93 | List edges = g.V().outE().inV().path().by("name").by().toList(); 94 | 95 | for (Path p : edges) 96 | { 97 | System.out.println(p); 98 | } 99 | } 100 | 101 | 102 | // Open the sample csv file and build a graph based on its contents 103 | 104 | public static void main(String[] args) 105 | { 106 | GraphFromCSV gcsv = new GraphFromCSV(); 107 | 108 | if (gcsv.createGraph()) 109 | { 110 | try 111 | { 112 | String line; 113 | String [] values; 114 | 115 | FileReader fileReader = new FileReader("edges.csv"); 116 | 117 | BufferedReader bufferedReader = new BufferedReader(fileReader); 118 | 119 | while((line = bufferedReader.readLine()) != null) 120 | { 121 | //System.out.println(line); 122 | values = line.split(","); 123 | gcsv.addElements(values[0],values[1],values[2]); 124 | } 125 | 126 | gcsv.displayGraph(); 127 | bufferedReader.close(); 128 | } 129 | catch( Exception e ) 130 | { 131 | System.out.println("Unable to open file" + e.toString()); 132 | //e.printStackTrace(); 133 | } 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /sample-code/glv-client.js: -------------------------------------------------------------------------------- 1 | // glv-client.js 2 | // 3 | // Example of using Gremlin from Node.js via a remote connection. 4 | // 5 | // This example assumes you have previously used NPM as follows to install Gremlin support: 6 | // 7 | // npm install gremlin 8 | 9 | 10 | // Import the Gremlin specific objects we might need to reference 11 | const gremlin = require('gremlin'); 12 | const Graph = gremlin.structure.Graph; 13 | const __ = gremlin.process.statics; 14 | const { t,order,cardinality,column,scope,pop,operator,P } = gremlin.process; 15 | 16 | // Note that if we just wanted to import 'decr' rather than all of order we could do: 17 | // const { order: { decr } } = gremlin.process; 18 | 19 | const hostname = 'localhost' 20 | const port=8182 21 | console.log("Creating connection"); 22 | wspath = `ws://${hostname}:${port}/gremlin`; 23 | 24 | // NOTE: The empty object {} is to work around a bug in the 25 | // Gremlin JavaScript 3.3.5 and 3.4 clients. 26 | const DriverRemoteConnection = gremlin.driver.DriverRemoteConnection; 27 | const connection = new DriverRemoteConnection(wspath,{}); 28 | const graph = new Graph(); 29 | console.log("Connecting to :" + wspath); 30 | const g = graph.traversal().withRemote(connection); 31 | console.log("Connection created"); 32 | 33 | // Run a few tests that use the objects we imported above 34 | async function runTests() { 35 | try { 36 | const texas = await 37 | g.V().has('region','US-TX'). 38 | values('city'). 39 | order(). 40 | toList(); 41 | console.log("Airports in Texas"); 42 | console.log(texas); 43 | 44 | const runways = await 45 | g.V().has('region','US-TX'). 46 | group().by('code').by(__.out().count()). 47 | order(scope.local).by(column.values,order.decr). 48 | toList(); 49 | console.log("Route counts for airports in Texas"); 50 | console.log(runways); 51 | 52 | const most_runways = await 53 | g.V().has('runways',P.gte(5)). 54 | order().by('runways',order.decr). 55 | local(__.values('code','runways').fold()).toList(); 56 | console.log("Airports with the most runways"); 57 | console.log(most_runways); 58 | 59 | const highest = await 60 | g.V().hasLabel('airport'). 61 | order().by('elev',order.decr). 62 | limit(10). 63 | project('iata','city','elev'). 64 | by('code'). 65 | by('city'). 66 | by('elev'). 67 | toList() 68 | console.log("Airports at the highest altitude"); 69 | console.log(highest); 70 | 71 | const pop_test = await 72 | g.V().has('code','SFO').as('a'). 73 | out().limit(1).as('a'). 74 | select(pop.all,'a'). 75 | toList(); 76 | console.log("Using pop.all on a list"); 77 | console.log(pop_test); 78 | 79 | const label_test = await 80 | g.V().has('code',P.within(['EU','SFO','NA','MEX'])). 81 | group().by(t.label).by('desc'). 82 | toList(); 83 | console.log("Grouping by labels"); 84 | console.log(label_test); 85 | 86 | const routes = await 87 | g.withSack(0).V(). 88 | has('code','AUS'). 89 | repeat(__.outE().sack(operator.sum).by('dist').inV().simplePath()). 90 | until(__.has('code','WLG')). 91 | limit(10). 92 | order().by(__.sack()). 93 | local(__.union(__.path().by('code').by('dist'),__.sack()).fold()). 94 | toList(); 95 | console.log("\nSack step tests"); 96 | for (let i=0; i findRoutes(String from, String to, int max, int stops) 67 | { 68 | // Check that both airports exist so we don't waste time looking for 69 | // routes to non existent airports. 70 | Long check = g.V().has("code",P.within(from,to)).count().next(); 71 | if (check !=2) return null; 72 | 73 | // Look for routes matching the specified parameters 74 | List result = 75 | g.V().has("code",from). 76 | repeat(__.out().simplePath()).times(stops+1).emit().has("code",to). 77 | path().by("code").limit(max).toList(); 78 | 79 | return result; 80 | } 81 | 82 | // Run some tests 83 | public static void main(String[] args) 84 | { 85 | // If you want to check your Gremlin version, uncomment the next line 86 | //System.out.println("Gremlin version is: " + Gremlin.version()); 87 | 88 | RouteSearch rs = new RouteSearch(); 89 | boolean loaded = rs.loadGraph("air-routes.graphml"); 90 | 91 | if (loaded) 92 | { 93 | boolean done = false; 94 | while( !done ) 95 | { 96 | System.out.println("\nEnter from and to airport codes, eg DFW"); 97 | Console console = System.console(); 98 | System.out.print("From : "); 99 | String from = console.readLine().toUpperCase(); 100 | System.out.print("To : "); 101 | String to = console.readLine().toUpperCase(); 102 | System.out.print("Maximum number of routes to look for : "); 103 | int max = Integer.parseInt(console.readLine()); 104 | System.out.print("Maximum number of stops : "); 105 | int stops = Integer.parseInt(console.readLine()); 106 | 107 | List list; 108 | list = rs.findRoutes(from,to,max,stops) ; 109 | if (list == null) 110 | { 111 | System.out.println("\nPlease enter valid airport codes"); 112 | } 113 | else if (list.isEmpty()) 114 | { 115 | System.out.println("\nSorry, no routes were found, try more stops"); 116 | } 117 | else 118 | { 119 | list.forEach((v) -> System.out.println(v)); 120 | } 121 | 122 | System.out.print("\nAnother search (Y/N)? : "); 123 | String again = console.readLine().trim().toUpperCase(); 124 | 125 | if (again.equals("N")) 126 | { 127 | done = true; 128 | } 129 | } 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /sample-code/CreateGraph.java: -------------------------------------------------------------------------------- 1 | // CreateGraph.java 2 | // 3 | // Simple example of using TinkerGraph with Java 4 | // 5 | // This example does the following: 6 | // 1. Create an empty TinkerGraph instance 7 | // 2. Create some nodes and vertices 8 | // 3. Run a few queries against the newly created graph 9 | 10 | // I have highlighted the places where the Gremlin is slightly different from the 11 | // Gremlin we can use in the Gremlin Console. 12 | 13 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 14 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; 15 | import org.apache.tinkerpop.gremlin.process.traversal.Path; 16 | import org.apache.tinkerpop.gremlin.process.traversal.*; 17 | import org.apache.tinkerpop.gremlin.structure.Edge; 18 | import org.apache.tinkerpop.gremlin.structure.Vertex; 19 | import org.apache.tinkerpop.gremlin.structure.io.IoCore; 20 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.*; 21 | import org.apache.tinkerpop.gremlin.structure.T; 22 | import org.apache.tinkerpop.gremlin.structure.io.Io; 23 | import org.apache.tinkerpop.gremlin.util.Gremlin; 24 | import java.io.IOException; 25 | import java.util.List; 26 | import java.util.ArrayList; 27 | import java.util.Map; 28 | import java.util.HashMap; 29 | import java.util.Set; 30 | 31 | public class CreateGraph 32 | { 33 | public static void main(String[] args) 34 | { 35 | // If you want to check your Gremlin version, uncomment the next line 36 | //System.out.println("Gremlin version is: " + Gremlin.version()); 37 | 38 | // Create a new (empty) TinkerGrap 39 | TinkerGraph tg = TinkerGraph.open() ; 40 | 41 | // Create a Traversal source object 42 | GraphTraversalSource g = tg.traversal(); 43 | 44 | // Add some nodes and vertices - Note the use of "iterate". 45 | g.addV("airport").property("code","AUS").as("aus"). 46 | addV("airport").property("code","DFW").as("dfw"). 47 | addV("airport").property("code","LAX").as("lax"). 48 | addV("airport").property("code","JFK").as("jfk"). 49 | addV("airport").property("code","ATL").as("atl"). 50 | addE("route").from("aus").to("dfw"). 51 | addE("route").from("aus").to("atl"). 52 | addE("route").from("atl").to("dfw"). 53 | addE("route").from("atl").to("jfk"). 54 | addE("route").from("dfw").to("jfk"). 55 | addE("route").from("dfw").to("lax"). 56 | addE("route").from("lax").to("jfk"). 57 | addE("route").from("lax").to("aus"). 58 | addE("route").from("lax").to("dfw").iterate(); 59 | 60 | //System.out.println(g); 61 | //System.out.println(g.V().valueMap(true).toList()); 62 | 63 | // Simple example of how to work with the results we get back from a query 64 | 65 | List> vm = new ArrayList>() ; 66 | 67 | vm = g.V().valueMap(true).toList(); 68 | 69 | // Dislpay the code property as well as the label and id. 70 | for( Map m : vm) 71 | { 72 | System.out.println(((List)(m.get("code"))).get(0) + " " + m.get(T.id) + " " + m.get(T.label)); 73 | } 74 | System.out.println(); 75 | 76 | // Display the routes in the graph we just created. 77 | // Each path will include the vertex code values and the edge. 78 | 79 | List paths = new ArrayList(); 80 | 81 | paths = g.V().outE().inV().path().by("code").by().toList(); 82 | 83 | for (Path p : paths) 84 | { 85 | System.out.println(p.toString()); 86 | } 87 | 88 | // Count how many vertices and edges we just created. 89 | // Using groupCount is overkill when we only have one label 90 | // but typically you will have more so this is a useful technique 91 | // to be aware of. 92 | System.out.println("\nWe just created"); 93 | List verts = g.V().groupCount().by(T.label).toList(); 94 | System.out.println(((Map)verts.get(0)).get("airport") + " airports"); 95 | List edges = g.E().groupCount().by(T.label).toList(); 96 | System.out.println(((Map)edges.get(0)).get("route") + " routes"); 97 | 98 | // Note that we could also use the following code for a simple 99 | // case where we are only interested in specific labels. 100 | Long nv = g.V().hasLabel("airport").count().next(); 101 | Long ne = g.E().hasLabel("route").count().next(); 102 | System.out.println("The graph has " + nv + " airports and " + ne + " routes"); 103 | 104 | 105 | // Save the graph we just created as GraphML (XML) or GraphSON (JSON) 106 | try 107 | { 108 | // If you want to save the graph as GraphML uncomment the next line 109 | tg.io(IoCore.graphml()).writeGraph("mygraph.graphml"); 110 | 111 | // If you want to save the graph as JSON uncomment the next line 112 | //tg.io(IoCore.graphson()).writeGraph("mygraph.json"); 113 | } 114 | catch (IOException ioe) 115 | { 116 | System.out.println("Graph failed to save"); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /book/README.md: -------------------------------------------------------------------------------- 1 | This folder contains the AsciiDoc source file used to produce the HTML, XML (DOCBOOK), EPUB, MOBI and PDF output. 2 | 3 | 4 | **LATEST NEWS:** 5 | [Dec-26-2018] Revision 281 (TP 3.3.4) was just published in all formats. See [change history](https://github.com/krlawrence/graph/blob/master/ChangeHistory.md) for details. 6 | 7 | ## Releases and change history 8 | 9 | The most recent changes and additions are now being tracked in the [change history](https://github.com/krlawrence/graph/blob/master/ChangeHistory.md) file. 10 | 11 | **A special note about releases** 12 | 13 | Starting with revision 274 (Dec 24 2017), all of the output files (XML, EPUB, MOBI, HTML and PDF) will now be stored using Git releases. Going forward, this should reduce the amount of disk space required for people who create forks of this project. The releases are located [here](https://github.com/krlawrence/graph/releases). 14 | 15 | NOTE: In order to prune the unwanted files from the project, as part of the v274 release, the commit history for the output files had to be removed. If you had previously cloned or forked this project please create a new clone or fork. Sorry for the inconvenience but this will get you back approximately 60% (27+ mb) of the disk space that was being taken up and will help anyone else making a clone. 16 | 17 | **About the files in this folder** 18 | 19 | You can browse the 'Gremlin-Graph-Guide.adoc' file directly from within the GitHub (web interface) and it will work but you will not get the full color coding and other niceties that are present in the HTML and PDF versions as they have been run through an AsciiDoc processor and had various style sheets and code pretty printers applied. Your mileage may vary but I find the HTML version to be the most pleasing to read. The '.adoc' file will always contain the most recent updates. The other formats (HTML,DocBook,PDF,ePub and MOBI) will be generated once there are enough updates to make it worthwhile generating a 'release'. If you want to build the output format files yourself they can be generated by running the 'make-book.sh' script. The script assumes you have Asciidoctor installed (which is a Ruby Gem) as well as Pygments.rb (another Ruby Gem). To do the conversion to MOBI and EPUB the script assumes that Calibre and Pandoc are installed. I have successfuly built the book on several Linux distros including Ubuntu, CentOS and Red Hat. I have successfully used Asciidoctor on Mac OS as well but I always use Linux to produce the EPUB abd MOBI versions. 20 | 21 | To read the HTML file please either downloaded it to your computer or visit http://kelvinlawrence.net/book/Gremlin-Graph-Guide.html as it is too big for Git to display inside its web user interface. 22 | 23 | To view the PDF please either download it and use a PDF viewer or visit http://kelvinlawrence.net/book/Gremlin-Graph-Guide.pdf 24 | 25 | The XML (DOCBOOK) file is generated using Asciidoctor and can be viewed on Linux using the Yelp tool among many others or used to produce other formats. The EPUB and MOBI files can be viewed using most popular e-book readers and some browsers. 26 | 27 | Please note that the DOCBOOK, EPUB and MOBI format files currently do not have all of the nice source code highlighting and colors that the HTML and PDF versions have. 28 | 29 | 30 | **ARCHIVED NEWS:** 31 | [Jul-28-2018] Revision 280 (TP 3.3.3) was just published in all formats. See [change history](https://github.com/krlawrence/graph/blob/master/ChangeHistory.md) for details. 32 | [May-29-2018] Revision 279 (TP 3.3.3) was just published in all formats. See [change history](https://github.com/krlawrence/graph/blob/master/ChangeHistory.md) for details. 33 | [Mar-28-2018] Revision 278 (TP 3.3.1) was just published in all formats. See [change history](https://github.com/krlawrence/graph/blob/master/ChangeHistory.md) for details. 34 | [Feb-11-2018] Revision 277 was just published in all formats. See [change history](https://github.com/krlawrence/graph/blob/master/ChangeHistory.md) for details. 35 | [Jan-12-2018] Revision 276 was just plublished in all formats. Many updates to book and samples. 36 | [Jan-12-2018] Based on feedback I have decided to rename the book "Practical Gremlin" (see issue #29) 37 | [Jan-03-2018] Revision 275 was just published in all formats. Lots of updates to book and sample code. 38 | [Dec-24-2017] Revision 274 was just published in all formats. Now using releases to store output files. 39 | [Dec-12-2017] Revision 273 was just published in all formats. Fixes issue #12. Also added additonal clarifications. 40 | [Nov-23-2017] Revision 272 was just published in all formats. Many updates to sections 3 and 4. 41 | [Nov-03-2017] Revision 271 was just published in all formats. Several improvements and additions. 42 | [Oct-27-2017] Revision 270 was just published in all formats. Fixes issue #6 and adds more to Janus section. 43 | [Oct-23-2017] Quite a lot has been added to the Janus Graph section - more to come soon. 44 | [Oct-15-2017] Experimental - The /book folder now includes DOCBOOK, EPUB and MOBI format versions of the book. 45 | [Oct-11-2017] I improved the section that introduces the 'repeat' step. 46 | [Oct-10-2017] Several sections have been improved, I also made updates to reflect changes made in Tinkerpop 3.3 47 | -------------------------------------------------------------------------------- /sample-code/ListAirports.java: -------------------------------------------------------------------------------- 1 | // ListAirports.java 2 | // 3 | // Another simple example of using TinkerGraph with Java 4 | // 5 | // This example does the following: 6 | // 1. Creates an empty TinkerGraph instance 7 | // 2. Loads the air-routes.graphml file 8 | // 3. Displays information about selected airports. 9 | // 10 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 11 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; 12 | import org.apache.tinkerpop.gremlin.process.traversal.Path; 13 | import org.apache.tinkerpop.gremlin.process.traversal.*; 14 | import org.apache.tinkerpop.gremlin.structure.Edge; 15 | import org.apache.tinkerpop.gremlin.structure.Vertex; 16 | import org.apache.tinkerpop.gremlin.structure.io.IoCore; 17 | import org.apache.tinkerpop.gremlin.structure.T; 18 | import org.apache.tinkerpop.gremlin.structure.Column; 19 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.*; 20 | import org.apache.tinkerpop.gremlin.util.Gremlin; 21 | import java.io.IOException; 22 | import java.util.List; 23 | import java.util.ArrayList; 24 | import java.util.Map; 25 | import java.util.HashMap; 26 | import org.apache.commons.configuration.BaseConfiguration; 27 | 28 | public class ListAirports 29 | { 30 | private TinkerGraph tg; 31 | private GraphTraversalSource g; 32 | 33 | // ------------------------------------------------------------- 34 | // Try to create a new graph and load the specified GraphML file 35 | // ------------------------------------------------------------- 36 | public boolean loadGraph(String name) 37 | { 38 | // Make sure index ID values are set as LONG values. 39 | // If this is not done, when we try to sort results by vertex 40 | // ID later it will not sort the way you would expect it to. 41 | 42 | BaseConfiguration conf = new BaseConfiguration(); 43 | conf.setProperty("gremlin.tinkergraph.vertexIdManager","LONG"); 44 | conf.setProperty("gremlin.tinkergraph.edgeIdManager","LONG"); 45 | conf.setProperty("gremlin.tinkergraph.vertexPropertyIdManager","LONG"); 46 | 47 | // Create a new instance that uses this configuration. 48 | tg = TinkerGraph.open(conf) ; 49 | 50 | // Load the graph and time how long it takes. 51 | System.out.println("Loading " + name); 52 | long t1 = System.currentTimeMillis(); 53 | System.out.println(t1); 54 | 55 | try 56 | { 57 | tg.io(IoCore.graphml()).readGraph(name); 58 | } 59 | catch( IOException e ) 60 | { 61 | System.out.println("ERROR - GraphML file not found or invalid."); 62 | return false; 63 | } 64 | 65 | long t2 = System.currentTimeMillis(); 66 | System.out.println(t2 + "(" + (t2-t1) +")"); 67 | System.out.println("Graph loaded\n"); 68 | g = tg.traversal(); 69 | return true; 70 | } 71 | 72 | // ---------------------------------------------- 73 | // Display some information about the selected 74 | // number of airports. A value of -1 means select 75 | // all airports. 76 | // ---------------------------------------------- 77 | public void listAirports(int max) 78 | { 79 | if (max < -1 ) return; 80 | 81 | // Try to find the requested number of airports. 82 | // Note the use of the "__." and "Order" prefixes. 83 | List vlist = 84 | g.V().hasLabel("airport"). 85 | order().by(__.id(),Order.incr). 86 | limit(max). 87 | toList(); 88 | 89 | Long id; // Vertex ID 90 | String iata; // 3 character IATA code. 91 | String icao; // 4 character ICAO code. 92 | String city; // City the airport is in. 93 | String desc; // Airport description. 94 | String ctry; // 2 character country code. 95 | String rgn; // 5 or 6 character Region code 96 | 97 | for (Vertex v : vlist) 98 | { 99 | id = (Long)v.id(); 100 | iata = (String)v.values("code").next(); 101 | icao = (String)v.values("icao").next(); 102 | city = (String)v.values("city").next(); 103 | desc = (String)v.values("desc").next(); 104 | ctry = (String)v.values("country").next(); 105 | rgn = (String)v.values("region").next(); 106 | 107 | System.out.format("%5d %3s %4s %2s %6s %15s %-50s\n", 108 | id,iata,icao,ctry,rgn,city,desc); 109 | } 110 | } 111 | 112 | // --------------------------------------- 113 | // Try to load a graph and run a few tests 114 | // --------------------------------------- 115 | public static void main(String[] args) 116 | { 117 | int required = 10; 118 | boolean failed = false; 119 | 120 | try 121 | { 122 | if (args.length > 0) required = Integer.parseInt(args[0]); 123 | } 124 | catch (Exception e) 125 | { 126 | failed = true; 127 | } 128 | 129 | if (failed || required < -1) 130 | { 131 | System.out.println("Argument should be -1, 0 or any positive integer"); 132 | System.exit(1); 133 | } 134 | 135 | ListAirports lapt = new ListAirports(); 136 | 137 | if ( lapt.loadGraph("air-routes.graphml")) 138 | { 139 | lapt.listAirports(required); 140 | } 141 | 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /sample-code/Iterate.java: -------------------------------------------------------------------------------- 1 | // Iterate.java 2 | // 3 | // Simple example of using TinkerGraph with Java 4 | // 5 | // This example does the following: 6 | // 1. Create a TinkerGraph instance 7 | // 2. Load the air routes graph 8 | // 3. Experiment with maps and iterators 9 | // 4. Do some privitive analysis of how random the sample step is. 10 | 11 | // I have highlighted the places where the Gremlin is slightly different from the 12 | // Gremlin we can use in the Gremlin Console. 13 | 14 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 15 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; 16 | import org.apache.tinkerpop.gremlin.process.traversal.Path; 17 | import org.apache.tinkerpop.gremlin.process.traversal.*; 18 | import org.apache.tinkerpop.gremlin.structure.Edge; 19 | import org.apache.tinkerpop.gremlin.structure.Vertex; 20 | import org.apache.tinkerpop.gremlin.structure.io.IoCore; 21 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.*; 22 | import org.apache.tinkerpop.gremlin.structure.T; 23 | import java.io.IOException; 24 | import java.util.List; 25 | import java.util.ArrayList; 26 | import java.util.Map; 27 | import java.util.Set; 28 | import java.util.Iterator; 29 | 30 | public class Iterate 31 | { 32 | public static void main(String[] args) 33 | { 34 | // Create a new TinkerGraph and try to load the air-routes graph 35 | TinkerGraph tg = TinkerGraph.open() ; 36 | 37 | System.out.println("\nOpening air-routes.graphml...\n"); 38 | 39 | try 40 | { 41 | tg.io(IoCore.graphml()).readGraph("air-routes.graphml"); 42 | } 43 | catch( IOException e ) 44 | { 45 | System.out.println("Air routes GraphML file not found or invalid"); 46 | System.exit(1); 47 | } 48 | GraphTraversalSource g = tg.traversal(); 49 | 50 | // Default sample size can be overriden by command line parameter. 51 | int sample_size = 30 ; 52 | 53 | try 54 | { 55 | if (args.length > 0) sample_size = Integer.parseInt(args[0]); 56 | } 57 | catch (Exception e) 58 | { 59 | System.out.println("Unrecognized value:(" + args[0] + "). Using defaults"); 60 | } 61 | 62 | // Get an iterator of 30 value maps sampled at random. 63 | Iterator> res = 64 | g.V().hasLabel("airport").sample(sample_size).valueMap(true); 65 | 66 | 67 | // Build an iterator of 30 projected maps from a random sample of airports. 68 | // Note the use of "__." before the call to id(). 69 | 70 | Iterator> res2 = 71 | g.V().hasLabel("airport").sample(sample_size). 72 | project("id","iata","city"). 73 | by(__.id()).by("code").by("city"); 74 | 75 | 76 | // To experiment with the coin step you can use the code below. 77 | /* 78 | Iterator> res2 = 79 | g.V().hasLabel("airport").coin(0.5).limit(sample_size). 80 | project("id","iata","city"). 81 | by(__.id()).by("code").by("city"); 82 | */ 83 | 84 | // For each value map display a few fields. 85 | // Note how for property values we have to process them as lists. 86 | 87 | Map vmap; 88 | 89 | System.out.println("\n*** Output from valueMap() ***\n\n"); 90 | System.out.format("%4s %5s %5s","ID","IATA","CITY\n"); 91 | 92 | while(res.hasNext()) 93 | { 94 | vmap = res.next(); 95 | System.out.format( "%4s %5s %-20s\n", 96 | vmap.get(T.id), 97 | ((List)(vmap.get("code"))).get(0), 98 | ((List)(vmap.get("city"))).get(0)); 99 | } 100 | 101 | 102 | // Process the map built using project(). 103 | // Note that this time the values are not in lists. 104 | // Just for fun let's also see howthe sample was distributed. 105 | 106 | Map vmap2; 107 | int low = 0, medium = 0, high = 0; 108 | 109 | System.out.println("\n*** Output from project() ***\n\n"); 110 | System.out.format("%4s %5s %5s","ID","IATA","CITY\n"); 111 | 112 | Long num_airports = g.V().hasLabel("airport").count().next(); 113 | Long low_bar = num_airports/3; 114 | Long med_bar = low_bar * 2; 115 | 116 | while(res2.hasNext()) 117 | { 118 | 119 | vmap2 = res2.next(); 120 | int id = Integer.parseInt((String)(vmap2.get("id"))); 121 | 122 | System.out.format( "%4d %5s %-20s\n", 123 | id, 124 | vmap2.get("iata"), 125 | vmap2.get("city")); 126 | 127 | // Track sample distribution 128 | if (id < low_bar) 129 | { 130 | low += 1; 131 | } 132 | else if (id < med_bar) 133 | { 134 | medium += 1; 135 | } 136 | else 137 | { 138 | high += 1; 139 | } 140 | } 141 | 142 | 143 | System.out.println("\nGraph contains " + num_airports + " airports."); 144 | System.out.println("Low bar= " + low_bar + " med bar=" + med_bar); 145 | System.out.println("\nLow=" + low + " Medium=" + medium + " High=" + high); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /sample-code/glv-client-2.py: -------------------------------------------------------------------------------- 1 | # glv-client-2.py 2 | # 3 | # Connect to a Gremlin Server using a remote connection and issue some basic queries. 4 | # Note the way that certain Gremlin steps that share the same name as Python reserved words 5 | # or method names are handled by postfixing an underscore after them as in the case of "as_". 6 | # 7 | # Unlike in the basic-client.py example, the queries sent to the server are sent using 8 | # Gremlin byte code and not sent as text strings. 9 | # 10 | # This example code assumes that the GremlinPython library has been installed using: 11 | # 12 | # pip install gremlinpython 13 | # 14 | 15 | # Import some classes we will need to talk to our graph 16 | from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection 17 | from gremlin_python.structure.graph import Graph 18 | from gremlin_python import statics 19 | from gremlin_python.process.graph_traversal import __ 20 | from gremlin_python.process.strategies import * 21 | from gremlin_python.process.traversal import * 22 | 23 | # Path to our graph (this assumes a locally running Gremlin Server) 24 | # Note how the path is a Web Socket (ws) connection. 25 | endpoint = 'ws://localhost:8182/gremlin' 26 | 27 | # Obtain a graph traversal source using a remote connection 28 | graph=Graph() 29 | connection = DriverRemoteConnection(endpoint,'g') 30 | g = graph.traversal().withRemote(connection) 31 | 32 | # Helper method to pretty print some headings. 33 | def heading(s): 34 | print("\n{}".format(s)) 35 | for i in range(len(s)): 36 | print("-",end="") 37 | print("") 38 | 39 | # Cities in Texas with one or more airports. 40 | texas = g.V().has('region','US-TX').\ 41 | values('city').\ 42 | dedup().\ 43 | order().\ 44 | toList() 45 | 46 | heading("Cities with airports in Texas") 47 | for t in texas: 48 | print(t) 49 | 50 | # Outgoing route counts for airports in Texas. 51 | # Note the use of the anonymous traversal "__." as well as 52 | # the Scope, Column and Order enums. 53 | runways = g.V().has('region','US-TX').\ 54 | group().by('code').\ 55 | by(__.out().count()).\ 56 | order(Scope.local).\ 57 | by(Column.values,Order.decr).\ 58 | next() 59 | 60 | heading("Commercial route counts for airports in Texas") 61 | for k,v in runways.items(): 62 | print(k,v) 63 | 64 | # Find the top 10 airports at the highest elevation. 65 | # Note the use of the Order enum 66 | highest = g.V().hasLabel('airport').\ 67 | order().by('elev',Order.decr).\ 68 | limit(10).\ 69 | project('iata','city','elev').\ 70 | by('code').\ 71 | by('city').\ 72 | by('elev').\ 73 | toList() 74 | 75 | heading("Airports at the highest altitude") 76 | for row in highest: 77 | print("{:3s} {:20s} Elevation {:6d}ft".format(row['iata'],row['city'],row['elev'])) 78 | 79 | 80 | # Shows how to use the Pop enum. Note the use of "as_" and "all_". 81 | pop_test = g.V().has('code','SFO').as_('a').\ 82 | out().limit(1).as_('a').\ 83 | select(Pop.all_,'a').\ 84 | unfold().\ 85 | values('code').\ 86 | toList() 87 | 88 | heading("Using pop.all on a list") 89 | print(pop_test) 90 | 91 | # Shows how to access a vertex label using the T enum. 92 | label_test = g.V().has('code',P.within(['EU','SFO','NA','CUN'])).\ 93 | group().\ 94 | by(T.label).\ 95 | by('desc').\ 96 | next()\ 97 | 98 | heading("Grouping by labels") 99 | for k,v in label_test.items(): 100 | print(k,v) 101 | 102 | # Shows how to explicitly access the values of a map 103 | group = g.V().has('region','GB-ENG').\ 104 | has('city', P.within('London','Manchester')).\ 105 | group().\ 106 | by('city').\ 107 | by('code').\ 108 | select(Column.values).\ 109 | unfold().\ 110 | toList() 111 | 112 | heading("Selecting values from a group") 113 | print(group) 114 | 115 | # Airports with the most runways. Note the use of the P enum to 116 | # access the "gte" predicate. 117 | most_runways = g.V().has('runways',P.gte(5)).\ 118 | order().\ 119 | by('runways',Order.decr).\ 120 | local(__.values('code','runways').fold()).\ 121 | toList() 122 | 123 | heading("Airports with the most runways") 124 | for rows in most_runways: 125 | print(rows[0],rows[1]) 126 | 127 | # Shortest routes by distance from AUS to WLG. 128 | # Note the use of the Operator enum. 129 | routes = g.withSack(0).\ 130 | V().\ 131 | has('code','AUS').\ 132 | repeat(__.outE().sack(Operator.sum).by('dist').\ 133 | inV().simplePath()).\ 134 | until(__.has('code','WLG')).\ 135 | limit(10).\ 136 | order().\ 137 | by(__.sack()).\ 138 | local(__.union(__.path().by('code').by('dist'),__.sack()).fold()).\ 139 | toList() 140 | 141 | heading("Sack step tests") 142 | for route in routes: 143 | print(route) 144 | 145 | # All done so close the connetion 146 | connection.close() 147 | -------------------------------------------------------------------------------- /sample-code/quick-social2.groovy: -------------------------------------------------------------------------------- 1 | // quick-social2.groovy 2 | // 3 | // Creates a simple social graph that can be useful for doing some 4 | // simple testing and experimenting. A few example queries are also 5 | // included. This will work unchanged from the Gremlin console if 6 | // using a TinkerGraph or with any other TinkerPop graph database if 7 | // you remove the first two lines and the comment lines. 8 | 9 | // Remove these two lines if using a graph db other than TinkerGraph. 10 | graph=TinkerGraph.open() 11 | g=graph.traversal() 12 | 13 | g.addV("person").property("name","Albert").as("albert"). 14 | addV("person").property("name","Bill").as("bill"). 15 | addV("person").property("name","Fred").as("fred"). 16 | addV("person").property("name","Janet").as("janet"). 17 | addV("person").property("name","Mary").as("mary"). 18 | addV("person").property("name","Max").as("max"). 19 | addV("person").property("name","Lily").as("lily"). 20 | addV("person").property("name","Peter").as("peter"). 21 | addV("person").property("name","Sarah").as("sarah"). 22 | addV("person").property("name","Susan").as("susan"). 23 | addV("place").property("name","Boston").as("bos"). 24 | addV("place").property("name","Chicago").as("ord"). 25 | addV("place").property("name","Dallas").as("dal"). 26 | addV("place").property("name","Los Angeles").as("lax"). 27 | addV("place").property("name","Miami").as("mia"). 28 | addV("place").property("name","New York City").as("nyc"). 29 | addV("place").property("name","Seattle").as("sea"). 30 | addV("country").property("name","USA").as("usa"). 31 | addE("knows").from("albert").to("mary"). 32 | addE("lives_in").from("albert").to("mia"). 33 | addE("knows").from("bill").to("fred"). 34 | addE("knows").from("bill").to("max"). 35 | addE("knows").from("bill").to("peter"). 36 | addE("lives_in").from("bill").to("mia"). 37 | addE("knows").from("fred").to("mary"). 38 | addE("knows").from("fred").to("janet"). 39 | addE("knows").from("fred").to("bill"). 40 | addE("knows").from("fred").to("max"). 41 | addE("lives_in").from("fred").to("sea"). 42 | addE("knows").from("janet").to("fred"). 43 | addE("knows").from("janet").to("lily"). 44 | addE("lives_in").from("janet").to("dal"). 45 | addE("knows").from("lily").to("janet"). 46 | addE("lives_in").from("lily").to("bos"). 47 | addE("knows").from("mary").to("albert"). 48 | addE("knows").from("mary").to("susan"). 49 | addE("knows").from("mary").to("max"). 50 | addE("knows").from("mary").to("fred"). 51 | addE("lives_in").from("mary").to("nyc"). 52 | addE("knows").from("max").to("bill"). 53 | addE("knows").from("max").to("fred"). 54 | addE("knows").from("max").to("mary"). 55 | addE("knows").from("max").to("peter"). 56 | addE("lives_in").from("max").to("bos"). 57 | addE("knows").from("peter").to("bill"). 58 | addE("knows").from("peter").to("susan"). 59 | addE("knows").from("peter").to("max"). 60 | addE("lives_in").from("peter").to("dal"). 61 | addE("knows").from("susan").to("peter"). 62 | addE("knows").from("susan").to("mary"). 63 | addE("lives_in").from("sarah").to("ord"). 64 | addE("lives_in").from("susan").to("sea"). 65 | addE("city_in").from("bos").to("usa"). 66 | addE("city_in").from("dal").to("usa"). 67 | addE("city_in").from("lax").to("usa"). 68 | addE("city_in").from("mia").to("usa"). 69 | addE("city_in").from("nyc").to("usa"). 70 | addE("city_in").from("ord").to("usa"). 71 | addE("city_in").from("sea").to("usa").iterate() 72 | 73 | // What does the graph look like? 74 | g.V().order().by('name').outE().inV().path().by('name').by(label) 75 | 76 | // What is the distribution of relationships? 77 | g.V().hasLabel('person','place').out().groupCount().by('name') 78 | g.V().hasLabel('person','place').in().groupCount().by('name') 79 | 80 | // What vertices do we have? 81 | g.V().order().by('name').outE().inV().path().by('name').by(label) 82 | 83 | // Who does Max know that lives in Miami? 84 | g.V().has('name','Max').out('knows').where(out('lives_in').values('name').is('Miami')).values('name') 85 | 86 | // Who lives in New York City? 87 | g.V().hasLabel('person').where(out('lives_in').has('name','New York City')).values('name') 88 | 89 | // Who are Mary's friends , friends ? 90 | g.V().has('person','name','Mary').as('mary'). 91 | out('knows').out('knows').where(neq('mary')).dedup().values('name') 92 | 93 | // Who are Mary's friends , friends ? (using match) 94 | g.V().has('person','name','Mary'). 95 | match(__.as('a').out('knows').as('b') 96 | ,__.as('b').out('knows').where(neq('a')).as('c')). 97 | select('c').by('name').dedup() 98 | 99 | // Who does Mary know that already know each other? 100 | g.V().has('person','name','Mary').out('knows').as('x').aggregate('maryalreadyknows'). 101 | out('knows').where(within('maryalreadyknows')).path().by('name').from('x') 102 | 103 | // Who does Mary know whose friends don't know Mary? 104 | g.V().has('person','name','Mary').as('mary'). 105 | out('knows').aggregate('maryalreadyknows'). 106 | out('knows').where(neq('mary')).where(without('maryalreadyknows')). 107 | values('name').dedup() 108 | 109 | // Who does Mary know whose friends don't know Mary? (using match) 110 | g.V().has('person','name','Mary'). 111 | match(__.as('mary').out('knows').as('maryalreadyknows') 112 | ,__.as('maryalreadyknows').out('knows').where(neq('mary')).as('c') 113 | ,__.not(__.as('mary').out().as('c'))). 114 | select('c').by('name').dedup() 115 | 116 | // Which of Mary's friends already know each other and which do not? 117 | g.V().has('name','Mary').as('mary').out('knows').aggregate('maryknows'). 118 | local(union(identity().values('name'), 119 | out('knows').where(neq('mary')).where(within('maryknows')). 120 | values('name')).fold()) 121 | 122 | -------------------------------------------------------------------------------- /sample-code/graph-stats.groovy: -------------------------------------------------------------------------------- 1 | ;[] // graph-stats.groovy 2 | ;[] // 3 | ;[] // This script is intended to be run within the Gremlin Console. 4 | ;[] // 5 | ;[] // Small Groovy script that can be used from within the Gremlin console after 6 | ;[] // the air-routes graph has been loaded that will provide statistics about the 7 | ;[] // graph. This script demonstrates different ways of doing similar things 8 | ;[] // 9 | ;[] // From the console use :load graph-stats.groovy to run it. 10 | ;[] // 11 | ;[] // The ";[]" notation is used to prevent unwanted output from the Gremlin 12 | ;[] // Console. 13 | 14 | println "\n\nA few statistics about the air-routes graph";[] 15 | println "===========================================";[] 16 | 17 | println "\nDistribution of vertices and edges";[] 18 | println "----------------------------------";[] 19 | verts = g.V().groupCount().by(label).next();[] 20 | edges = g.E().groupCount().by(label).next();[] 21 | println "Vertices : ${verts}";[] 22 | println "Edges : ${edges}";[] 23 | 24 | most = g.V().hasLabel('airport').order().by(bothE('route').count(),decr).limit(1). 25 | project('ap','num','city').by('code').by(bothE('route').count()).by('city').next();[] 26 | 27 | println "\nThe airport with the most routes (incoming and outgoing) is ${most['ap']}/${most['city']} with ${most['num']}";[] 28 | 29 | 30 | println "\nTop 20 airports ordered by overall routes";[] 31 | println "-----------------------------------------";[] 32 | most = g.V().hasLabel('airport').order().by(both('route').count(),decr).limit(20). 33 | project('ap','num','city').by('code').by(both('route').count()).by('city').toList();[] 34 | 35 | most.each {printf("%4s %15s %5d\n", it.ap, it.city, it.num)};[] 36 | 37 | 38 | println "\nTop 20 airports ordered by number of outgoing routes";[] 39 | println "----------------------------------------------------";[] 40 | most = g.V().hasLabel('airport').order().by(out('route').count(),decr).limit(20). 41 | project('ap','num','city').by('code').by(out('route').count()).by('city').toList();[] 42 | 43 | most.each {printf("%4s %15s %5d\n", it.ap, it.city, it.num)};[] 44 | 45 | println "\nTop 20 airports ordered by number of incoming routes";[] 46 | println "----------------------------------------------------";[] 47 | most = g.V().hasLabel('airport').order().by(__.in('route').count(),decr).limit(20). 48 | project('ap','num','city').by('code').by(__.in('route').count()).by('city').toList();[] 49 | 50 | most.each {printf("%4s %15s %5d\n", it.ap, it.city, it.num)};[] 51 | 52 | 53 | longroute = g.E().hasLabel('route').order().by('dist',decr).limit(1). 54 | project('from','to','num'). 55 | by(inV().values('code')).by(outV().values('code')).by('dist').next();[] 56 | 57 | println "\nThe longest route in the graph is ${longroute['num']} miles between ${longroute['from']} and ${longroute['to']}";[] 58 | 59 | shortroute = g.E().hasLabel('route').order().by('dist',incr).limit(1). 60 | project('from','to','num'). 61 | by(inV().values('code')).by(outV().values('code')).by('dist').next();[] 62 | 63 | println "The shortest route in the graph is ${shortroute['num']} miles between ${shortroute['from']} and ${shortroute['to']}";[] 64 | 65 | 66 | meanroute = g.E().hasLabel('route').values('dist').mean().next().round(4);[] 67 | println "The average route distance is ${meanroute} miles";[] 68 | 69 | println "\nTop 20 routes in the graph by distance";[] 70 | println "--------------------------------------";[] 71 | 72 | routes = g.E().hasLabel('route').order().by('dist',decr).limit(40). 73 | project('a','b','c'). 74 | by(inV().values('code')).by('dist').by(outV().values('code')). 75 | filter(select('a','c')).where('a',lt('c')).toList();[] 76 | 77 | routes.each {printf("%4s %4d %4s\n", it.a, it.b, it.c)};[] 78 | 79 | 80 | longest = g.V().hasLabel('airport').order().by('longest',decr).limit(1). 81 | project('ap','num','city').by('code').by('longest').by('city').next();[] 82 | 83 | println "\nThe longest runway in the graph is ${longest['num']} feet at ${longest['ap']}/${longest['city']}";[] 84 | 85 | shortest = g.V().hasLabel('airport').order().by('longest',incr).limit(1). 86 | project('ap','num','city').by('code').by('longest').by('city').next();[] 87 | 88 | println "The shortest runway in the graph is ${shortest['num']} feet at ${shortest['ap']}/${shortest['city']}";[] 89 | 90 | ;[] // A different way of doing the above type of query using two queries. 91 | ;[] // Just to show a different approach 92 | highest = g.V().hasLabel('airport').values('elev').max().next();[] 93 | aptcity = g.V().has('elev',highest).valueMap('code','city').next();[] 94 | println "\nThe highest airport in the graph is ${aptcity['code'][0]}/${aptcity['city'][0]} which is at ${highest} feet above sea level";[] 95 | 96 | lowest = g.V().hasLabel('airport').order().by('elev',incr).limit(1). 97 | project('ap','num','city').by('code').by('elev').by('city').next();[] 98 | 99 | ab = "above";[] 100 | if (lowest['num'] < 0) ab = "below";[] 101 | println "The lowest airport in the graph is ${lowest['ap']}/${lowest['city']} which is at ${lowest['num']} feet ${ab} sea level";[] 102 | 103 | 104 | ;[] // Here is an example of using the group step to perform similar tasks 105 | continents = g.V().hasLabel('continent').group().by('desc').by(out().count()). 106 | order(local).by(values,decr).next();[] 107 | 108 | 109 | println("\nNumber of airports in each continent");[] 110 | println("------------------------------------");[] 111 | continents.each {printf("%15s %4d\n",it.key,it.value)};[] 112 | println "";[] 113 | 114 | 115 | countries = g.V().hasLabel('country').order().by(outE().count(),decr).limit(20). 116 | project('airports','name').by(outE().count()).by('desc').toList();[] 117 | 118 | println("\nCountries with the most airports");[] 119 | println("--------------------------------");[] 120 | countries.each {printf("%20s %4d\n",it.name,it.airports)};[] 121 | println "";[] 122 | -------------------------------------------------------------------------------- /sample-code/TestImports.java: -------------------------------------------------------------------------------- 1 | // TestImports.java 2 | // 3 | // Simple example of using TinkerGraph with Java 4 | // 5 | // This example does the following: 6 | // 1. Create a TinkerGraph instance 7 | // 2. Load the air routes graph 8 | // 3. Demonstrate some queries that show how to do in Java what is a little 9 | // simpler using the Gremlin console. Mainly shows which Enums, classes and 10 | // imports are needed. 11 | 12 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 13 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; 14 | import org.apache.tinkerpop.gremlin.process.traversal.Path; 15 | import org.apache.tinkerpop.gremlin.process.traversal.*; 16 | import org.apache.tinkerpop.gremlin.structure.Edge; 17 | import org.apache.tinkerpop.gremlin.structure.Vertex; 18 | import org.apache.tinkerpop.gremlin.structure.Property; 19 | import org.apache.tinkerpop.gremlin.structure.Column; 20 | import org.apache.tinkerpop.gremlin.structure.io.IoCore; 21 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.*; 22 | import org.apache.tinkerpop.gremlin.structure.T; 23 | import java.io.IOException; 24 | import java.util.List; 25 | import java.util.ArrayList; 26 | import java.util.Map; 27 | import java.util.Set; 28 | 29 | public class TestImports 30 | { 31 | private TinkerGraph tg; 32 | private GraphTraversalSource g; 33 | 34 | // Try to create a new graph and load the specified GraphML file 35 | public boolean loadGraph(String name) 36 | { 37 | tg = TinkerGraph.open() ; 38 | 39 | try 40 | { 41 | tg.io(IoCore.graphml()).readGraph(name); 42 | } 43 | catch( IOException e ) 44 | { 45 | System.out.println("GraphStats - GraphML file not found"); 46 | return false; 47 | } 48 | g = tg.traversal(); 49 | return true; 50 | } 51 | 52 | // Help make the output easier to read 53 | 54 | private void showHeader(String str) 55 | { 56 | String tmp = "***** " +str + " *****" ; 57 | String tmp2 = "" ; 58 | 59 | for (int i=0; i props = 151 | g.V().has("code","SFO").properties().order().by(T.key).toList(); 152 | 153 | showHeader("Order properties by(T.key)"); 154 | props.forEach((p) -> System.out.println(p)); 155 | System.out.println(); 156 | 157 | // -------------------- 158 | // Working with labels. 159 | // -------------------- 160 | 161 | showHeader("groupCount().by(T.label)"); 162 | 163 | results = g.V().groupCount().by(T.label).toList(); 164 | System.out.println(results + "\n"); 165 | } 166 | 167 | public static void main(String[] args) 168 | { 169 | // If you want to check your Gremlin version, uncomment the next line 170 | //System.out.println("Gremlin version is: " + Gremlin.version()); 171 | 172 | TestImports tim = new TestImports(); 173 | boolean loaded = tim.loadGraph("air-routes.graphml"); 174 | 175 | if (loaded) 176 | { 177 | tim.runTests(); 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /sample-code/nested-repeat.groovy: -------------------------------------------------------------------------------- 1 | // Experiments with the nested repeat feature added in TinkerPop 3.4.0 2 | // 3 | // NOTE: To run you will need the Gremlin Console at the TinkerPop 3.4.0 4 | // level or higher. As other vendors upgrade to TinkerPop 3.4.0 5 | // you mayl be able to use nested repeats on those platforms also. 6 | 7 | conf = new BaseConfiguration() 8 | conf.setProperty("gremlin.tinkergraph.vertexIdManager","LONG") 9 | conf.setProperty("gremlin.tinkergraph.edgeIdManager","LONG") 10 | conf.setProperty("gremlin.tinkergraph.vertexPropertyIdManager","LONG") 11 | 12 | graph = TinkerGraph.open(conf) 13 | g = graph.traversal() 14 | 15 | g.addV('person').property('name','Amy').as('amy'). 16 | addV('person').property('name','Bill').as('bill'). 17 | addV('person').property('name','Sam').as('sam'). 18 | addV('person').property('name','Eric').as('eric'). 19 | addV('person').property('name','Frank').as('frank'). 20 | addV('person').property('name','Janet').as('janet'). 21 | addV('person').property('name','Marie').as('marie'). 22 | addV('person').property('name','Mark').as('mark'). 23 | addV('person').property('name','Pam').as('pam'). 24 | addV('person').property('name','Peter').as('peter'). 25 | addV('city').property('name','Austin').as('austin'). 26 | addV('city').property('name','Brighton').as('brighton'). 27 | addV('city').property('name','Canterbury').as('canterbury'). 28 | addV('city').property('name','Miami').as('miami'). 29 | addV('city').property('name','New York City').as('nyc'). 30 | addV('county').property('name','Dade').as('dade'). 31 | addV('county').property('name','East Sussex').as('esussex'). 32 | addV('county').property('name','Kent').as('kent'). 33 | addV('county').property('name','New York County').as('nycc'). 34 | addV('county').property('name','Travis').as('travis'). 35 | addV('state').property('name','Florida').as('florida'). 36 | addV('state').property('name','New York').as('ny'). 37 | addV('state').property('name','Texas').as('texas'). 38 | addV('country').property('name','USA').as('usa'). 39 | addV('country').property('name','England').as('england'). 40 | addE('knows').from('bill').to('amy'). 41 | addE('knows').from('bill').to('eric'). 42 | addE('knows').from('bill').to('frank'). 43 | addE('knows').from('bill').to('sam'). 44 | addE('knows').from('eric').to('pam'). 45 | addE('knows').from('eric').to('marie'). 46 | addE('location').from('amy').to('canterbury'). 47 | addE('location').from('bill').to('austin'). 48 | addE('location').from('eric').to('austin'). 49 | addE('location').from('frank').to('miami'). 50 | addE('location').from('janet').to('brighton'). 51 | addE('location').from('marie').to('canterbury'). 52 | addE('location').from('mark').to('miami'). 53 | addE('location').from('pam').to('nyc'). 54 | addE('location').from('peter').to('brighton'). 55 | addE('location').from('sam').to('brighton'). 56 | addE('part_of').from('austin').to('travis'). 57 | addE('part_of').from('brighton').to('esussex'). 58 | addE('part_of').from('canterbury').to('kent'). 59 | addE('part_of').from('miami').to('dade'). 60 | addE('part_of').from('nyc').to('nycc'). 61 | addE('part_of').from('nycc').to('ny'). 62 | addE('part_of').from('travis').to('texas'). 63 | addE('part_of').from('dade').to('florida'). 64 | addE('part_of').from('esussex').to('england'). 65 | addE('part_of').from('kent').to('england'). 66 | addE('part_of').from('florida').to('usa'). 67 | addE('part_of').from('texas').to('usa'). 68 | addE('part_of').from('ny').to('usa'). 69 | iterate() 70 | 71 | // Check the relationships we just created. 72 | g.V().hasLabel('person'). 73 | repeat(outE().inV()). 74 | until(__.not(out())). 75 | path().by('name').by(label) 76 | /* 77 | ==>[Amy,location,Canterbury,part_of,Kent,part_of,England] 78 | ==>[Bill,location,Austin,part_of,Travis,part_of,Texas,part_of,USA] 79 | ==>[Bill,knows,Amy,location,Canterbury,part_of,Kent,part_of,England] 80 | ==>[Bill,knows,Sam,location,Brighton,part_of,East Sussex,part_of,England] 81 | ==>[Bill,knows,Eric,location,Austin,part_of,Travis,part_of,Texas,part_of,USA] 82 | ==>[Bill,knows,Eric,knows,Pam,location,New York City,part_of,New York,part_of,USA] 83 | ==>[Bill,knows,Frank,location,Miami,part_of,Dade,part_of,Florida,part_of,USA] 84 | ==>[Sam,location,Brighton,part_of,East Sussex,part_of,England] 85 | ==>[Eric,location,Austin,part_of,Travis,part_of,Texas,part_of,USA] 86 | ==>[Eric,knows,Pam,location,New York City,part_of,New York,part_of,USA] 87 | ==>[Frank,location,Miami,part_of,Dade,part_of,Florida,part_of,USA] 88 | ==>[Janet,location,Brighton,part_of,East Sussex,part_of,England] 89 | ==>[Marie,location,Canterbury,part_of,Kent,part_of,England] 90 | ==>[Mark,location,Miami,part_of,Dade,part_of,Florida,part_of,USA] 91 | ==>[Pam,location,New York City,part_of,New York,part_of,USA] 92 | ==>[Peter,location,Brighton,part_of,East Sussex,part_of,England] 93 | */ 94 | 95 | // Bill's friends in the USA 96 | g.V().has('name','Bill'). 97 | out('knows').as('friend'). 98 | repeat(out('location')). 99 | until(repeat(out('part_of')). 100 | emit(has('name','USA'))). 101 | path().from('friend').by('name') 102 | //[Frank,Miami] 103 | //[Eric,Austin] 104 | 105 | //Bill's friends in England 106 | g.V().has('name','Bill'). 107 | out('knows').as('friend'). 108 | repeat(out('location')). 109 | until(repeat(out('part_of')). 110 | emit(has('name','England'))). 111 | path().from('friend').by('name') 112 | //[Sam,Brighton] 113 | //[Amy,Canterbury] 114 | 115 | // We could get the same result using a where step but only because 116 | // we have a fixed number of out steps before the where. 117 | g.V().has('name','Bill'). 118 | out('knows').as('friend'). 119 | out('location'). 120 | where(repeat(out('part_of')). 121 | emit(has('name','England'))). 122 | path().from('friend').by('name') 123 | //[Sam,Brighton] 124 | //[Amy,Canterbury] 125 | 126 | 127 | // This will not get us any results 128 | g.V().has('name','Bill'). 129 | out('knows').as('friend'). 130 | repeat(out('location'). 131 | where(repeat(out('part_of')). 132 | emit(has('name','England')))). 133 | path().from('friend').by('name') 134 | 135 | 136 | // Similar but without a nested repeat. 137 | // Notice the difference. We get the whole path back. 138 | g.V().has('name','Bill'). 139 | out('knows').as('friend'). 140 | out('location'). 141 | repeat(out('part_of')). 142 | emit(has('name','England')). 143 | path().from('friend').by('name') 144 | //[Amy,Canterbury,Kent,England] 145 | //[Sam,Brighton,East Sussex,England] 146 | 147 | 148 | -------------------------------------------------------------------------------- /sample-data/README-air-routes.txt: -------------------------------------------------------------------------------- 1 | Information about the Air Routes graph data set. 2 | 3 | These notes refer to the version of the data set used by the examples in the book. 4 | 5 | If you would like instead to work with the most recent version of the data please use 6 | the file called 'air-routes-latest.graphml.' 7 | 8 | Timestamp: Fri, 06 Oct 2017 11:28:40 -0500 9 | 10 | This file contains the following sections 11 | 1. Introduction 12 | 2. Some statistics about the graph 13 | 14 | 15 | 1. INTRODUCTION 16 | 17 | The graph provides a model of the world commercial airline route network. It 18 | remains a work in progress but I have tried to curate the data carefully. 19 | However,I do not doubt there are errors and omissions that remain. This is 20 | intended as a learning tool and not for actual travel planning purposes! If 21 | you spot any errors such as missing routes or routes that are no longer served, 22 | please do let me know. 23 | 24 | I have tried to verify that a connection between airports is only given if at 25 | least one commercial airline currently operates scheduled service between them. 26 | Given the dynamic nature of the airline industry where routes are added and 27 | removed on a weekly basis any graph such as this one is, invariably, out of 28 | date the day it is published. That said I have tried to keep the graph as up to 29 | date as I can. 30 | 31 | This graph only models airports and routes it does not attempt to model airlines 32 | or route frequency. For example, the graph can tell you that there is a route 33 | between LHR and JFK that at least one airline operates but not which airlines 34 | fly that route nor how many times a day the route is operated. That is an 35 | exercise for another day and for a bigger graph! The graph also does not 36 | currently contain any aircraft information. For the most part I have only 37 | included scheduled flights flown by commercial airlines. I have included a few 38 | unusual routes such as the flights from RAF Brize Norton to RAF Ascension Island 39 | continuing on to Mount Pleasant in the Falkland Islands as I believe this 40 | represents a significant route and is a sort of pseudo-scheduled flight. I do 41 | not include routes flown only by freight carriers like FedEx and UPS. I also 42 | have only mostly included airports with at least one route. There are a few 43 | exceptions such as St. Helena which is a new airport with service pending, but 44 | delayed, due to issues with wind shear. Where an airport has no flights but 45 | remains in the graph it is probably because it was served by commercial airlines 46 | at some point. It is also useful for people learning to search graphs to be able 47 | to query for orphan nodes so for that reason as well I have left them in the 48 | graph. 49 | 50 | All of this said, I believe, as a learning tool there is plenty in the graph to 51 | facilitate writing some interesting queries and if you are so inclined for 52 | producing nice visuals. I hope people have as much fun playing with the graph 53 | as I have had putting it together. 54 | 55 | Please do let me know of any mistakes you find or about airports and/or routes 56 | that are currently missing. I believe I have most of the airports from around 57 | the World that offer scheduled airline service included in the graph at this 58 | point. The one exception is about ten regional airports in China that I 59 | still need to add 60 | 61 | If you require more detailed information about the schema of the graph and 62 | it's overall demographic please see the comments at the top of the 63 | air-routes.graphml file. 64 | 65 | 66 | 2. SOME STATISTICS ABOUT THE GRAPH 67 | 68 | Air Routes Graph (v0.77, 2017-Oct-06) contains: 69 | 3,374 airports 70 | 43,400 routes 71 | 237 countries (and dependent areas) 72 | 7 continents 73 | 3,619 total nodes 74 | 50,148 total edges 75 | 76 | Additional observations: 77 | Longest route is between DOH and AKL (9,025 miles) 78 | Shortest route is between WRY and PPW (2 miles) 79 | Average route distance is 1,164.747 miles. 80 | Longest runway is 18,045ft (BPX) 81 | Shortest runway is 1,300ft (SAB) 82 | Furthest North is LYR (latitude: 78.2461013793945) 83 | Furthest South is USH (latitude: -54.8433) 84 | Furthest East is SVU (longitude: 179.341003418) 85 | Furthest West is TVU (longitude: -179.876998901) 86 | Closest to the Equator is MDK (latitude: 0.0226000007242) 87 | Closest to the Greenwich meridian is LDE (longitude: -0.006438999902457) 88 | Highest elevation is DCY (14,472 feet) 89 | Lowest elevation is GUW (-72 feet) 90 | Maximum airport node degree (routes in and out) is 544 (FRA) 91 | Country with the most airports: United States (579) 92 | Continent with the most airports: North America (978) 93 | Average degree (airport nodes) is 25.726 94 | Average degree (all nodes) is 25.856 95 | 96 | 97 | Here are the top 50 airports with the most routes 98 | 99 | POS ID CODE TOTAL DETAILS 100 | 101 | 1 52 FRA (544) out:272 in:272 102 | 2 70 AMS (541) out:269 in:272 103 | 3 161 IST (540) out:270 in:270 104 | 4 51 CDG (524) out:262 in:262 105 | 5 80 MUC (474) out:237 in:237 106 | 6 64 PEK (469) out:234 in:235 107 | 7 18 ORD (464) out:232 in:232 108 | 8 1 ATL (464) out:232 in:232 109 | 9 58 DXB (458) out:229 in:229 110 | 10 8 DFW (442) out:221 in:221 111 | 11 102 DME (428) out:214 in:214 112 | 12 67 PVG (402) out:201 in:201 113 | 13 50 LGW (400) out:200 in:200 114 | 14 13 LAX (390) out:195 in:195 115 | 15 74 MAD (384) out:192 in:192 116 | 16 11 IAH (384) out:192 in:192 117 | 17 49 LHR (382) out:191 in:191 118 | 18 73 BCN (380) out:190 in:190 119 | 19 68 FCO (378) out:189 in:189 120 | 20 31 DEN (376) out:188 in:188 121 | 21 12 JFK (373) out:187 in:186 122 | 22 94 STN (372) out:186 in:186 123 | 23 35 EWR (364) out:182 in:182 124 | 24 84 MAN (363) out:182 in:181 125 | 25 47 YYZ (362) out:181 in:181 126 | 26 79 BRU (360) out:180 in:180 127 | 27 16 MIA (342) out:171 in:171 128 | 28 178 CLT (336) out:168 in:168 129 | 29 198 DUS (332) out:166 in:166 130 | 30 60 DUB (330) out:165 in:165 131 | 31 250 CAN (327) out:164 in:163 132 | 32 106 DOH (326) out:163 in:163 133 | 33 75 VIE (324) out:162 in:162 134 | 34 103 SVO (312) out:156 in:156 135 | 35 76 ZRH (304) out:152 in:152 136 | 36 61 HKG (302) out:151 in:151 137 | 37 56 SIN (292) out:146 in:146 138 | 38 177 CPH (290) out:145 in:145 139 | 39 30 LAS (290) out:145 in:145 140 | 40 122 ICN (288) out:144 in:144 141 | 41 17 MSP (288) out:144 in:144 142 | 42 230 PMI (286) out:143 in:143 143 | 43 93 ARN (286) out:143 in:143 144 | 44 9 FLL (284) out:142 in:142 145 | 45 23 SFO (282) out:141 in:141 146 | 46 46 DTW (274) out:137 in:137 147 | 47 10 IAD (272) out:136 in:136 148 | 48 346 LED (266) out:133 in:133 149 | 49 101 BKK (264) out:132 in:132 150 | 50 5 BOS (260) out:130 in:130 151 | 152 | 153 | -------------------------------------------------------------------------------- /sample-code/RemoteStats.java: -------------------------------------------------------------------------------- 1 | // RemoteStats.java 2 | // 3 | // Simple example of using GremlinServer from a Java client 4 | // This code performs the same queries that GraphStats.java does 5 | // but to a remote endpoint rather than a local in-memory graph. 6 | // 7 | // This example does the following: 8 | // 1. Configure a new Cluster object 9 | // 2. Use that cluster to connect to a Gremlin Server 10 | // 3. Generate some interesting statistics about the data in the graph. 11 | 12 | import org.apache.tinkerpop.gremlin.driver.Cluster; 13 | import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection; 14 | import org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0; 15 | import org.apache.tinkerpop.gremlin.process.traversal.*; 16 | import org.apache.tinkerpop.gremlin.process.traversal.Path; 17 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 18 | import org.apache.tinkerpop.gremlin.structure.Edge; 19 | import org.apache.tinkerpop.gremlin.structure.T; 20 | import org.apache.tinkerpop.gremlin.structure.Vertex; 21 | import org.apache.tinkerpop.gremlin.structure.io.IoCore; 22 | import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; 23 | import java.util.Map; 24 | import java.util.List; 25 | import java.util.ArrayList; 26 | 27 | // Using a static import avoids needing to use the "__." prefix as in "__.out()" 28 | import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.*; 29 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; 30 | 31 | public class RemoteStats 32 | { 33 | public static void main( String[] args ) 34 | { 35 | Cluster.Builder builder = Cluster.build(); 36 | builder.addContactPoint("localhost"); 37 | builder.port(8182); 38 | builder.serializer(new GryoMessageSerializerV1d0()); 39 | 40 | Cluster cluster = builder.create(); 41 | 42 | GraphTraversalSource g = 43 | EmptyGraph.instance().traversal(). 44 | withRemote(DriverRemoteConnection.using(cluster)); 45 | 46 | // Run some queries and display a few statistics 47 | 48 | System.out.println("Collecting stats"); 49 | 50 | System.out.println("\nDistribution of vertices and edges"); 51 | System.out.println("----------------------------------"); 52 | 53 | // Display some basic demographics 54 | // Note that label has to be prefixed by "T." 55 | Map verts = g.V().groupCount().by(T.label).next(); 56 | Map edges = g.E().groupCount().by(T.label).next(); 57 | System.out.println("Vertices : " + verts); 58 | System.out.println("Edges : " + edges); 59 | 60 | // Find the airport with the most overall routes. 61 | Map most = g.V().hasLabel("airport"). 62 | order().by(bothE("route").count(),Order.decr).limit(1). 63 | project("ap","num","city").by("code").by(bothE("route").count()). 64 | by("city").next(); 65 | 66 | String s = "" + most.get("ap") + "/" + most.get("city"); 67 | Long r = (Long) most.get("num"); 68 | System.out.println("\nThe airport with the most routes is " + s + " with " + r + " routes") ; 69 | 70 | 71 | // Find the airports with the most routes overall (incoming + outgoing) 72 | 73 | System.out.println("\nTop 20 airports by total routes"); 74 | System.out.println("==============================="); 75 | 76 | List> top = 77 | g.V().hasLabel("airport"). 78 | order().by(both("route").count(),Order.decr).limit(20). 79 | project("ap","num","city").by("code").by(both("route").count()).by("city"). 80 | toList(); 81 | 82 | // Either of these can be used 83 | //for(Map a: top) { System.out.format("%4s %12s %4d\n",a.get("ap"),a.get("city"), a.get("num"));} 84 | top.forEach((a) -> System.out.format("%4s %12s %4d\n",a.get("ap"),a.get("city"),a.get("num"))); 85 | 86 | 87 | 88 | // Find the airports with the most outgoing routes 89 | 90 | System.out.println("\nTop 20 airports by outgoing routes"); 91 | System.out.println("=================================="); 92 | 93 | List> topout = 94 | g.V().hasLabel("airport"). 95 | order().by(out("route").count(),Order.decr).limit(20). 96 | project("ap","num","city").by("code").by(out("route").count()).by("city"). 97 | toList(); 98 | 99 | topout.forEach((a) -> System.out.format("%4s %12s %4d\n",a.get("ap"),a.get("city"),a.get("num"))); 100 | 101 | // Find the airports with the most incoming routes 102 | 103 | System.out.println("\nTop 20 airports by incoming routes"); 104 | System.out.println("=================================="); 105 | 106 | List> topin = 107 | g.V().hasLabel("airport"). 108 | order().by(in("route").count(),Order.decr).limit(20). 109 | project("ap","num","city").by("code").by(in("route").count()).by("city"). 110 | toList(); 111 | 112 | topin.forEach((a) -> System.out.format("%4s %12s %4d\n",a.get("ap"),a.get("city"),a.get("num"))); 113 | 114 | 115 | // Find the longest route in the graph 116 | 117 | Map longroute = 118 | g.E().hasLabel("route"). 119 | order().by("dist",Order.decr).limit(1). 120 | project("from","to","num"). 121 | by(inV().values("city")).by(outV().values("city")).by("dist").next(); 122 | 123 | System.out.println("\nThe longest route in the graph is " + longroute.get("num") + 124 | " miles between " + longroute.get("from") + " and " + longroute.get("to")); 125 | 126 | // Find the longest runway in the graph 127 | 128 | Map longest = 129 | g.V().hasLabel("airport").order().by("longest",Order.decr).limit(1). 130 | project("ap","num","city").by("code").by("longest").by("city").next(); 131 | 132 | System.out.println("The longest runway in the graph is " + longest.get("num") + " feet at " + 133 | longest.get("city") + "/" + longest.get("ap")); 134 | 135 | 136 | // Find the continent with the most airports 137 | 138 | Map cmost; 139 | 140 | cmost = g.V().hasLabel("continent"). 141 | order().by(out("contains").count(),Order.decr).limit(1). 142 | project("num","cont"). 143 | by(out("contains").count()). 144 | by("desc").next(); 145 | 146 | System.out.println("The continent with the most airports: " + 147 | cmost.get("cont") + " (" + 148 | cmost.get("num") +")"); 149 | 150 | 151 | // Find the country with the most airports 152 | 153 | cmost = g.V().hasLabel("country"). 154 | order().by(out("contains").count(),Order.decr).limit(1). 155 | project("num","country"). 156 | by(out("contains").count()). 157 | by("desc").next(); 158 | 159 | System.out.println("The country with the most airports: " + 160 | cmost.get("country") + " (" + 161 | cmost.get("num") +")"); 162 | 163 | cluster.close(); 164 | } 165 | } 166 | 167 | -------------------------------------------------------------------------------- /sample-code/GraphStats.java: -------------------------------------------------------------------------------- 1 | // GraphStats.java 2 | // 3 | // Simple example of using TinkerGraph with Java 4 | // 5 | // This example does the following: 6 | // 1. Create a TinkerGraph instance 7 | // 2. Load the air routes graph 8 | // 3. Display some statistics about the graph 9 | 10 | // I have highlighted the places where the Gremlin is slightly different from the 11 | // Gremlin we can use in the Gremlin Console. 12 | 13 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; 14 | import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; 15 | import org.apache.tinkerpop.gremlin.process.traversal.Path; 16 | import org.apache.tinkerpop.gremlin.process.traversal.*; 17 | import org.apache.tinkerpop.gremlin.structure.Edge; 18 | import org.apache.tinkerpop.gremlin.structure.Vertex; 19 | import org.apache.tinkerpop.gremlin.structure.io.IoCore; 20 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.*; 21 | import org.apache.tinkerpop.gremlin.structure.T; 22 | import java.io.IOException; 23 | import java.util.List; 24 | import java.util.ArrayList; 25 | import java.util.Map; 26 | import java.util.Set; 27 | 28 | public class GraphStats 29 | { 30 | public static void main(String[] args) 31 | { 32 | // Create a new TinkerGraph and try to load the air-routes graph 33 | TinkerGraph tg = TinkerGraph.open() ; 34 | 35 | System.out.println("\nOpening air-routes.graphml"); 36 | 37 | try 38 | { 39 | tg.io(IoCore.graphml()).readGraph("air-routes.graphml"); 40 | } 41 | catch( IOException e ) 42 | { 43 | System.out.println("GraphStats - Air routes GraphML file not found"); 44 | System.exit(1); 45 | } 46 | GraphTraversalSource g = tg.traversal(); 47 | 48 | // Run some queries and display a few statistics 49 | 50 | System.out.println("Collecting stats"); 51 | 52 | System.out.println("\nDistribution of vertices and edges"); 53 | System.out.println("----------------------------------"); 54 | 55 | // Display some basic demographics 56 | // Note that label has to be prefixed by "T." 57 | Map verts = g.V().groupCount().by(T.label).next(); 58 | Map edges = g.E().groupCount().by(T.label).next(); 59 | System.out.println("Vertices : " + verts); 60 | System.out.println("Edges : " + edges); 61 | 62 | // Find the airport with the most overall routes. 63 | // Note that we have to use the "__." prefix for some steps and that "decr" 64 | // has to be prefixed by "Order". 65 | Map most = g.V().hasLabel("airport"). 66 | order().by(__.bothE("route").count(),Order.decr).limit(1). 67 | project("ap","num","city").by("code").by(__.bothE("route").count()). 68 | by("city").next(); 69 | 70 | String s = "" + most.get("ap") + "/" + most.get("city"); 71 | Long r = (Long) most.get("num"); 72 | System.out.println("\nThe airport with the most routes is " + s + " with " + r + " routes") ; 73 | 74 | 75 | 76 | // Find the airports with the most routes overall (incoming + outgoing) 77 | 78 | System.out.println("\nTop 20 airports by total routes"); 79 | System.out.println("==============================="); 80 | 81 | List> top = 82 | g.V().hasLabel("airport"). 83 | order().by(__.both("route").count(),Order.decr).limit(20). 84 | project("ap","num","city").by("code").by(__.both("route").count()).by("city"). 85 | toList(); 86 | 87 | // Either of these can be used 88 | //for(Map a: top) { System.out.format("%4s %12s %4d\n",a.get("ap"),a.get("city"), a.get("num"));} 89 | top.forEach((a) -> System.out.format("%4s %12s %4d\n",a.get("ap"),a.get("city"),a.get("num"))); 90 | 91 | 92 | 93 | // Find the airports with the most outgoing routes 94 | 95 | System.out.println("\nTop 20 airports by outgoing routes"); 96 | System.out.println("=================================="); 97 | 98 | List> topout = 99 | g.V().hasLabel("airport"). 100 | order().by(__.out("route").count(),Order.decr).limit(20). 101 | project("ap","num","city").by("code").by(__.out("route").count()).by("city"). 102 | toList(); 103 | 104 | topout.forEach((a) -> System.out.format("%4s %12s %4d\n",a.get("ap"),a.get("city"),a.get("num"))); 105 | 106 | // Find the airports with the most incoming routes 107 | 108 | System.out.println("\nTop 20 airports by incoming routes"); 109 | System.out.println("=================================="); 110 | 111 | List> topin = 112 | g.V().hasLabel("airport"). 113 | order().by(__.in("route").count(),Order.decr).limit(20). 114 | project("ap","num","city").by("code").by(__.in("route").count()).by("city"). 115 | toList(); 116 | 117 | topin.forEach((a) -> System.out.format("%4s %12s %4d\n",a.get("ap"),a.get("city"),a.get("num"))); 118 | 119 | 120 | // Find the longest route in the graph 121 | 122 | Map longroute = 123 | g.E().hasLabel("route"). 124 | order().by("dist",Order.decr).limit(1). 125 | project("from","to","num"). 126 | by(__.inV().values("city")).by(__.outV().values("city")).by("dist").next(); 127 | 128 | System.out.println("\nThe longest route in the graph is " + longroute.get("num") + 129 | " miles between " + longroute.get("from") + " and " + longroute.get("to")); 130 | 131 | // Find the longest runway in the graph 132 | 133 | Map longest = 134 | g.V().hasLabel("airport").order().by("longest",Order.decr).limit(1). 135 | project("ap","num","city").by("code").by("longest").by("city").next(); 136 | 137 | System.out.println("The longest runway in the graph is " + longest.get("num") + " feet at " + 138 | longest.get("city") + "/" + longest.get("ap")); 139 | 140 | 141 | // Find the continent with the most airports 142 | 143 | Map cmost; 144 | 145 | cmost = g.V().hasLabel("continent"). 146 | order().by(__.out("contains").count(),Order.decr).limit(1). 147 | project("num","cont"). 148 | by(__.out("contains").count()). 149 | by("desc").next(); 150 | 151 | System.out.println("The continent with the most airports: " + 152 | cmost.get("cont") + " (" + 153 | cmost.get("num") +")"); 154 | 155 | 156 | // Find the country with the most airports 157 | 158 | cmost = g.V().hasLabel("country"). 159 | order().by(__.out("contains").count(),Order.decr).limit(1). 160 | project("num","country"). 161 | by(__.out("contains").count()). 162 | by("desc").next(); 163 | 164 | System.out.println("The country with the most airports: " + 165 | cmost.get("country") + " (" + 166 | cmost.get("num") +")"); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /sample-code/janus-cassandra.groovy: -------------------------------------------------------------------------------- 1 | ;[]// Create a Janus Graph instance and connect it to a Cassandra back end. Next 2 | ;[]// define the schema and index and load air-routes graph data. This is 3 | ;[]// intended to be loaded and run inside the Gremlin Console from the Janus 4 | ;[]// Graph download. Usage :load janus-cassandra.groovy 5 | ;[]// Note that the ;[] is used purely to stop unwanted console output. 6 | 7 | println "\n==============================================";[] 8 | println "Creating Cassandra backed Janus Graph instance";[] 9 | println "==============================================\n";[] 10 | ;[]// Create a new graph instance 11 | ;[]// Use the following line to use CQL 12 | ;[]//graph = JanusGraphFactory.open('conf/janusgraph-cql.properties') 13 | 14 | ;[]// Use the following line to use Thrift. Thrift is disabled by default but 15 | ;[]// can be enabled using Nodetool or using the CASSANDRA_START_RPC=true 16 | ;[]// environment variable. 17 | graph = JanusGraphFactory.open('conf/janusgraph-cassandra.properties') 18 | println "\n===============";[] 19 | println "Defining labels";[] 20 | println "===============\n";[] 21 | ;[]// Define edge labels and usage 22 | mgmt = graph.openManagement() 23 | mgmt.makeEdgeLabel('route').multiplicity(MULTI).make() 24 | mgmt.makeEdgeLabel('contains').multiplicity(SIMPLE).make() 25 | 26 | ;[]// Define vertex labels 27 | mgmt.makeVertexLabel('version').make() 28 | mgmt.makeVertexLabel('airport').make() 29 | mgmt.makeVertexLabel('country').make() 30 | mgmt.makeVertexLabel('continent').make() 31 | 32 | println "\n=============";[] 33 | println "Creating keys";[] 34 | println "=============\n";[] 35 | ;[]// Define vertex property keys 36 | mgmt.makePropertyKey('code').dataType(String.class).cardinality(Cardinality.SINGLE).make() 37 | mgmt.makePropertyKey('icao').dataType(String.class).cardinality(Cardinality.SINGLE).make() 38 | mgmt.makePropertyKey('type').dataType(String.class).cardinality(Cardinality.SINGLE).make() 39 | mgmt.makePropertyKey('city').dataType(String.class).cardinality(Cardinality.SINGLE).make() 40 | mgmt.makePropertyKey('country').dataType(String.class).cardinality(Cardinality.SINGLE).make() 41 | mgmt.makePropertyKey('region').dataType(String.class).cardinality(Cardinality.SINGLE).make() 42 | mgmt.makePropertyKey('desc').dataType(String.class).cardinality(Cardinality.SINGLE).make() 43 | mgmt.makePropertyKey('runways').dataType(Integer.class).cardinality(Cardinality.SINGLE).make() 44 | mgmt.makePropertyKey('elev').dataType(Integer.class).cardinality(Cardinality.SINGLE).make() 45 | mgmt.makePropertyKey('lat').dataType(Double.class).cardinality(Cardinality.SINGLE).make() 46 | mgmt.makePropertyKey('lon').dataType(Double.class).cardinality(Cardinality.SINGLE).make() 47 | 48 | ;[]// Define edge property keys 49 | mgmt.makePropertyKey('dist').dataType(Integer.class).cardinality(Cardinality.SINGLE).make() 50 | 51 | println "\n==============";[] 52 | println "Building index";[] 53 | println "==============\n";[] 54 | 55 | ;[]// Construct a composite index for a few commonly used property keys 56 | graph.tx().rollback();[] 57 | 58 | idx1 = mgmt.buildIndex('airportIndex',Vertex.class) 59 | idx2 = mgmt.buildIndex('icaoIndex',Vertex.class) 60 | idx3 = mgmt.buildIndex('cityIndex',Vertex.class) 61 | idx4 = mgmt.buildIndex('runwayIndex',Vertex.class) 62 | idx5 = mgmt.buildIndex('countryIndex',Vertex.class) 63 | idx6 = mgmt.buildIndex('regionIndex',Vertex.class) 64 | idx7 = mgmt.buildIndex('typeIndex',Vertex.class) 65 | idx8 = mgmt.buildIndex('distIndex',Edge.class) 66 | 67 | iata = mgmt.getPropertyKey('code') 68 | icao = mgmt.getPropertyKey('icao') 69 | city = mgmt.getPropertyKey('city') 70 | rway = mgmt.getPropertyKey('runways') 71 | ctry = mgmt.getPropertyKey('country') 72 | regn = mgmt.getPropertyKey('region') 73 | type = mgmt.getPropertyKey('type') 74 | dist = mgmt.getPropertyKey('dist') 75 | 76 | idx1.addKey(iata).buildCompositeIndex() 77 | idx2.addKey(icao).buildCompositeIndex() 78 | idx3.addKey(city).buildCompositeIndex() 79 | idx4.addKey(rway).buildCompositeIndex() 80 | idx5.addKey(ctry).buildCompositeIndex() 81 | idx6.addKey(regn).buildCompositeIndex() 82 | idx7.addKey(type).buildCompositeIndex() 83 | idx8.addKey(dist).buildCompositeIndex() 84 | 85 | println "\n==================";[] 86 | println "Committing changes";[] 87 | println "==================\n";[] 88 | mgmt.commit() 89 | 90 | 91 | println "\n=================================";[] 92 | println "Waiting for the index to be ready";[] 93 | println "=================================\n";[] 94 | 95 | mgmt.awaitGraphIndexStatus(graph, 'airportIndex'). 96 | status(SchemaStatus.REGISTERED,SchemaStatus.ENABLED).call() 97 | 98 | mgmt.awaitGraphIndexStatus(graph, 'icaoIndex'). 99 | status(SchemaStatus.REGISTERED,SchemaStatus.ENABLED).call() 100 | 101 | mgmt.awaitGraphIndexStatus(graph, 'cityIndex'). 102 | status(SchemaStatus.REGISTERED,SchemaStatus.ENABLED).call() 103 | 104 | mgmt.awaitGraphIndexStatus(graph, 'runwayIndex'). 105 | status(SchemaStatus.REGISTERED,SchemaStatus.ENABLED).call() 106 | 107 | mgmt.awaitGraphIndexStatus(graph, 'countryIndex'). 108 | status(SchemaStatus.REGISTERED,SchemaStatus.ENABLED).call() 109 | 110 | mgmt.awaitGraphIndexStatus(graph, 'regionIndex'). 111 | status(SchemaStatus.REGISTERED,SchemaStatus.ENABLED).call() 112 | 113 | mgmt.awaitGraphIndexStatus(graph, 'typeIndex'). 114 | status(SchemaStatus.REGISTERED,SchemaStatus.ENABLED).call() 115 | 116 | mgmt.awaitGraphIndexStatus(graph, 'distIndex'). 117 | status(SchemaStatus.REGISTERED,SchemaStatus.ENABLED).call() 118 | 119 | 120 | ;[]// Load the air-routes graph and display a few statistics. 121 | ;[]// Not all of these steps use the index so Janus Graph will give us some warnings. 122 | println "\n========================";[] 123 | println "Loading air-routes graph";[] 124 | println "========================\n";[] 125 | graph.io(graphml()).readGraph('air-routes.graphml') 126 | graph.tx().commit() 127 | 128 | println "\n==========================";[] 129 | println "Acquiring traversal source";[] 130 | println "==========================\n";[] 131 | ;[]// Setup our traversal source object 132 | g = graph.traversal() 133 | 134 | println "\n==========================";[] 135 | println "Preparing graph statistics";[] 136 | println "==========================\n";[] 137 | // Display a few statistics 138 | apt = g.V().has('type','airport').count().next();[] 139 | cty = g.V().has('type','country').count().next();[] 140 | cnt = g.V().has('type','continent').count().next();[] 141 | rts = g.E().hasLabel('route').count().next();[] 142 | edg = g.E().count().next();[] 143 | 144 | println "Airports : $apt";[] 145 | println "Countries : $cty";[] 146 | println "Continents : $cnt";[] 147 | println "Routes : $rts";[] 148 | println "Edges : $edg";[] 149 | 150 | ;[]// Look at the properties, just as an example of how to do it! 151 | println "\n========================";[] 152 | println "Retrieving property keys";[] 153 | println "========================\n";[] 154 | mgmt = graph.openManagement();[] 155 | types = mgmt.getRelationTypes(PropertyKey.class);[] 156 | types.each{println "$it\t: " + mgmt.getPropertyKey("$it").dataType() + " " + mgmt.getPropertyKey("$it").cardinality()};[] 157 | mgmt.commit();[] 158 | 159 | 160 | ;[]// Query the indexes we created as an example of how to do it! 161 | println "\n==================";[] 162 | println "Retrieving indexes";[] 163 | println "==================\n";[] 164 | mgmt = graph.openManagement();[] 165 | v_idxes = mgmt.getGraphIndexes(Vertex.class);[] 166 | e_idxes = mgmt.getGraphIndexes(Edge.class);[] 167 | v_idxes.each {println "Name: ${it.name()}, Keys: ${it.getFieldKeys()}, Composite: ${it.isCompositeIndex()}, Backing: ${it.getBackingIndex()}"};[] 168 | e_idxes.each {println "Name: ${it.name()}, Keys: ${it.getFieldKeys()}, Composite: ${it.isCompositeIndex()}, Backing: ${it.getBackingIndex()}"};[] 169 | mgmt.commit();[] 170 | 171 | 172 | println "\n===============";[] 173 | println "Tasks completed";[] 174 | println "===============\n";[] 175 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /sample-code/janus-inmemory.groovy: -------------------------------------------------------------------------------- 1 | // Create an in memory Janus Graph instance, define the schema and index and load air-routes. 2 | // This is intended to be loaded and run inside the Gremlin Console from the Janus 3 | // Graph download. Usage :load janus-inmemory.groovy 4 | 5 | println "\n=======================================";[] 6 | println "Creating in-memory Janus Graph instance";[] 7 | println "=======================================\n";[] 8 | // Create a new graph instance 9 | graph = JanusGraphFactory.open('inmemory') 10 | 11 | println "\n===============";[] 12 | println "Defining labels";[] 13 | println "===============\n";[] 14 | // Define edge labels and usage 15 | mgmt = graph.openManagement() 16 | mgmt.makeEdgeLabel('route').multiplicity(MULTI).make() 17 | mgmt.makeEdgeLabel('contains').multiplicity(SIMPLE).make() 18 | mgmt.commit() 19 | 20 | // Define vertex labels 21 | mgmt = graph.openManagement() 22 | mgmt.makeVertexLabel('version').make() 23 | mgmt.makeVertexLabel('airport').make() 24 | mgmt.makeVertexLabel('country').make() 25 | mgmt.makeVertexLabel('continent').make() 26 | mgmt.commit() 27 | 28 | println "\n=============";[] 29 | println "Creating keys";[] 30 | println "=============\n";[] 31 | // Define vertex property keys 32 | mgmt = graph.openManagement() 33 | mgmt.makePropertyKey('code').dataType(String.class).cardinality(Cardinality.SINGLE).make() 34 | mgmt.makePropertyKey('icao').dataType(String.class).cardinality(Cardinality.SINGLE).make() 35 | mgmt.makePropertyKey('type').dataType(String.class).cardinality(Cardinality.SINGLE).make() 36 | mgmt.makePropertyKey('city').dataType(String.class).cardinality(Cardinality.SINGLE).make() 37 | mgmt.makePropertyKey('country').dataType(String.class).cardinality(Cardinality.SINGLE).make() 38 | mgmt.makePropertyKey('region').dataType(String.class).cardinality(Cardinality.SINGLE).make() 39 | mgmt.makePropertyKey('desc').dataType(String.class).cardinality(Cardinality.SINGLE).make() 40 | mgmt.makePropertyKey('runways').dataType(Integer.class).cardinality(Cardinality.SINGLE).make() 41 | mgmt.makePropertyKey('elev').dataType(Integer.class).cardinality(Cardinality.SINGLE).make() 42 | mgmt.makePropertyKey('lat').dataType(Double.class).cardinality(Cardinality.SINGLE).make() 43 | mgmt.makePropertyKey('lon').dataType(Double.class).cardinality(Cardinality.SINGLE).make() 44 | mgmt.commit() 45 | 46 | // Define edge property keys 47 | mgmt = graph.openManagement() 48 | mgmt.makePropertyKey('dist').dataType(Integer.class).cardinality(Cardinality.SINGLE).make() 49 | mgmt.commit() 50 | 51 | println "\n==============";[] 52 | println "Building index";[] 53 | println "==============\n";[] 54 | 55 | // Construct a composite index for a few commonly used property keys 56 | graph.tx().rollback() 57 | mgmt=graph.openManagement() 58 | 59 | idx1 = mgmt.buildIndex('airportIndex',Vertex.class) 60 | idx2 = mgmt.buildIndex('icaoIndex',Vertex.class) 61 | idx3 = mgmt.buildIndex('cityIndex',Vertex.class) 62 | idx4 = mgmt.buildIndex('runwayIndex',Vertex.class) 63 | idx5 = mgmt.buildIndex('countryIndex',Vertex.class) 64 | idx6 = mgmt.buildIndex('regionIndex',Vertex.class) 65 | idx7 = mgmt.buildIndex('typeIndex',Vertex.class) 66 | idx8 = mgmt.buildIndex('distIndex',Edge.class) 67 | 68 | iata = mgmt.getPropertyKey('code') 69 | icao = mgmt.getPropertyKey('icao') 70 | city = mgmt.getPropertyKey('city') 71 | rway = mgmt.getPropertyKey('runways') 72 | ctry = mgmt.getPropertyKey('country') 73 | regn = mgmt.getPropertyKey('region') 74 | type = mgmt.getPropertyKey('type') 75 | dist = mgmt.getPropertyKey('dist') 76 | 77 | idx1.addKey(iata).buildCompositeIndex() 78 | idx2.addKey(icao).buildCompositeIndex() 79 | idx3.addKey(city).buildCompositeIndex() 80 | idx4.addKey(rway).buildCompositeIndex() 81 | idx5.addKey(ctry).buildCompositeIndex() 82 | idx6.addKey(regn).buildCompositeIndex() 83 | idx7.addKey(type).buildCompositeIndex() 84 | idx8.addKey(dist).buildCompositeIndex() 85 | 86 | mgmt.commit() 87 | 88 | 89 | println "\n=================================";[] 90 | println "Waiting for the index to be ready";[] 91 | println "=================================\n";[] 92 | 93 | mgmt.awaitGraphIndexStatus(graph, 'airportIndex'). 94 | status(SchemaStatus.REGISTERED).call() 95 | 96 | mgmt.awaitGraphIndexStatus(graph, 'icaoIndex'). 97 | status(SchemaStatus.REGISTERED).call() 98 | 99 | mgmt.awaitGraphIndexStatus(graph, 'cityIndex'). 100 | status(SchemaStatus.REGISTERED).call() 101 | 102 | mgmt.awaitGraphIndexStatus(graph, 'runwayIndex'). 103 | status(SchemaStatus.REGISTERED).call() 104 | 105 | mgmt.awaitGraphIndexStatus(graph, 'countryIndex'). 106 | status(SchemaStatus.REGISTERED).call() 107 | 108 | mgmt.awaitGraphIndexStatus(graph, 'regionIndex'). 109 | status(SchemaStatus.REGISTERED).call() 110 | 111 | mgmt.awaitGraphIndexStatus(graph, 'typeIndex'). 112 | status(SchemaStatus.REGISTERED).call() 113 | 114 | mgmt.awaitGraphIndexStatus(graph, 'distIndex'). 115 | status(SchemaStatus.REGISTERED).call() 116 | 117 | // Once the index is created force a re-index Note that a reindex is not strictly 118 | // necessary here. It could be avoided by creating the keys and index as part of the 119 | // same transaction. I did it this way just to show an example of re-indexing being 120 | // done. A reindex is always necessary if the index is added after data has been 121 | // loaded into the graph. 122 | 123 | println "\n===========";[] 124 | println "re-indexing";[] 125 | println "===========\n";[] 126 | mgmt = graph.openManagement() 127 | 128 | mgmt.awaitGraphIndexStatus(graph, 'airportIndex').call() 129 | mgmt.updateIndex(mgmt.getGraphIndex('airportIndex'), SchemaAction.REINDEX).get() 130 | 131 | mgmt.awaitGraphIndexStatus(graph, 'icaoIndex').call() 132 | mgmt.updateIndex(mgmt.getGraphIndex('icaoIndex'), SchemaAction.REINDEX).get() 133 | 134 | mgmt.awaitGraphIndexStatus(graph, 'cityIndex').call() 135 | mgmt.updateIndex(mgmt.getGraphIndex('cityIndex'), SchemaAction.REINDEX).get() 136 | 137 | mgmt.awaitGraphIndexStatus(graph, 'runwayIndex').call() 138 | mgmt.updateIndex(mgmt.getGraphIndex('runwayIndex'), SchemaAction.REINDEX).get() 139 | 140 | mgmt.awaitGraphIndexStatus(graph, 'countryIndex').call() 141 | mgmt.updateIndex(mgmt.getGraphIndex('countryIndex'), SchemaAction.REINDEX).get() 142 | 143 | mgmt.awaitGraphIndexStatus(graph, 'regionIndex').call() 144 | mgmt.updateIndex(mgmt.getGraphIndex('regionIndex'), SchemaAction.REINDEX).get() 145 | 146 | mgmt.awaitGraphIndexStatus(graph, 'typeIndex').call() 147 | mgmt.updateIndex(mgmt.getGraphIndex('typeIndex'), SchemaAction.REINDEX).get() 148 | 149 | mgmt.awaitGraphIndexStatus(graph, 'distIndex').call() 150 | mgmt.updateIndex(mgmt.getGraphIndex('distIndex'), SchemaAction.REINDEX).get() 151 | 152 | mgmt.commit() 153 | 154 | // Load the air-routes graph and display a few statistics. 155 | // Not all of these steps use the index so Janus Graph will give us some warnings. 156 | println "\n========================";[] 157 | println "Loading air-routes graph";[] 158 | println "========================\n";[] 159 | graph.io(graphml()).readGraph('air-routes.graphml') 160 | graph.tx().commit();[] 161 | 162 | // Setup our traversal source object 163 | g = graph.traversal() 164 | 165 | // Display a few statistics 166 | apt = g.V().has('type','airport').count().next();[] 167 | cty = g.V().has('type','country').count().next();[] 168 | cnt = g.V().has('type','continent').count().next();[] 169 | rts = g.E().hasLabel('route').count().next();[] 170 | edg = g.E().count().next();[] 171 | 172 | println "Airports : $apt";[] 173 | println "Countries : $cty";[] 174 | println "Continents : $cnt";[] 175 | println "Routes : $rts";[] 176 | println "Edges : $edg";[] 177 | 178 | // Look at the properties, just as an exampl of how to do it! 179 | println "\n========================";[] 180 | println "Retrieving property keys";[] 181 | println "========================\n";[] 182 | mgmt = graph.openManagement() 183 | types = mgmt.getRelationTypes(PropertyKey.class);[] 184 | types.each{println "$it\t: " + mgmt.getPropertyKey("$it").dataType() + " " + mgmt.getPropertyKey("$it").cardinality()};[] 185 | mgmt.commit() 186 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /sample-data/README-air-routes-latest.txt: -------------------------------------------------------------------------------- 1 | Information about the Air Routes graph. 2 | 3 | Timestamp: Sat, 27 Apr 2019 10:03:59 -0500 4 | 5 | This file contains the following sections 6 | 1. Introduction 7 | 2. Some statistics about the graph 8 | 9 | The latest data set adds 63 additional airports and 5,838 additional routes to 10 | the original air-routes.graphml data set. The latest data set also incorporates 11 | updates such as the new Istanbul Airport opening. All distances have been 12 | updated of the location change. This update also corrects the number of runways 13 | at Chicago O'Hare (ORD) to 7 rather than the 8 previously used based on latest 14 | airport charts. 15 | 16 | 1. INTRODUCTION 17 | 18 | The graph provides a model of the world commercial airline route network. It 19 | remains a work in progress but I have tried to curate the data carefully. 20 | However,I do not doubt there are errors and omissions that remain. This is 21 | intended as a learning tool and not for actual travel planning purposes! If 22 | you spot any errors such as missing routes or routes that are no longer served, 23 | please do let me know. 24 | 25 | I have tried to verify that a connection between airports is only given if at 26 | least one commercial airline currently operates scheduled service between them. 27 | Given the dynamic nature of the airline industry where routes are added and 28 | removed on a weekly basis any graph such as this one is, invariably, out of 29 | date the day it is published. That said I have tried to keep the graph as up to 30 | date as I can. 31 | 32 | This graph only models airports and routes it does not attempt to model airlines 33 | or route frequency. For example, the graph can tell you that there is a route 34 | between LHR and JFK that at least one airline operates but not which airlines 35 | fly that route nor how many times a day the route is operated. That is an 36 | exercise for another day and for a bigger graph! The graph also does not 37 | currently contain any aircraft information. For the most part I have only 38 | included scheduled flights flown by commercial airlines. I have included a few 39 | unusual routes such as the flights from RAF Brize Norton to RAF Ascension Island 40 | continuing on to Mount Pleasant in the Falkland Islands as I believe this 41 | represents a significant route and is a sort of pseudo-scheduled flight. I do 42 | not include routes flown only by freight carriers like FedEx and UPS. I also 43 | have only mostly included airports with at least one route. There are a few 44 | exceptions such as St. Helena which is a new airport with service pending, but 45 | delayed, due to issues with wind shear. Where an airport has no flights but 46 | remains in the graph it is probably because it was served by commercial airlines 47 | at some point. It is also useful for people learning to search graphs to be able 48 | to query for orphan nodes so for that reason as well I have left them in the 49 | graph. 50 | 51 | All of this said, I believe, as a learning tool there is plenty in the graph to 52 | facilitate writing some interesting queries and if you are so inclined for 53 | producing nice visuals. I hope people have as much fun playing with the graph 54 | as I have had putting it together. 55 | 56 | Please do let me know of any mistakes you find or about airports and/or routes 57 | that are currently missing. I believe I have most of the airports from around 58 | the World that offer scheduled airline service included in the graph at this 59 | point. The one exception is about ten regional airports in China that I 60 | still need to add 61 | 62 | If you require more detailed information about the schema of the graph and 63 | it's overall demographic please see the comments at the top of the 64 | air-routes.graphml file. 65 | 66 | 67 | 2. SOME STATISTICS ABOUT THE GRAPH 68 | 69 | Air Routes Graph (v0.82, 2019-April-27th) contains: 70 | 3,437 airports 71 | 49,238 routes 72 | 237 countries (and dependent areas) 73 | 7 continents 74 | 3,682 total nodes 75 | 56,112 total edges 76 | 77 | Additional observations: 78 | Longest route is between SIN and EWR (9,523 miles) 79 | Shortest route is between WRY and PPW (2 miles) 80 | Average route distance is 1,204.759 miles. 81 | Longest runway is 18,045ft (BPX) 82 | Shortest runway is 1,300ft (SAB) 83 | Average number of runways is 1.42624 84 | Furthest North is LYR (latitude: 78.2461013793945) 85 | Furthest South is USH (latitude: -54.8433) 86 | Furthest East is SVU (longitude: 179.341003418) 87 | Furthest West is TVU (longitude: -179.876998901) 88 | Closest to the Equator is MDK (latitude: 0.0226000007242) 89 | Closest to the Greenwich meridian is LDE (longitude: -0.006438999902457) 90 | Highest elevation is DCY (14,472 feet) 91 | Lowest elevation is GUW (-72 feet) 92 | Maximum airport node degree (routes in and out) is 612 (FRA) 93 | Country with the most airports: United States (582) 94 | Continent with the most airports: North America (983) 95 | Average degree (airport nodes) is 28.652 96 | Average degree (all nodes) is 28.620 97 | 98 | 99 | Here are the top 50 airports with the most routes 100 | 101 | POS ID CODE TOTAL DETAILS 102 | 103 | 1 52 FRA (612) out:306 in:306 104 | 2 161 IST (608) out:304 in:304 105 | 3 51 CDG (580) out:290 in:290 106 | 4 70 AMS (559) out:278 in:281 107 | 5 80 MUC (530) out:265 in:265 108 | 6 18 ORD (507) out:254 in:253 109 | 7 64 PEK (493) out:246 in:247 110 | 8 58 DXB (490) out:245 in:245 111 | 9 8 DFW (484) out:242 in:242 112 | 10 1 ATL (482) out:241 in:241 113 | 11 50 LGW (456) out:228 in:228 114 | 12 102 DME (454) out:227 in:227 115 | 13 49 LHR (434) out:217 in:217 116 | 14 13 LAX (424) out:212 in:212 117 | 15 67 PVG (418) out:209 in:209 118 | 16 31 DEN (417) out:209 in:208 119 | 17 94 STN (416) out:208 in:208 120 | 18 84 MAN (415) out:208 in:207 121 | 19 74 MAD (414) out:207 in:207 122 | 20 73 BCN (404) out:202 in:202 123 | 21 12 JFK (401) out:201 in:200 124 | 22 68 FCO (400) out:200 in:200 125 | 23 75 VIE (398) out:199 in:199 126 | 24 11 IAH (392) out:196 in:196 127 | 25 47 YYZ (390) out:195 in:195 128 | 26 198 DUS (386) out:193 in:193 129 | 27 16 MIA (386) out:193 in:193 130 | 28 79 BRU (384) out:192 in:192 131 | 29 35 EWR (384) out:192 in:192 132 | 30 177 CPH (380) out:190 in:190 133 | 31 106 DOH (366) out:183 in:183 134 | 32 103 SVO (362) out:181 in:181 135 | 33 178 CLT (358) out:179 in:179 136 | 34 60 DUB (358) out:179 in:179 137 | 35 76 ZRH (356) out:178 in:178 138 | 36 61 HKG (346) out:173 in:173 139 | 37 250 CAN (342) out:172 in:170 140 | 38 122 ICN (336) out:168 in:168 141 | 39 93 ARN (334) out:167 in:167 142 | 40 56 SIN (332) out:166 in:166 143 | 41 15 MCO (318) out:159 in:159 144 | 42 30 LAS (314) out:157 in:157 145 | 43 9 FLL (314) out:157 in:157 146 | 44 346 LED (310) out:155 in:155 147 | 45 17 MSP (308) out:154 in:154 148 | 46 230 PMI (304) out:152 in:152 149 | 47 101 BKK (304) out:152 in:152 150 | 48 110 ATH (303) out:152 in:151 151 | 49 23 SFO (303) out:151 in:152 152 | 50 200 TXL (302) out:152 in:150 153 | 154 | 155 | Here are the longest routes currently in the graph 156 | 157 | 60 route(s) 158 | SIN->EWR 9,523 159 | EWR->SIN 9,523 160 | DOH->AKL 9,025 161 | AKL->DOH 9,025 162 | PER->LHR 9,009 163 | LHR->PER 9,009 164 | PTY->PEK 8,884 165 | PEK->PTY 8,884 166 | DXB->AKL 8,818 167 | AKL->DXB 8,818 168 | SIN->LAX 8,756 169 | LAX->SIN 8,756 170 | MEX->CAN 8,754 171 | CAN->MEX 8,754 172 | SYD->IAH 8,591 173 | IAH->SYD 8,591 174 | SYD->DFW 8,574 175 | DFW->SYD 8,574 176 | MNL->JFK 8,504 177 | JFK->MNL 8,504 178 | JNB->ATL 8,434 179 | ATL->JNB 8,434 180 | SIN->SFO 8,433 181 | SFO->SIN 8,433 182 | LAX->AUH 8,372 183 | AUH->LAX 8,372 184 | LAX->DXB 8,321 185 | DXB->LAX 8,321 186 | LAX->JED 8,314 187 | JED->LAX 8,314 188 | LAX->DOH 8,287 189 | DOH->LAX 8,287 190 | RUH->LAX 8,246 191 | LAX->RUH 8,246 192 | TLV->SCL 8,208 193 | SCL->TLV 8,208 194 | YVR->MEL 8,197 195 | MEL->YVR 8,197 196 | ORD->AKL 8,186 197 | AKL->ORD 8,186 198 | IAH->DXB 8,150 199 | DXB->IAH 8,150 200 | SFO->AUH 8,139 201 | AUH->SFO 8,139 202 | IAD->HKG 8,135 203 | HKG->IAD 8,135 204 | HKG->DFW 8,105 205 | DFW->HKG 8,105 206 | SFO->DXB 8,085 207 | DXB->SFO 8,085 208 | JFK->HKG 8,054 209 | HKG->JFK 8,054 210 | DFW->AUH 8,053 211 | AUH->DFW 8,053 212 | HKG->EWR 8,047 213 | EWR->HKG 8,047 214 | IAH->DOH 8,030 215 | DOH->IAH 8,030 216 | DXB->DFW 8,022 217 | DFW->DXB 8,022 218 | 219 | 220 | 221 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Practical Gremlin: An Apache TinkerPop Tutorial 2 | 3 | 4 | ![map](https://github.com/krlawrence/graph/raw/master/images/GremlinEaselNoText.png?raw=true, "graph picture") 5 | 6 | ## Welcome! 7 | 8 | This repository is the new home for the source materials, sample code and examples for the book "Practical Gremlin - An Apache TinkerPop Tutorial" 9 | 10 | **Quick Start** 11 | 12 | To read the latest snapshot of the book right away in a browser (HTML format) click [here](http://kelvinlawrence.net/book/Gremlin-Graph-Guide.html) or for a PDF version click [here](http://kelvinlawrence.net/book/Gremlin-Graph-Guide.pdf). These snapshots are updated regularly. You will find other formats including MOBI, EPUB and XML (Docbook) in the [releases](https://github.com/krlawrence/graph/releases) section. Formal releases will be published periodically assuming there is enough new material to make it worthwhile. If you want to see the absolute latest updates you can always browse the Asciidoc source file (Gremlin-Graph-Guide.adoc) in the /book folder. The PDF version is currently the "official" version. It has a better table of contents, some better formatting and a much nicer title page! 13 | 14 | **LATEST NEWS:** 15 | 16 | [Apr-27-2019] Updated versions of the sample data and corresponding demo apps have been uploaded. 17 | [Dec-26-2018] Revision 281 (TP 3.3.4) was just published in all formats. See [change history](https://github.com/krlawrence/graph/blob/master/ChangeHistory.md) for details. 18 | 19 | ## Releases and change history 20 | 21 | The most recent changes and additions are now being tracked in the [change history](https://github.com/krlawrence/graph/blob/master/ChangeHistory.md) file. 22 | 23 | **A Special note about releases** 24 | 25 | Starting with revision 274 (Dec 24 2017), all of the output files (XML, EPUB, MOBI, HTML and PDF) will now be stored using Git releases. Going forward, this should reduce the amount of disk space required for people who create forks of this project. The release notes and dowloadable materials are located [here](https://github.com/krlawrence/graph/releases). 26 | 27 | NOTE: In order to prune the unwanted files from the project the commit history for the output files had to be removed as part of making the v274 release. If you had previously cloned or forked this project please create a new clone or fork. Sorry for the inconvenience but this will get you back approximately 60% (27+ mb) of the disk space that was being taken up and will help anyone else making a clone. 28 | 29 | 30 | Details of how to build the various output formats from the Asciidoc source are contained in the README.md under the *book* folder. 31 | 32 | ## How this book came to be 33 | 34 | I forget exactly when, but over a year ago I started compiling a list of notes, hints and tips, initially for my own benefit, of things I had found poorly explained elsewhere while using graph databases and especially using Apache TinkerPop, Janus Graph and Gremlin. Over time that document grew (and continues to grow) and has effectively become a book. After some encouragement from colleagues I have decided to release it as a living book in an open source venue so that anyone who is interested can read it. It is aimed at programmers and anyone using the Gremlin query language to work with graphs. Lots of code examples, sample queries, discussion of best practices, lessons I learned the hard way etc. are included. 35 | 36 | While this book remains a work in progress, indeed some sections are still to be filled in, I think there is enough here that people may find it a useful aid to learning the Gremlin graph traversal and query language. 37 | 38 | Thanks to all those that have encouraged me to keep going with this adventure! 39 | 40 | Kelvin R. Lawrence 41 | October 6th, 2017 42 | 43 | ## Introduction 44 | 45 | **This book is a work in progress. Feedback (ideally via issue) is very much encouraged and welcomed!** 46 | 47 | The title of this book could equally well be "A getting started guide for users of graph databases and the Gremlin query language featuring hints, tips and sample queries". It turns out that is a bit too too long to fit on one line for a heading but in a single sentence that describes the focus of this book pretty well. 48 | 49 | The book introduces the Apache TinkerPop 3 Gremlin graph query and traversal language via real examples against a real world graph. They are given as a set of working examples against a graph that is also provided in the sample-data folder. The graph, air-routes.graphml, is a model of the world airline route network between 3,367 airports including 43,160 routes. The examples we present will work unmodified with the air-routes.graphml file loaded into the Gremlin console running with a TinkerGraph. 50 | 51 | ## How this site is organized 52 | 53 | The book is being written using a text editor in AsciiDoc format. The source manuscript "Gremlin-Graph-Guide.adoc" can be found in the /book folder. This file will always reflect the most recent updates and will often be ahead of the other formats that will only be updated as part of a formal release. You will find formatted HTML and PDF versions of the book in the releases area. I have also provided DOCBOOK, EPUB and MOBI versions as part of each release. These can be viewed using many tools and e-book readers. Note that currently, only the HTML and PDF versions have all the nice colors for source code listings etc. 54 | 55 | Included with the book are sample graph data (GraphML) and program files. You will find these, as well as some screen shots and images, and demos in the following folders. 56 | 57 | - /book 58 | - /sample-data 59 | - /sample-code 60 | - /images 61 | - /demos 62 | 63 | ## How the book is organized 64 | 65 | Chapter 1 - INTRODUCTION 66 | - We start off by briefly doing a recap on why Graph databases are of interest to us 67 | and discuss some good use cases for graphs. 68 | 69 | Chapter 2 - GETTING STARTED 70 | - In Chapter 2 we introduce several of the components of Apache TinkerPop 3 and we 71 | also introduce the air-routes.graphml file that will be used as the graph we base 72 | most of our examples on. 73 | 74 | Chapter 3 - WRITING GREMLIN QUERIES 75 | - In Chapter 3 we start discussing how to use the Gremlin graph traversal and 76 | query language to interrogate the air-routes graph. We begin by comparing how we 77 | could have built the air-routes graph using a more traditional relational database 78 | and then look at how SQL and Gremlin are both similar in some ways and very 79 | different in others. For the rest of the Chapter, we introduce several of 80 | the key Gremlin methods, or as they are often called, "steps". We 81 | mostly focus on reading the graph (not adding or deleting things) in this Chapter. 82 | 83 | Chapter 4 - BEYOND BASIC QUERIES 84 | - In Chapter 4 we move beyond just reading the graph and describe how to add nodes, 85 | edges and properties as well as how to delete and update them. We also present a 86 | discussion of various best practices.We also start to explore some slightly more 87 | advanced topics in this chapter. 88 | 89 | Chapter 5 - MISCELLANEOUS QUERIES AND THE RESULTS THEY GENERATE 90 | - In Chapter 5 we focus on using what we have covered in the prior Chapters to write 91 | queries that have a more real world feel. We present a lot more examples of the 92 | output from running queries in this Chapter. We also start to discuss topics such 93 | as analyzing distances, route distribution and writing geospatial queries. 94 | 95 | Chapter 6 - MOVING BEYOND THE CONSOLE AND TINKERGRAPH 96 | - In Chapter 6 we move beyond our focus on the Gremlin Console and TinkerGraph. We 97 | start by looking at how you can write stand alone Java and Groovy applications that 98 | can work with a graph. We then introduce Janus Graph and take a fairly detailed 99 | look at its capabilities such as support for transactions, schemas and external 100 | indexes. We also explore various technology choices for back end persistent store 101 | and index as well as introducing the Gremlin Server. 102 | 103 | Chapter 7 - COMMON GRAPH SERIALIZATION FORMATS 104 | - In Chapter 7 We have provided a discussion of some common Graph serialization file 105 | formats along with a discussion of how to use them in the context of TinkerPop 3 106 | enabled graphs. 107 | 108 | Chapter 8 - FURTHER READING 109 | - We finish up by providing several links to useful web sites where you can find 110 | tools and documentation for many of the technologies covered in this document. 111 | 112 | **NEWS ARCHIVE:** 113 | 114 | [Dec-24-2018] Updated versions of the sample data and corresponding demo apps have been uploaded. 115 | [Sep-29-2018] Updated versions of the sample data and corresponding demo apps have been uploaded. 116 | [Jul-28-2018] Revision 280 (TP 3.3.3) was just published in all formats. See [change history](https://github.com/krlawrence/graph/blob/master/ChangeHistory.md) for details. 117 | [May-29-2018] Revision 279 (TP 3.3.3) was just published in all formats. See [change history](https://github.com/krlawrence/graph/blob/master/ChangeHistory.md) for details. 118 | [Mar-28-2018] Revision 278 (TP 3.3.1) was just published in all formats. See [change history](https://github.com/krlawrence/graph/blob/master/ChangeHistory.md) for details. 119 | [Feb-11-2018] Revision 277 was just published in all formats. See [change history](https://github.com/krlawrence/graph/blob/master/ChangeHistory.md) for details. 120 | [Jan-12-2018] Revision 276 was just published in all formats. Many updates to book and samples. 121 | [Jan-12-2018] Based on feedback I have decided to rename the book "Practical Gremlin" (see issue #29) 122 | [Jan-06-2018] Several new Java samples have been added to the sample-code directory and others improved. 123 | [Jan-03-2018] Revision 275 was just published in all formats. Lots of updates to book and sample code. 124 | [Dec-24-2017] Revision 274 was just published in all formats. Now using releases to store output files. 125 | [Dec-12-2017] Revision 273 was just published in all formats. Fixes issue #12. Also added additonal clarifications. 126 | [Nov-23-2017] Revision 272 was just published in all formats. Many updates to sections 3 and 4. 127 | [Nov-03-2017] Revision 271 was just published in all formats. Several improvements and additions. 128 | [Oct-27-2017] Revision 270 was just published in all formats. Fixes issue #6 and adds more to Janus section. 129 | [Oct-23-2017] Quite a lot has been added to the Janus Graph section - more to come soon 130 | [Oct-15-2017] Experimental - The /book folder now includes DOCBOOK, EPUB and MOBI format versions of the book. 131 | [Oct-10-2017] Several sections have been improved, I also made updates to reflect changes made in Tinkerpop 3.3 132 | --------------------------------------------------------------------------------