Virtuoso Native Graph Analytics with GQL: Enhanced by Standardized Namespaces and Identifiers

A standards distinction matters: ISO/IEC 39075:2024 standardizes GQL for property graphs and includes graph pattern matching and path queries. The bif: analytics functions in these examples are Virtuoso extensions; they are not functions specified by ISO GQL. The path pattern examples near the end use GQL path matching, while the analytics calls use Virtuoso’s bif: functions.

The examples query the urn:social graph and use foaf:knows relationships. Run links open the supplied queries at the VEC endpoint.

PageRank and centrality

PageRank ranks nodes by the link structure of the selected graph. With RDF 1.2 edge annotations, the first example uses an edge weight. The following examples show unweighted PageRank, parameterized PageRank, and four centrality measures.

Weighted PageRank via RDF 1.2 edge annotations

GQL
PREFIX ex: <#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

VERSION "rdf 1.2"
USE GRAPH <urn:social>
MATCH (p)-[e:foaf:knows {ex:weight: w}]->(other)
RETURN DISTINCT p,
  bif:GRAPH_PAGERANK_WEIGHTED(
    p,
    iri('urn:social'),
    iri('http://xmlns.com/foaf/0.1/knows'),
    iri('#weight')
  ) AS score
ORDER BY score DESC

Run weighted PageRank.

Basic PageRank

GQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

USE GRAPH <urn:social>
MATCH (p)-[:foaf:knows]-(other)
RETURN DISTINCT p,
  bif:pagerank(
    p,
    iri('urn:social'),
    iri('http://xmlns.com/foaf/0.1/knows')
  ) AS score
ORDER BY score DESC

Run basic PageRank.

PageRank with damping, iteration limit, and tolerance

This example sets a damping factor of 0.9, a maximum of 500 iterations, and a tolerance of 0.000001.

GQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

USE GRAPH <urn:social>
MATCH (p)-[:foaf:knows]-(other)
RETURN DISTINCT p,
  bif:pagerank(
    p,
    iri('urn:social'),
    iri('http://xmlns.com/foaf/0.1/knows'),
    0.9,
    500,
    0.000001
  ) AS score
ORDER BY score DESC

Run parameterized PageRank.

Degree centrality

Degree centrality counts a node’s connections. This query asks for the measure in both directions.

GQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

USE GRAPH <urn:social>
MATCH (p)-[:foaf:knows]-(other)
RETURN DISTINCT p,
  bif:degree_centrality(
    p,
    iri('urn:social'),
    iri('http://xmlns.com/foaf/0.1/knows'),
    'both'
  ) AS score
ORDER BY score DESC

Run degree centrality.

Betweenness centrality

Betweenness centrality scores nodes by their role along paths between other nodes. The arguments specify the graph, relationship type, normalization, and direction settings.

GQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

USE GRAPH <urn:social>
MATCH (p)-[:foaf:knows]-(other)
RETURN DISTINCT p,
  bif:betweenness(
    p,
    iri('urn:social'),
    iri('http://xmlns.com/foaf/0.1/knows'),
    1,
    0
  ) AS score
ORDER BY score DESC

Run betweenness centrality.

Closeness centrality

Closeness centrality measures how near a node is to the other nodes, based on paths through the graph.

GQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

USE GRAPH <urn:social>
MATCH (p)-[:foaf:knows]-(other)
RETURN DISTINCT p,
  bif:closeness(
    p,
    iri('urn:social'),
    iri('http://xmlns.com/foaf/0.1/knows')
  ) AS score
ORDER BY score DESC

Run closeness centrality.

Eigenvector centrality

Eigenvector centrality gives greater weight to connections with nodes that themselves score highly. This example supplies an iteration limit and tolerance.

GQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

USE GRAPH <urn:social>
MATCH (p)-[:foaf:knows]-(other)
RETURN DISTINCT p,
  bif:eigenvector(
    p,
    iri('urn:social'),
    iri('http://xmlns.com/foaf/0.1/knows'),
    200,
    0.00001
  ) AS score
ORDER BY score DESC

Run eigenvector centrality.

Components, communities, and triangles

These queries group nodes by connectivity or community assignment, or count triangles involving each node.

Weakly connected components (WCC)

WCC groups nodes by connectivity while disregarding edge direction.

GQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

USE GRAPH <urn:social>
MATCH (p)-[:foaf:knows]-(other)
RETURN DISTINCT p,
  bif:wcc(
    p,
    iri('urn:social'),
    iri('http://xmlns.com/foaf/0.1/knows')
  ) AS score
