Earlier, we created a simple vertex extension, Airport, but we forgot to ask an important question:

  • What if some vertices in our graph are not airports?
    For example, we could have vertices representing airplanes, people, runways, etc.

Essentially, we want to be able to do the following:

  • Get vertices that correspond to airports, and extend them with the Airport extension.

route_conditions

You can define a route_conditions method that will tell Pacer which vertices can be extended by an extension.

In most applications, filtering by extensions is very common, and needs to be fast. Therefore, route_conditions only allows for very simple filtering conditions:

  • Exact property match with a single value.
    For example, {foo: 'bar'}.
  • Exact property match with a set of values (i.e. exact match with one of the items in the set).
    For example, {foo: Set['bar1', 'bar2']}

Tip: Save a _type property with each vertex, create an index on the key _type and use it for filtering.

See it in action

First, let's re-create our simple test data. This time, we will create a _type property in each vertex.

g = Pacer.tg()

g.transaction do # optional with TinkerGraph

  lax = g.create_vertex({_type: :airport, airport: 'LAX', city: 'Los Angeles'})
  lga = g.create_vertex({_type: :airport, airport: 'LGA', city: 'New York'})
  sfo = g.create_vertex({_type: :airport, airport: 'SFO', city: 'San Francisco'})
  yyz = g.create_vertex({_type: :airport, airport: 'YYZ', city: 'Toronto'})

  lga.add_edges_to(:flight, lax, {airline: 'Delta'})
  lga.add_edges_to(:flight, yyz, {airline: 'Air Canada'})
  yyz.add_edges_to(:flight, lga, {airline: 'Air Canada'})
  lax.add_edges_to(:flight, yyz, {airline: 'Delta'})
  lax.add_edges_to(:flight, sfo, {airline: 'WestJet'})
  lax.add_edges_to(:flight, sfo, {airline: 'American Airlines'})

end

Next, we will define the route_conditions method, so that only vertices whose _type property is airport will get extended by our Airport extension.

module Airport

    def self.route_conditions(graph)
        {_type: :airport}
    end


    module Vertex

        def display_name
            "#{self[:airport]} airport, #{self[:city]}"
        end

    end


    module Route

        def departures
            self.out_e(:flight)
        end

        def arrivals
            self.in_e(:flight)
        end

    end

end

Now, let's test our changes in the IRB.

# Just as before, extend a vertex route with our Airport extension
jruby-1.7.19 :061 > g.v(Airport)
#<V[3] YYZ airport, Toronto>  #<V[2] SFO airport, San Francisco>  
#<V[1] LGA airport, New York>   #<V[0] LAX airport, Los Angeles>  
Total: 4

# Create a non-airport vertex (we're using TinkerGraph, so we don't need a transaction)
jruby-1.7.19 :062 > g.create_vertex
 => #<V[10]> 

# The new vertex is filtered out, when we extend the route with our Airport extension
jruby-1.7.19 :063 > g.v(Airport)
#<V[3] YYZ airport, Toronto>  #<V[2] SFO airport, San Francisco>  
#<V[1] LGA airport, New York>   #<V[0] LAX airport, Los Angeles>  
Total: 4

# Create another vertex, this time with a '_type' property whose value is 'airport'.
jruby-1.7.19 :064 > g.create_vertex({_type: :airport, airport: 'MSY', city: 'New Orleans'})

 # The new vertex is included in the result, when we filter using our `Airport` extension.
jruby-1.7.19 :065 > g.v(Airport)
#<V[3] YYZ airport, Toronto>       #<V[2] SFO airport, San Francisco> 
#<V[1] LGA airport, New York>      #<V[0] LAX airport, Los Angeles>  
#<V[11] MSY airport, New Orleans> 
Total: 5

Indexing our filtering property

Since the _type property will be used for filtering, we better make sure it is indexed:

# Filter by extension, without an index
jruby-1.7.19 :072 > g.v(Airport)
#<V[3] YYZ airport, Toronto>       #<V[2] SFO airport, San Francisco> 
#<V[1] LGA airport, New York>      #<V[0] LAX airport, Los Angeles>  
#<V[11] MSY airport, New Orleans> 
Total: 5
 => #<GraphV -> V-Property(Airport)> 

# Create the index
jruby-1.7.19 :073 > g.create_key_index :_type
 => nil 

# Filter by extension, with an index
jruby-1.7.19 :074 > g.v(Airport)
#<V[3] YYZ airport, Toronto>       #<V[2] SFO airport, San Francisco> 
#<V[1] LGA airport, New York>      #<V[0] LAX airport, Los Angeles>  
#<V[11] MSY airport, New Orleans> 
Total: 5
 => #<V-Index(_type: :airport) -> V>

Notice the difference in output:

  • Without index: #<GraphV -> V-Property(Airport)>.
  • With index: #<V-Index(_type: :airport) -> V>.

The IRB output tells you exactly how Pacer evaluates the route.
In this case, we can see that, once we created an index on the _type property, Pacer uses it automatically.