Loading
XN Logic Corporation
This is a live streamed presentation. You will automatically follow the presenter and see the slide they're currently on.
Brought to you by
Hands-on introduction to graph databases
Step 1: Install dependencies
$ gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
$ \curl -sSL https://get.rvm.io | bash -s stable
$ rvm install jruby
$ gem install pacer
Step 2: Start the IRB and load Pacer
$ irb
jruby-1.7.18 :001 > require 'pacer'
=> true
Step 3: Create a Graph
jruby-1.7.18 :002 > g = Pacer.tg()
=> #<PacerGraph tinkergraph[vertices:0 edges:0]
Windows users may want to try
jirb_swing
jruby-1.7.19 :003 > v1 = g.create_vertex()
=> #<V[0]>
jruby-1.7.19 :004 > v2 = g.create_vertex()
=> #<V[1]>
graph.create_vertex
vertex.add_edges_to
jruby-1.7.19 :005 > v1.add_edges_to(:likes, v2)
#<E[2]:0-likes-1>
Total: 1
=> #<Obj 1 ids -> lookup -> is_not(nil)>
jruby-1.7.18 :006 > v2.add_edges_to(:dislikes, v1)
#<E[3]:1-dislikes-0>
Total: 1
=> #<Obj 1 ids -> lookup -> is_not(nil)>
In most cases, you probably want to create elements with properties ...
alice = g.create_vertex({type: 'person', name: 'Alice'})
bob = g.create_vertex({type: 'person', name: 'Bob'})
post = g.create_vertex({type: 'post',
text: 'Learning about Pacer ...'})
alice.add_edges_to( :follows, bob, {since: Time.now})
bob.add_edges_to( :posted, post, {timestamp: Time.now})
alice.add_edges_to( :likes, post, {timestamp: Time.now})
graph.v
Get all vertices in the graph
jruby-1.7.18 :007 > g.v
#<V[0]> #<V[1]> #<V[2]>
Total: 3
=> #<GraphV>
graph.vertex
Get a specific vertex by its id
jruby-1.7.18 :008 > g.vertex(1)
=> #<V[1]>
graph.e
Get all edges in the graph
jruby-1.7.18 :009 > g.e
#<E[3]:0-follows-1> #<E[4]:1-posted-2> #<E[5]:0-likes-2>
Total: 3
=> #<GraphE>
graph.edge
Get a specific edge by its id
jruby-1.7.18 :010 > g.edge(4)
=> #<E[4]:1-posted-2>
Routes are collections/streams of elements.
return a Route object.
If you are not familiar with some of the terminology, don't worry, we will go into more details later.
For now, just think of routes as plain old collections.
graph.v / graph.e
g.v.first
Get the first element
Return value is a single element
g.e[2..4]
Get a range of elements
Return value is a collection/route of elements
g.v.each {|v| do_something_with(v)}
Go through the elements
By property value
jruby-1.7.18 :011 > g.v(type: 'person')
#<V[0]> #<V[1]>
Total: 2
=> #<GraphV -> V-Property(type=="person")>
jruby-1.7.18 :012 > g.e(:likes)
#<E[5]:0-likes-2>
Total: 1
=> #<GraphE -> E-Property(:likes)>
On, in the case of edges, by edge-label
some_vertex.out_e.in_v
some_vertex
some_vertex.out_e
some_vertex.in_e.out_v
some_vertex
some_vertex.in_e
out_e, in_e, both_e
jruby-1.7.18 :013 > bob = g.v(name: 'Bob').first
=> #<V[1]>
jruby-1.7.18 :014 > bob.out_e
#<E[4]:1-posted-2>
Total: 1
=> #<outE>
jruby-1.7.18 :015 > bob.in_e
#<E[3]:0-follows-1>
Total: 1
=> #<inE>
jruby-1.7.18 :016 > bob.both_e
#<E[3]:0-follows-1> #<E[4]:1-posted-2>
Total: 2
=> #<bothE>
out_e, in_e, both_e
jruby-1.7.18 :017 > g.v.out_e
#<E[3]:0-follows-1> #<E[5]:0-likes-2> #<E[4]:1-posted-2>
Total: 3
=> #<GraphV -> outE>
Can be called on a single element as well as a route
out_v, in_v, both_v
jruby-1.7.18 :018 > e = g.e.first
=> #<E[3]:0-follows-1>
jruby-1.7.18 :019 > e.out_v
#<V[0]>
Total: 1
=> #<outV>
jruby-1.7.18 :020 > e.in_v
#<V[1]>
Total: 1
=> #<inV>
jruby-1.7.18 :021 > e.both_v
#<V[0]> #<V[1]>
Total: 2
=> #<bothV>
out_v, in_v, both_v
jruby-1.7.18 :022 > g.e.out_v
#<V[0]> #<V[1]> #<V[0]>
Total: 3
=> #<GraphE -> outV>
Can be called on a single element as well as a route
out_vertex, in_vertex
jruby-1.7.18 :023 > g.e.first.out_vertex
=> #<V[0]>
Get a single vertex (not a route) from an edge
jruby-1.7.18 :024 > g.v(type: 'person').first.properties
=> {"name"=>"Alice", "type"=>"person"}
jruby-1.7.18 :025 > g.v(type: 'person').properties
{"name"=>"Alice", "type"=>"person"}
{"name"=>"Bob", "type"=>"person"}
Total: 2
=> #<GraphV -> V-Property(type=="person") -> Hash-Map>
All properties of an element
Return value is a hash
All properties of every element in a route
Return value is a route of hashes
jruby-1.7.18 :026 > g.v(type: 'person').first[:name]
=> "Alice"
jruby-1.7.18 :027 > g.v(type: 'person')[:name]
"Alice" "Bob"
Total: 2
=> #<GraphV -> V-Property(type=="person") -> Obj(name) -> decode>
Specific property of an element
Specific property of every element in a route
Return value is a route
jruby-1.7.18 :028 > alice = g.v(name: 'Alice').first
=> #<V[0]>
jruby-1.7.18 :029 > alice.properties
=> {"name"=>"Alice", "type"=>"person"}
jruby-1.7.18 :030 > alice[:age] = 32
=> 32
jruby-1.7.18 :031 > alice.properties
=> {"name"=>"Alice", "type"=>"person", "age"=>32}
jruby-1.7.18 :031 > alice.properties
=> {"name"=>"Alice", "type"=>"person", "age"=>32}
jruby-1.7.18 :032 > alice[:age] = nil
=> nil
jruby-1.7.18 :033 > alice.properties
=> {"name"=>"Alice", "type"=>"person"}
Note: You cannot set/delete property on a route!
g.v(name: 'Alice')[:name] = 'foo'
g.v(name: 'Alice').first[:name] = 'foo'
jruby-1.7.18 :034 > g.e
#<E[3]:0-follows-1> #<E[4]:1-posted-2> #<E[5]:0-likes-2>
Total: 3
=> #<GraphE>
jruby-1.7.18 :035 > g.e.first.delete!
=> nil
jruby-1.7.18 :036 > g.e
#<E[4]:1-posted-2> #<E[5]:0-likes-2>
Total: 2
=> #<GraphE>
A single element
delete!
jruby-1.7.18 :062 > g.v.delete!
Bulk job -> 0!
Bulk job -> 0!
=> 5
jruby-1.7.18 :063 > g.v
Total: 0
=> #<GraphV>
Every element in a route
delete!
Note: Deleting a vertex also deletes all of its edges.
vertex_or_route.out_e.in_v
vertex_or_route.in_e.out_v
People should be able to:
person
type
name
Comment
type
text
timestamp
post
type
text
timestamp
Get the code
git clone git@github.com:xnlogic/graph-training.git
cd graph-training/exercises
Install MiniTest
gem install minitest
Run the tests
ruby ex1-test.rb
Edit ex1.rb until you get to
28 runs, 46 assertions, 0 failures, 0 errors, 0 skips
You should expect to get
28 runs, 15 assertions, 15 failures, 13 errors, 0 skips