Queries

The query macro is used to execute graph queries in a pipelined manner.The main functionalities provided by the query macro are:

eachvertex:

This abstraction is used to run an expression on every vertex in the graph, and retrieve a vector result.

For example, @query g |> eachvertex(v.p1 + v.p2 * v.p3) executes the expression v.p1 + v.p2 * v.p3 on every vertex in the result from the previous pipeline stage. Here, v.p1 denotes the value of property p1 for every vertex.

eachedge:

This abstraction is used to run an expression on every vertex in the graph, and retrieve a vector result.

For example, @query g |> eachedge(e.p1 + s.p1 + t.p1) executes the expression e.p1 + s.p1 + t.p1 on every edge in the graph. Here, 'e.p1' denotes the value of property p1 for every edge in the graph. Since each edge has a source vertex s and a target vertex t, the properties of these vertices can be used in the expression as shown by s.p1 and t.p1.

filter

This abstraction is used to compute a subgraph of the input from the previous pipeline stage, on the given conditions.

For example, @query g |> filter(v.p1 < 5, v.p1 < v.p2, e.p1 > 5) uses the three filter conditions provided to compute a subgraph. Currently only binary comparisons are supported, so comparisons like 1 < v.p1 < v.p2 will not work. Instead you can supply multiple conditions as separate arguments.

select

This abstraction is used to compute a subgraph of the input from the previous pipeline state, for a subset of vertex and or edge properties.

For example, @query g |> select(v.p1, v.p3, e.p1) preserves only vertex properties p1,p2 and edge property p1.

Examples

The abstractions can be chained together using the pipe notation, so that the output of one stage becomes the input to the next.

julia> using Graft

julia> g = propgraph(10, [:p1, :p2], [:p1, :p2])
Graph(10 vertices, 90 edges, Symbol[:p1,:p2] vertex properties, Symbol[:p1,:p2] edge properties)

julia> # Run a filter using vertex properties
       @query g |> filter(0.5 <= v.p1, v.p1 < v.p2)
Graph(0 vertices, 0 edges, Symbol[:p1,:p2] vertex properties, Symbol[:p1,:p2] edge properties)

julia> # Run a filter using source and target properties
       @query g |> filter(s.p1 < t.p2)
Graph(10 vertices, 67 edges, Symbol[:p1,:p2] vertex properties, Symbol[:p1,:p2] edge properties)

julia> # Run filter using edge properties
       @query g |> filter(e.p1 < 0.7)
Graph(10 vertices, 65 edges, Symbol[:p1,:p2] vertex properties, Symbol[:p1,:p2] edge properties)

julia> # Chain filter expressions
       @query g |> filter(v.p1 < v.p2) |> filter(e.p1 < e.p1)
Graph(7 vertices, 0 edges, Symbol[:p1,:p2] vertex properties, Symbol[:p1,:p2] edge properties)

julia> # Select properties
       @query g |> filter(v.p1 < v.p2) |> select(v.p2, e.p1)
Graph(7 vertices, 42 edges, Symbol[:p2] vertex properties, Symbol[:p1] edge properties)

julia> # Run an expression on each vertex
       @query g |> eachvertex(v.p1 + v.p2)
10-element DataArrays.DataArray{Float64,1}:
 0.94857
 1.08217
 1.30267
 1.23016
 0.960419
 1.11792
 1.17587
 0.892584
 0.953239
 1.48109

julia> # Run an expression on each edge
       @query g |> filter(e.p1 < e.p2) |> eachedge(e.p1 + e.p2)
46-element DataArrays.DataArray{Float64,1}:
 0.31571
 0.252064
 0.759534
 1.20403
 0.608237
 1.1838
 0.625409
 0.658119
 0.356378
 1.02913
 
 1.39794
 0.668967
 1.54307
 1.2911
 1.21115
 0.420303
 1.40106
 0.842471
 1.25522

The entire query is parsed into a DAG, using a recursive descent parser, and then executed in a bottom up manner. The results of intermediate nodes, and fetched vertex properties are cached to avoid redundant computations.