ORDER BY score DESC

Run WCC.

Strongly connected components (SCC)

SCC retains direction: nodes are grouped when directed paths connect them both ways.

GQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

USE GRAPH <urn:social>
MATCH (p)-[:foaf:knows]-(other)
RETURN DISTINCT p,
  bif:scc(
    p,
    iri('urn:social'),
    iri('http://xmlns.com/foaf/0.1/knows')
  ) AS score
ORDER BY score DESC

Run SCC.

Community ID (Louvain)

This query returns a community identifier for each matched node.

GQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

USE GRAPH <urn:social>
MATCH (p)-[:foaf:knows]-(other)
RETURN DISTINCT p,
  bif:community_id(
    p,
    iri('urn:social'),
    iri('http://xmlns.com/foaf/0.1/knows')
  ) AS score
ORDER BY score DESC

Run Louvain community ID.

Triangles

Triangle counts show how many closed three-node patterns include each node.

GQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

USE GRAPH <urn:social>
MATCH (p)-[:foaf:knows]-(other)
RETURN DISTINCT p,
  bif:triangle_count(
    p,
    iri('urn:social'),
    iri('http://xmlns.com/foaf/0.1/knows')
  ) AS score
ORDER BY score DESC

Run triangle counts.

Match and measure paths

GQL path patterns can express reachability and shortest-path matches. The next examples fix Alice as the starting node and Eve as the destination, then return either a path match, its length, or a serialized route.

Shortest-path matching with GQL

GQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

USE GRAPH <urn:social>
MATCH SHORTEST PATH (a)-[:foaf:knows*]->(b)
WHERE a = iri('#alice') AND b = iri('#eve')
RETURN a, b

Run shortest-path matching.

Shortest-path length: Alice to Eve

This query returns the hop count as well as the endpoints.

GQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

USE GRAPH <urn:social>
MATCH (a)-[:foaf:knows*]->(b)
WHERE a = iri('#alice') AND b = iri('#eve')
RETURN DISTINCT a, b,
  bif:shortest_path_length(
    a,
    b,
    iri('urn:social'),
    iri('http://xmlns.com/foaf/0.1/knows')
  ) AS hops

Run the Alice-to-Eve path-length query.

Shortest route: return the node sequence

The route function returns the node sequence; sql:obj2json serializes it as JSON for display.

GQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

USE GRAPH <urn:social>
MATCH (a)-[:foaf:knows*]->(b)
WHERE a = iri('#alice') AND b = iri('#eve')
RETURN DISTINCT
  sql:obj2json(
    bif:shortest_path(
      a,
      b,
      iri('urn:social'),
      iri('http://xmlns.com/foaf/0.1/knows')
    )
  ) AS route

Run the shortest-route query.

Cheapest weighted route and total cost

The weighted shortest-path function returns an array-like result. The query converts its route element to JSON and reads the total cost from element 2.

GQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

USE GRAPH <urn:social>
MATCH (a)-[:foaf:knows*]->(b)
WHERE a = iri('#alice') AND b = iri('#eve')
LET result = bif:GRAPH_SHORTEST_PATH_WEIGHTED(
  a,
  b,
  iri('urn:social'),
  iri('http://xmlns.com/foaf/0.1/knows'),
  iri('#weight'),
  1
)
RETURN DISTINCT
  sql:obj2json(bif:aref(result, 0)) AS route,
  bif:aref(result, 2) AS cost

Run the cheapest weighted-route query.

Path finding: everyone reachable from Alice

The + quantifier requires one or more foaf:knows edges, returning nodes reachable from Alice.

GQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

USE GRAPH <urn:social>
MATCH (a)-[:foaf:knows+]->(b)
WHERE a = iri('#alice')
RETURN DISTINCT b

Run the Alice reachability query.

Queries and analytics in one graph workflow

The examples show two related capabilities: GQL patterns express graph matches and paths, while Virtuoso’s bif: functions add graph analytics over the RDF relationships. Their combination keeps the data pattern, selected graph, analytics operation, and returned result visible in query text.

The analytics function names and parameters shown here are Virtuoso-specific. Their presence in a GQL query does not make them part of ISO GQL; implementations can provide different analytics functions and interfaces. The RDF 1.2 edge-annotation example likewise relies on the endpoint’s RDF 1.2 support.

These examples extend the original RDF graph-analytics article from SPARQL query patterns to GQL query text, including standard path matching and Virtuoso analytics extensions.

Related