Loading

Graph Training 4

XN Logic Corporation

This is a live streamed presentation. You will automatically follow the presenter and see the slide they're currently on.

Data Modeling using Pacer

Brought to you by

What Is Data Modeling?

Mike buys a book online

Data Modeling is about going back and forth between the real-world (on the left) and the graph (on the right).

VS.

Pacer Extensions

A fundamental building block of Pacer

Without extensions


def comments_to_posts_by(person)
   person
      .out_e(:POSTED)
      .in_v(type: 'post')
      .in_e(:IS_ABOUT)
      .in_v(type: 'comment')
end
   

With extensions




def comments_to_posts_by(person)
   person.posts.comments
end
   

Pacer Extensions

What do they look like?

module Person

   # ...

   module Vertex
 
      def posts
         self.out_e(:POSTED).in_v(type: 'post')
      end

   end

   # ...

end

Case Study - NorthWind

Setup

$ cd pacer-northwind
$ irb
jruby-1.7.18 :001 > require 'pacer'
 => true

jruby-1.7.18 :002 > g = Pacer.tg
 => #<PacerGraph tinkergraph[vertices:0 edges:0]

jruby-1.7.18 :003 > Pacer::GraphML.import(g, 'northwind.graphml')
 => true

From the root folder of our repo

And then

NorthWind

# Find out the different types of vertices ...

jruby-1.7.18 :004 > g.v[:type].uniq
"Order"  "Category" "Employee" 
"Customer" "Product"  "Supplier"
Total: 6

Let's explore the dataset ...

# Look at an outgoing edge from a Customer vertex ...

jruby-1.7.18 :005 > e = g.v(type: 'Customer').out_e.limit(1)
#<E[e3026]:n10-PURCHASED-n255>
Total: 1
# What is the type of the in-vertex of that edge?

jruby-1.7.18 :033 > e.in_v.first[:type]
 => "Order"

First Extension - Customer

In a file called customer.rb

module NorthWind
    module Customer

        

            
                
            

   
    end	
end
module NorthWind
    module Customer

        module Vertex

            
            
            

    	end
    end
end
module NorthWind
    module Customer

        module Vertex

            def orders
                
            end

    	end
    end
end
module NorthWind
    module Customer

        module Vertex

            def orders
                self.out_e(:PURCHASED).in_v(type: "Order")
            end

    	end
    end
end
  • Extensions are plain old Ruby modules
  • Create a Vertex module
  • Define vertex extension methods
  • Implement them (self is a vertex object)

Using The Extension

Try it in the IRB ...

jruby-1.7.18 :100 > load 'customer.rb'
 => true

jruby-1.7.18 :101 > c = g.v(NorthWind::Customer, 
                            type: 'Customer').first
 => #<V[n10]>

jruby-1.7.18 :102 > c.orders
#<V[n255]> #<V[n913]> #<V[n450]> #<V[n505]> #<V[n989]> 
#<V[n504]> #<V[n909]> #<V[n437]> #<V[n544]> #<V[n565]>
Total: 10

What just happened?

  • All vertices
  • Whose type is 'Customer'
  • Extended by the Customer extension
g.v

The vertex                                                                       responds to the              vertex-extension method.

g.v(NorthWind::Customer, type: 'Customer').first
g.v(NorthWind::Customer, type: 'Customer')
g.v(                     type: 'Customer')
orders

Filter By Extension

Only vertices whose type is 'Customer' should be extended by the Customer extension.

module NorthWind
    module Customer

        
        
        

        module Vertex

            def orders
                self.out_e(:PURCHASED).in_v(type: "Order")
            end

        end
    end
end

        def self.route_conditions(graph)
            {type: 'Customer'}
        end

Filter By Extension

jruby-1.7.18 :103 > load 'customer.rb'
 => true

jruby-1.7.18 :104 > include NorthWind
 => Object

jruby-1.7.18 :105 > g.v(Customer).first.orders
#<V[n255]> #<V[n913]> #<V[n450]> #<V[n505]> #<V[n989]> 
#<V[n504]> #<V[n909]> #<V[n437]> #<V[n544]> #<V[n565]>
Total: 10

Filter By Extension

Try to get the orders of multiple customers ...

