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.