Loading

Graph Training 5

XN Logic Corporation

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

Advanced Data Modeling Using Pacer

Brought to you by

Traversing Extended Routes

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

Consider our Customer extension.

Instead of the following route extension method

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

We can define

* Assuming we have created a NorthWind::Order extension.

Now, we can traverse the graph by chaining extension methods:

# Get a customer from the graph
c = g.v(NorthWind::Customer).first

# Get their orders
c.orders

# Chain the result (the `Order` extension has a 
# `products` route extension method).
c.orders.products

# If all of our extensions are returning extended routes,
# our traversals start looking like this:
c.orders.products.categories.uniq

Traversing Extended Routes

Exercise

Go over all the extensions you've created, and make sure that extension methods return extended routes.

category = g.v(NorthWind::Category).first

category.products

category.products.orders.customers

# And even a slightly more complex traversal ...
g.v(NorthWind::Customer)
   .lookahead(max: 1) do |c| 
      c.orders.employees.uniq
   end 
.uniq

When you're done, try to run some traversals in the IRB.

For example:

Properties

Instead of getting/setting properties as follows:

jruby-1.7.18 :018 > e = g.v(Employee).first
 => #<V[n202] Michael Suyama, Sales Representative>

jruby-1.7.18 :019 > e[:title] = "Senior Sales Representative"
 => "Senior Sales Representative"

jruby-1.7.18 :020 > e[:title]
 => "Senior Sales Representative"

We can define properties as vertex extensions


  def title
    self[:title]
  end

  def title=(new_title)
    self[:title] = new_title
  end

Properties

And use them

jruby-1.7.18 :021 > e = g.v(Employee).first
 => #<V[n202] Michael Suyama, Senior Sales Representative>

jruby-1.7.18 :022 > e.title = "Sales Representative"
 => "Sales Representative"

jruby-1.7.18 :023 > e.title
 => "Sales Representative"

Properties

# We don't actually store a `name` property.
# Instead, we compute it on demand.

def name
    "#{self[:firstName]} #{self[:lastName]}"
end

Simple technique that leads to slightly cleaner code:

e[:title]
e[:title] = 'Boss'
e.title
e.title = 'Boss'

VS.

Properties that are computed on-demand

Exercise

  • Add a name property to the Product extension.
  • The property methods (name and name=) should get/set the underlying companyName property.

 

After reloading the code, you should be able to do

product = g.v(Product).first

# Test the getter
name = product.name

# Test the setter
product.name = 'foo'

Edge Extensions

Let's look at how orders are stored:

jruby-1.7.18 :205 > o = g.v(Order).first
 => #<V[n819] Order 10853>

jruby-1.7.18 :206 > o.out_e
#<E[e1589]:n819-PRODUCT-n108>

jruby-1.7.18 :207 > o.out_e(:PRODUCT).properties
{"unitPrice"=>62.5, "quantity"=>10.0}

Essentially, the edge from an Order to a Product serves as an order item:

Edge Extensions

Create an edge extension, in a file called order_item.rb

module NorthWind
    module OrderItem
        module Edge  # Containing Edge extension methods

	    def order
		self.out_vertex(NorthWind::Order)
	    end

	    def product
		self.in_vertex(NorthWind::Product)
	    end

	    # ...
	end
    end
end

Edge Extensions

Use the extension

jruby-1.7.18 :207 > load 'order_item.rb'
 => true

jruby-1.7.18 :208 > o = g.v(Order).first
 => #<V[n819] Order 10853>

jruby-1.7.18 :209 > o.out_e(OrderItem)
#<E[e1589]:10.0 units of Carnarvon Tigers at 62.5$/unit>
Total: 1
 => #<outE -> E>

jruby-1.7.18 :210 > o.out_e(OrderItem).first.order
 => #<V[n819] Order 10853>

jruby-1.7.18 :211 > o.out_e(OrderItem).first.product
 => #<V[n108] Carnarvon Tigers, 62.5$>

Exercise

Add the following edge extension methods to OrderItem:

  • display_name
  • quantity property getter and setter
  • price property getter and setter

Edge Extensions

As you might expect, we can define which edges can be extended by OrderItem

module NorthWind
    module OrderItem

        # Extend only edges whose label is PRODUCT
        def self.route_conditions(graph)
            :PRODUCT
    	end

        # ...

Edge Extensions

We can also create route extension methods.

module NorthWind
    module OrderItem

        # ...

        module Route

            def products
        	self.in_v(NorthWind::Product)
            end

            # ...
        end
       
        # ...

Edge Extensions

Use the products extensions method on a route of order items:

# Get (a route containing) a few order items
items = g.e(NorthWind::OrderItem).limit(3)

# And their products
items.products

Exercise

Add the orders route extensions method to OrderItem.

  • Return a route of vertices
  • Extended by the Order extension

Edge Extensions

NOTE: Although Pacer supports edge extensions, we recommend to keep your edges property-free, if possible.

We can turn

Into

Flexibility -  We can have edges to/from the new vertex. 

Indexing

Index properties frequently used for searching.

jruby-1.7.18 :068 > g.v(type: 'foo')
Total: 0
 => #<GraphV -> V-Property(type=="foo")>
jruby-1.7.18 :069 > g.create_key_index :type
jruby-1.7.18 :070 > g.v(type: 'foo')
Total: 0
 => #<V-Index(type: "foo")>

Create an index on the type property:

What's next?

We will see a demo of a full web application, backed by a graph database.

In this demo, we will

  • Use Pacer with Neo4j
  • Expose our traversals as a web API, using Sinatra
Made with Slides.com