jruby-1.7.18 :106 > g.v(Customer).orders
NoMethodError
...
Total: 91
undefined method `orders' for 
#<GraphV -> V-Property(NorthWind::Customer)>

We want to be able to extend routes, not just vertices.

Vertex vs. Route

module NorthWind
    module Customer

        def self.route_conditions(graph)
            {type: "Customer"}
        end

        module Vertex  # Contains vertex extension methods
            # ... 
        end

        module Route   # Contains route extension methods

            def orders
                self.out_e(:PURCHASED).in_v(type: "Order")
            end

        end

    end
end
jruby-1.7.18 :107 > load 'customer.rb'
 => true

jruby-1.7.18 :108 > g.v(Customer).limit(3).orders
#<V[n255]>  #<V[n913]>  #<V[n450]>  #<V[n505]>  #<V[n989]>  
#<V[n504]>  #<V[n909]>  #<V[n437]>  #<V[n544]>  #<V[n565]>  
#<V[n225]>  #<V[n487]>  #<V[n903]>  #<V[n1020]> #<V[n748]>  
#<V[n847]>  #<V[n785]>
Total: 17
 => #<GraphV -> V-Property(NorthWind::Customer) -> V-Range(-1...3) 
    -> outE(:PURCHASED) -> inV -> V-Property(type=="Order")>

Vertex vs. Route

Reload and try it in the IRB

jruby-1.7.18 :109 > g.v(Customer).first.orders
#<V[n255]> #<V[n913]> #<V[n450]> #<V[n505]> #<V[n989]> 
#<V[n504]> #<V[n909]> #<V[n437]> #<V[n544]> #<V[n565]>
Total: 10
 => #<outE(:PURCHASED) -> inV -> V-Property(type=="Order")>

Route-extension methods can be called on a single element:

* Because an element can be converted to a route with one element.

Vertex vs. Route

Exercise

  • Create extensions for all 6 types:
    • Category 
    • Customer
    • Employee
    • Order
    • Product
    • Supplier
  • Conventions:
    • Each extension in its own file
    • Under the NorthWind namespace.
    • Filenames are lower-case

Exercise

  • Define route conditions.
    • Based on the type property of a vertex.
  • Explore the dataset to discover all types of relations.
    • Use the IRB and/or write a script.
    • Remember: A vertex can have edges of multiple labels.
  • Write route-extension methods for all relations.

Display Name

Customers have a few properties.

jruby-1.7.18 :111 > g.v(Customer).first
 => #<V[n10]>

Yet, in the IRB, we only display their internal id.

jruby-1.7.18 :110 > g.v(Customer).first.properties
 => {"phone"=>"(171) 555-1212", 
     "companyName"=>"B's Beverages", 
     "customerID"=>"BSBEV", 
     "type"=>"Customer"}

Can we define some sort of a  toString method? 

Display Name

Add the following vertex extension method:

def display_name
    "#{self[:companyName]} (#{self[:customerID]})"
end

And ...

jruby-1.7.18 :112 > load 'customer.rb'
 => true
jruby-1.7.18 :113 > g.v(Customer).first
 => #<V[n10] B's Beverages (BSBEV)>

Exercise

Add a display_name to every extension you created.

After doing so, you should be able to do the following:

# Get a customer
jruby-1.7.18 :114 > c = g.v(Customer).first
 => #<V[n10] B's Beverages (BSBEV)>

# Get their orders
jruby-1.7.18 :115 > c.orders
#<V[n255] Order 10289> #<V[n913] Order 10947> #<V[n450] Order 10484> ... 
Total: 10

# Get the employees who sold something to this customer
jruby-1.7.18 :116 > c.orders.employees.uniq
#<V[n203] Robert King, Sales Representative> ... 
Total: 7

# Which other customers did these employees serve?
jruby-1.7.18 :117 > c.orders
jruby-1.7.18 :118 >  .employees.uniq
jruby-1.7.18 :119 >  .orders.customers
jruby-1.7.18 :120 >  .uniq.is_not(c)
#<V[n59] Princesa Isabel Vinhos (PRINI)>  #<V[n75] Suprêmes délices (SUPRD)> ...
Total: 89

What's next?

  • Common patterns
  • Practical tips and tricks
  • Considerations when modeling a realistic dataset

We have seen the basic concepts for Data Modeling using Pacer.

Next, we will go through

Made with Slides.com