Scale AI into Production: Neo4j's Five Scale Capabilities Meshed with Virtuoso and agent-rdf-memory

Same five problems, one engine: reach, growth, availability, size and analytics, with the live proof on demo.openlinksw.com.

Executive SummaryBy Paul Blewett · Neo4j · 2026-09-17

Synopsis

Getting an AI application into production is only part of the journey; as organizations move beyond their first applications the challenges shift. Neo4j's Paul Blewett describes five capabilities for that stage: Virtual Graph to query warehouse data where it lives, Multiple Databases to consolidate workloads, AuraDB instances up to about 2TB of RAM and 5TB of storage, Cross-Cluster Database Replication for availability, and a Graph Analytics tier that scales independently of the operational database.

View this analysis as a KG entity
The Source

What the Article Says

Paul Blewett of Neo4j closes by saying the five capabilities address different dimensions of one problem: Virtual Graph handles reach, Multiple Databases handle growth, Cross-Cluster Replication handles availability, larger instances handle size and an independent analytics tier handles contention. That framing is the spine of this page: for each dimension, what does a Virtuoso deployment with the agent-rdf-memory harness do about the same problem?

3
Virtual Graph reads Snowflake, Databricks and Google BigQuery in place. Public preview; general availability expected in a couple of months.
100 → 250
Up to 5 per GB of RAM, capped at 100 in preview and 250 after general availability.
2 TB / 5 TB
Largest AuraDB
RAM and storage on high-memory Business Critical and Virtual Dedicated Cloud instances, on Google Cloud today.
2
The replica pulls transactions from the upstream cluster or differential backups from object storage. Active-passive.
Sept
An Early Access Program for self-managed customers; algorithms run on dedicated compute, billed per running session in Aura.

Two limits the article states plainly are carried into the comparison below: sharded databases are not yet supported by replication, and role-based access control is not replicated. It also draws a line for agents: those that can work in seconds suit Virtual Graph, while those that must act in milliseconds, such as online fraud scoring, need the graph stored natively. Read the original at neo4j.com.

Twelve Axes

Where the Two Stacks Diverge

Each row states the Neo4j position as the article gives it, the Virtuoso position as this page demonstrates or documents it, and an assessment that names what the difference costs. A lean is a judgement about one axis, not a verdict on either platform.

0
Lean Neo4j
No axis leans towards Neo4j on the evidence gathered.
12
Lean Virtuoso
All twelve axes: reach, translation, model proposal, isolation, size, replication, analytics, latency tiers, query model, identifiers, entailment and operating the platform.
0
Even
No axis is a genuine tie on the evidence gathered.

Showing one card per platform so the twelve dimensions stay readable on a narrow screen.

DimensionNeo4jVirtuoso + agent-rdf-memoryAssessment
Querying data where it livesVirtual Graph: a zero-copy graph over Snowflake, Databricks and Google BigQuery, with the data left in place under its existing governance. In public preview at publication, with general availability expected in a couple of months.RDF Views: one ALTER QUAD STORAGE statement maps the tables of any SQL system of record to triples computed at query time, with the SQL engine still holding and governing the rows. Snowflake, Databricks and BigQuery are SQL systems, so they are simply further systems of record for the same mechanism. Proven live on this page over the ScaleKG tables.Same idea, but Virtuoso's is shipping and demonstrated on this page, while Neo4j's is in public preview with general availability still to come. Neo4j's is aimed at three named warehouses; Virtuoso's works against any SQL system of record, which is what those warehouses are. Pointing it at one particular remote SQL engine is connection configuration that this page does not exercise.
Virtuoso edge

Evidence: Virtuoso: demonstrated on this page, Queries 1 to 9. Neo4j: the article, which gives public preview status.

How the graph query reaches the sourceNeo4j rewrites the Cypher query as SQL and executes it inside the source system.The engine compiles queries in several open-standards languages into SQL over the mapped tables at query time: SPARQL and SPASQL are demonstrated on this page, and GraphQL and GQL are stated by OpenLink. The generated SQL can be inspected; Query 8 shows a two-pattern SPARQL query compiling to 22,712 characters of SQL.Both compile graph queries to SQL, so the mechanism is shared and the differences favour Virtuoso. It does this for several open-standards languages where the article describes one, Cypher, and it exposes the compiled SQL, which this page demonstrates; the article does not say whether Virtual Graph's generated SQL can be inspected.
Virtuoso edge

Evidence: Virtuoso: SPARQL and SPASQL compilation demonstrated on this page, Query 8 shows the generated SQL; GraphQL and GQL stated by OpenLink. Neo4j: one sentence in the article, describing Cypher only.

Proposing the graph modelBuilt-in AI assistance drafts the graph model from the tables, deciding what becomes a node, a relationship or a property, and reaching relationships between keys even where no foreign key is declared.The agent-rdf-memory harness deployed on Virtuoso carries skills that generate ontologies and instance data from text (kg-generator, document-to-kg-skill) and from relational tables (linked-data-skills, which produces the ontology, the RDF View mapping and the rewrite rules), alongside Virtuoso's own RDF View generators. An LLM agent working through them can propose relationships the schema does not declare. This page's own ontology, quad map and rewrite rules were produced that way, and each is plain Turtle or SQL that is reviewed before it is deployed.Virtuoso's reach is wider: the harness generates ontologies and instance data from text as well as from tables, and this page's own ontology, quad map and rewrite rules came from it, as standards-based artefacts that can be reviewed. Neo4j ships its assistance inside the product and the article describes it for tables only, including relationships between undeclared keys. That last claim was not tested on either side here.
Virtuoso edge

Evidence: Virtuoso: demonstrated by how this page's ontology, quad map and rewrite rules were produced, with the skills documented in the repository. Neo4j: the article; its undeclared-key claim was not tested.

Isolating tenants, teams and environmentsMultiple Databases inside one instance, allowing 5 databases per GB of RAM by default, bounded at 100 per instance in preview and 250 after general availability. The article's examples are multi-tenant SaaS, consolidated environments, departmental graphs and separated workloads.No database-count ceiling to plan around. Each domain lives in its own named graph with graph-level permissions (read, SPARQL write, sponge); RDF Views inherit the SQL table privileges of their source tables; and capacity grows by federating graphs and instances into a Semantic Web of purpose-specific graphs. This page is itself an example: the RDF View is hosted on demo.openlinksw.com, this collection's graph is hosted on URIBurner, and Query 9 joins the two in one statement.The article's 5-per-GB rule and its 100 and 250 caps are planning constraints of the database-per-tenant model, and Virtuoso's model does not need equivalents. A separate database is a harder storage boundary than a graph permission, but a federated set of named graphs lets one query span graphs and instances whenever access allows, which a database boundary forbids.
Virtuoso edge

Evidence: Virtuoso: demonstrated on this page, Query 9, and documented graph-level permissions. Neo4j: the article's figures.

Ceiling on one deploymentHigh-memory AuraDB Business Critical and Virtual Dedicated Cloud instances with up to 2TB of RAM and 5TB of storage, generally available on Google Cloud with more clouds planned.Single-server deployments, and from Virtuoso 7 an Elastic cluster that shards data into self-contained partitions and can be resized. OpenLink reports Berlin SPARQL Benchmark runs against 50 and 150 billion triple datasets on the column-store cluster. Pay-as-you-go machine offers exist on AWS, Azure and Google Cloud, so the instance type is chosen per cloud.The two ceilings are quoted in different units, machine memory against triple counts, so they cannot be compared number for number. Neo4j scales one managed instance up, on Google Cloud today with more clouds planned. Virtuoso documents scale-out as well as scale-up, to 150 billion triples, and is offered on-premise, in containers and on three clouds.
Virtuoso edge

Evidence: Virtuoso: OpenLink-reported benchmark figures and documented cloud offers. Neo4j: the article's figures.

Staying available across regionsCross-Cluster Database Replication is active-passive: only the primary takes writes and the replica stays read-only until promoted. A replica catches up either by pulling transactions from the upstream cluster or by pulling differential backups from object storage. Sharded databases are not yet supported and role-based access control does not replicate. Generally available in Enterprise Edition, coming soon to Aura.Transactional replication (one-way or bi-directional with conflict resolution), snapshot replication (incremental or not) and RDF graph replication, where named graphs are published and subscribed in chain, star or bi-directional topologies. The replication documentation consulted does not say whether SQL users and roles replicate.Virtuoso documents more topologies, including writable bi-directional ones that the article's active-passive model excludes, plus snapshot and graph-level replication. The article's model has sharded databases unsupported, access control not replicated and Aura availability still to come. Neo4j states its limits plainly; whether SQL roles replicate in Virtuoso is not stated in the documentation consulted, and should be checked before it is relied on.
Virtuoso edge

Evidence: Both: vendor documentation, the Virtuoso replication pages consulted on 2026-09-30 and the article.

Analytics that do not contend with transactionsNeo4j Graph Analytics runs algorithms on dedicated compute machines, not inside the database JVM, scaled independently. Early Access starts in September; in Aura, sessions are billed only while running.Graph analytics run in the engine through SQL, SPARQL and GQL over the same data, without compromising the standardized identifiers and multilingual capabilities of RDF, and with HTTP making each graph part of a Semantic Web, public or private. Virtuoso is available as pay-as-you-go machine offers on AWS, Azure and Google Cloud, so analytics capacity is chosen by instance type, and replication can carry heavy analytics on a separate instance from transactional load.Virtuoso runs graph analytics today, per OpenLink, through SQL, SPARQL and GQL on instances sized for the job in three clouds, over standards-based identifiers and HTTP-addressable graphs. Neo4j's dedicated compute tier, billed per running session, is an Early Access Program for self-managed customers. Neither was benchmarked here, so this lean rests on availability and breadth, not on measured speed.
Virtuoso edge

Evidence: Virtuoso: stated by OpenLink, not benchmarked here. Neo4j: the article, which describes an Early Access Program.

Seconds versus millisecondsSeconds-scale agents suit Virtual Graph; agents that must respond in milliseconds need the graph held natively in AuraDB. Two storage models, chosen per workload.The same SPARQL runs against an RDF View over SQL tables or against triples held in the physical quad store, and a view can be copied into a physical graph. The latency tier is a deployment choice, not a change of model or language.Virtuoso's single query model across both tiers is a simplification. It does not make a warehouse-backed query as fast as a native one; the article's guidance on what each tier suits holds for both.
Virtuoso edge

Evidence: Virtuoso: documented, not demonstrated here. Neo4j: the article.

Query language and modelProperty graph queried with Cypher, natural language or direct syntax, against virtual or native graphs.RDF queried with SPARQL, SQL, GraphQL and GQL, the open-standards variant of Cypher, and with SPASQL, which nests a SPARQL query inside a SQL SELECT so a graph result set joins native relational tables in one statement. Query 5 on this page does exactly that.Cypher's compact pattern syntax and large practitioner base carry over to GQL, which Virtuoso also supports, so the languages are not where the two differ. What the article does not describe is SPASQL, or one engine answering in SPARQL, SQL, GraphQL and GQL over the same data. This page demonstrates SPARQL, SQL and SPASQL and does not exercise GQL.
Virtuoso edge

Evidence: Virtuoso: SPARQL, SQL and SPASQL demonstrated on this page; GraphQL and GQL stated by OpenLink. Neo4j: the article.

Identity that outlives the storeThe article is silent on global identifiers; nodes are identified within a database.Every entity in the ScaleKG view has an HTTP IRI built from its key column, and URL rewrite rules make it resolve: the IRI answers with a 303 to a description page, and a DESCRIBE through the SPARQL endpoint returns its triples. The key becomes a hyperlink that any other graph, table or document can reference, so it acts as a super-key across stores. On this host, content negotiation for Turtle on the bare IRI returns 406.For a single estate this is a convenience. It becomes the main difference when graphs from several owners must be joined, which is where a Semantic Web of purpose-specific graphs earns its keep.
Virtuoso edge

Evidence: Virtuoso: demonstrated on this page, 67 of 67 entity IRIs resolve. Neo4j: the article is silent.

Entailment from a declared vocabularyThe article does not describe ontology-driven inference.An RDFS rule set derived from the ScaleKG TBox makes a query for skg:DataAsset return the 16 databases and 9 warehouse tables that were only ever typed as their subclasses; with no rule set the same query returns 0. Query 6 shows it live. Sub-property entailment over the view did not fire on this build, so Query 7 reads the property hierarchy from the TBox by joining it into the query.A silence in an article is not a gap in a product, so this axis records only what Virtuoso demonstrates here. Class entailment works over an RDF View; property entailment over a view needs the TBox joined in explicitly on this build, and combining SELECT DISTINCT, ORDER BY and inference raised an error.
Virtuoso edge

Evidence: Virtuoso: demonstrated on this page, Queries 6 and 7. Neo4j: the article is silent.

Operating the platformAuraDB is a managed service, and the article also refers to Neo4j Enterprise Edition for self-managed deployments. Its capabilities arrive as instance types, editions and preview programmes a platform team selects.Virtuoso is offered on-premise, as Docker containers, as cloud machine images on AWS, Azure and Google Cloud, and as a self-managed service on AWS, with OpenLink Managed services announced for release this month. It can be configured and administered in natural language through its bundled MCP tooling and packaged SKILL.md skills, as well as through SQL, Conductor and scripts. This page's own deployment, its tables, quad map, rewrite rules and grants, was driven that way by an agent calling the same OpenLink functions that the MCP tooling exposes.Virtuoso leads on operating the platform. An agent configures and administers the instance in natural language, which is demonstrated on this page and removes much of the operating effort a managed service exists to remove, and the deployment choice is the widest of the two: on-premise, containers, three clouds and a self-managed AWS service. Neo4j's one operational advantage, a generally available vendor-run service in AuraDB, is noted and does not outweigh that, particularly since Neo4j also offers a self-managed edition and OpenLink's managed service is announced for this month.
Virtuoso edge

Evidence: Neo4j: the article. Virtuoso: agent-driven configuration demonstrated on this page and the MCP tooling documented in the repository; deployment options stated by OpenLink; the managed service is announced, not yet released.

Neo4jThe article
Virtual Graph: a zero-copy graph over Snowflake, Databricks and Google BigQuery, with the data left in place under its existing governance. In public preview at publication, with general availability expected in a couple of months.
Neo4j rewrites the Cypher query as SQL and executes it inside the source system.
Built-in AI assistance drafts the graph model from the tables, deciding what becomes a node, a relationship or a property, and reaching relationships between keys even where no foreign key is declared.
Multiple Databases inside one instance, allowing 5 databases per GB of RAM by default, bounded at 100 per instance in preview and 250 after general availability. The article's examples are multi-tenant SaaS, consolidated environments, departmental graphs and separated workloads.
High-memory AuraDB Business Critical and Virtual Dedicated Cloud instances with up to 2TB of RAM and 5TB of storage, generally available on Google Cloud with more clouds planned.
Cross-Cluster Database Replication is active-passive: only the primary takes writes and the replica stays read-only until promoted. A replica catches up either by pulling transactions from the upstream cluster or by pulling differential backups from object storage. Sharded databases are not yet supported and role-based access control does not replicate. Generally available in Enterprise Edition, coming soon to Aura.
Neo4j Graph Analytics runs algorithms on dedicated compute machines, not inside the database JVM, scaled independently. Early Access starts in September; in Aura, sessions are billed only while running.
Seconds-scale agents suit Virtual Graph; agents that must respond in milliseconds need the graph held natively in AuraDB. Two storage models, chosen per workload.
Property graph queried with Cypher, natural language or direct syntax, against virtual or native graphs.
The article is silent on global identifiers; nodes are identified within a database.
The article does not describe ontology-driven inference.
AuraDB is a managed service, and the article also refers to Neo4j Enterprise Edition for self-managed deployments. Its capabilities arrive as instance types, editions and preview programmes a platform team selects.
RDF Views: one ALTER QUAD STORAGE statement maps the tables of any SQL system of record to triples computed at query time, with the SQL engine still holding and governing the rows. Snowflake, Databricks and BigQuery are SQL systems, so they are simply further systems of record for the same mechanism. Proven live on this page over the ScaleKG tables.
The engine compiles queries in several open-standards languages into SQL over the mapped tables at query time: SPARQL and SPASQL are demonstrated on this page, and GraphQL and GQL are stated by OpenLink. The generated SQL can be inspected; Query 8 shows a two-pattern SPARQL query compiling to 22,712 characters of SQL.
The agent-rdf-memory harness deployed on Virtuoso carries skills that generate ontologies and instance data from text (kg-generator, document-to-kg-skill) and from relational tables (linked-data-skills, which produces the ontology, the RDF View mapping and the rewrite rules), alongside Virtuoso's own RDF View generators. An LLM agent working through them can propose relationships the schema does not declare. This page's own ontology, quad map and rewrite rules were produced that way, and each is plain Turtle or SQL that is reviewed before it is deployed.
No database-count ceiling to plan around. Each domain lives in its own named graph with graph-level permissions (read, SPARQL write, sponge); RDF Views inherit the SQL table privileges of their source tables; and capacity grows by federating graphs and instances into a Semantic Web of purpose-specific graphs. This page is itself an example: the RDF View is hosted on demo.openlinksw.com, this collection's graph is hosted on URIBurner, and Query 9 joins the two in one statement.
Single-server deployments, and from Virtuoso 7 an Elastic cluster that shards data into self-contained partitions and can be resized. OpenLink reports Berlin SPARQL Benchmark runs against 50 and 150 billion triple datasets on the column-store cluster. Pay-as-you-go machine offers exist on AWS, Azure and Google Cloud, so the instance type is chosen per cloud.
Transactional replication (one-way or bi-directional with conflict resolution), snapshot replication (incremental or not) and RDF graph replication, where named graphs are published and subscribed in chain, star or bi-directional topologies. The replication documentation consulted does not say whether SQL users and roles replicate.
Graph analytics run in the engine through SQL, SPARQL and GQL over the same data, without compromising the standardized identifiers and multilingual capabilities of RDF, and with HTTP making each graph part of a Semantic Web, public or private. Virtuoso is available as pay-as-you-go machine offers on AWS, Azure and Google Cloud, so analytics capacity is chosen by instance type, and replication can carry heavy analytics on a separate instance from transactional load.
The same SPARQL runs against an RDF View over SQL tables or against triples held in the physical quad store, and a view can be copied into a physical graph. The latency tier is a deployment choice, not a change of model or language.
RDF queried with SPARQL, SQL, GraphQL and GQL, the open-standards variant of Cypher, and with SPASQL, which nests a SPARQL query inside a SQL SELECT so a graph result set joins native relational tables in one statement. Query 5 on this page does exactly that.
Every entity in the ScaleKG view has an HTTP IRI built from its key column, and URL rewrite rules make it resolve: the IRI answers with a 303 to a description page, and a DESCRIBE through the SPARQL endpoint returns its triples. The key becomes a hyperlink that any other graph, table or document can reference, so it acts as a super-key across stores. On this host, content negotiation for Turtle on the bare IRI returns 406.
An RDFS rule set derived from the ScaleKG TBox makes a query for skg:DataAsset return the 16 databases and 9 warehouse tables that were only ever typed as their subclasses; with no rule set the same query returns 0. Query 6 shows it live. Sub-property entailment over the view did not fire on this build, so Query 7 reads the property hierarchy from the TBox by joining it into the query.
Virtuoso is offered on-premise, as Docker containers, as cloud machine images on AWS, Azure and Google Cloud, and as a self-managed service on AWS, with OpenLink Managed services announced for release this month. It can be configured and administered in natural language through its bundled MCP tooling and packaged SKILL.md skills, as well as through SQL, Conductor and scripts. This page's own deployment, its tables, quad map, rewrite rules and grants, was driven that way by an agent calling the same OpenLink functions that the MCP tooling exposes.
AssessmentWhat it costs
Same idea, but Virtuoso's is shipping and demonstrated on this page, while Neo4j's is in public preview with general availability still to come. Neo4j's is aimed at three named warehouses; Virtuoso's works against any SQL system of record, which is what those warehouses are. Pointing it at one particular remote SQL engine is connection configuration that this page does not exercise.
Virtuoso edge

Evidence: Virtuoso: demonstrated on this page, Queries 1 to 9. Neo4j: the article, which gives public preview status.

Both compile graph queries to SQL, so the mechanism is shared and the differences favour Virtuoso. It does this for several open-standards languages where the article describes one, Cypher, and it exposes the compiled SQL, which this page demonstrates; the article does not say whether Virtual Graph's generated SQL can be inspected.
Virtuoso edge

Evidence: Virtuoso: SPARQL and SPASQL compilation demonstrated on this page, Query 8 shows the generated SQL; GraphQL and GQL stated by OpenLink. Neo4j: one sentence in the article, describing Cypher only.

Virtuoso's reach is wider: the harness generates ontologies and instance data from text as well as from tables, and this page's own ontology, quad map and rewrite rules came from it, as standards-based artefacts that can be reviewed. Neo4j ships its assistance inside the product and the article describes it for tables only, including relationships between undeclared keys. That last claim was not tested on either side here.
Virtuoso edge

Evidence: Virtuoso: demonstrated by how this page's ontology, quad map and rewrite rules were produced, with the skills documented in the repository. Neo4j: the article; its undeclared-key claim was not tested.

The article's 5-per-GB rule and its 100 and 250 caps are planning constraints of the database-per-tenant model, and Virtuoso's model does not need equivalents. A separate database is a harder storage boundary than a graph permission, but a federated set of named graphs lets one query span graphs and instances whenever access allows, which a database boundary forbids.
Virtuoso edge

Evidence: Virtuoso: demonstrated on this page, Query 9, and documented graph-level permissions. Neo4j: the article's figures.

The two ceilings are quoted in different units, machine memory against triple counts, so they cannot be compared number for number. Neo4j scales one managed instance up, on Google Cloud today with more clouds planned. Virtuoso documents scale-out as well as scale-up, to 150 billion triples, and is offered on-premise, in containers and on three clouds.
Virtuoso edge

Evidence: Virtuoso: OpenLink-reported benchmark figures and documented cloud offers. Neo4j: the article's figures.

Virtuoso documents more topologies, including writable bi-directional ones that the article's active-passive model excludes, plus snapshot and graph-level replication. The article's model has sharded databases unsupported, access control not replicated and Aura availability still to come. Neo4j states its limits plainly; whether SQL roles replicate in Virtuoso is not stated in the documentation consulted, and should be checked before it is relied on.
Virtuoso edge

Evidence: Both: vendor documentation, the Virtuoso replication pages consulted on 2026-09-30 and the article.

Virtuoso runs graph analytics today, per OpenLink, through SQL, SPARQL and GQL on instances sized for the job in three clouds, over standards-based identifiers and HTTP-addressable graphs. Neo4j's dedicated compute tier, billed per running session, is an Early Access Program for self-managed customers. Neither was benchmarked here, so this lean rests on availability and breadth, not on measured speed.
Virtuoso edge

Evidence: Virtuoso: stated by OpenLink, not benchmarked here. Neo4j: the article, which describes an Early Access Program.

Virtuoso's single query model across both tiers is a simplification. It does not make a warehouse-backed query as fast as a native one; the article's guidance on what each tier suits holds for both.
Virtuoso edge

Evidence: Virtuoso: documented, not demonstrated here. Neo4j: the article.

Cypher's compact pattern syntax and large practitioner base carry over to GQL, which Virtuoso also supports, so the languages are not where the two differ. What the article does not describe is SPASQL, or one engine answering in SPARQL, SQL, GraphQL and GQL over the same data. This page demonstrates SPARQL, SQL and SPASQL and does not exercise GQL.
Virtuoso edge

Evidence: Virtuoso: SPARQL, SQL and SPASQL demonstrated on this page; GraphQL and GQL stated by OpenLink. Neo4j: the article.

For a single estate this is a convenience. It becomes the main difference when graphs from several owners must be joined, which is where a Semantic Web of purpose-specific graphs earns its keep.
Virtuoso edge

Evidence: Virtuoso: demonstrated on this page, 67 of 67 entity IRIs resolve. Neo4j: the article is silent.

A silence in an article is not a gap in a product, so this axis records only what Virtuoso demonstrates here. Class entailment works over an RDF View; property entailment over a view needs the TBox joined in explicitly on this build, and combining SELECT DISTINCT, ORDER BY and inference raised an error.
Virtuoso edge

Evidence: Virtuoso: demonstrated on this page, Queries 6 and 7. Neo4j: the article is silent.

Virtuoso leads on operating the platform. An agent configures and administers the instance in natural language, which is demonstrated on this page and removes much of the operating effort a managed service exists to remove, and the deployment choice is the widest of the two: on-premise, containers, three clouds and a self-managed AWS service. Neo4j's one operational advantage, a generally available vendor-run service in AuraDB, is noted and does not outweigh that, particularly since Neo4j also offers a self-managed edition and OpenLink's managed service is announced for this month.
Virtuoso edge

Evidence: Neo4j: the article. Virtuoso: agent-driven configuration demonstrated on this page and the MCP tooling documented in the repository; deployment options stated by OpenLink; the managed service is announced, not yet released.

Live Demonstration

ScaleKG — The Article's Estate, Running

The demonstration is about a SQL system of record, which is what Snowflake, Databricks and BigQuery are to a graph layer. The article's scenario, a platform team running tenants, environments, agents and source-backed workloads, was built as ordinary SQL tables on demo.openlinksw.com, given an RDF View and an ontology, and every query below was executed against it before being written down. The data is synthetic and illustrative: it models the article's scenario and is not Neo4j data.

11
Normalised, foreign-key constrained, 76 synthetic rows on demo.openlinksw.com.
268
11 classes and 33 properties under schema.org supertypes, with a DataAsset hierarchy.
347
Computed at query time from the tables. Not one is stored.
9
Live queries
Three SPARQL, two SPASQL, one entailment, one TBox join, one compiled-SQL view and one federated query across two instances, all run before being written down.

SQL, step by step

Seven cards follow the build in the order a fresh database needs it, then one consolidated script for copy-and-run. The table and row statements are standard SQL; the ontology is plain Turtle; the IRI class, quad map and rewrite-rule statements are Virtuoso-specific and the part most likely to need adjusting on another version.

Eleven tables, foreign keys declared

SQL

The relational estate: regions, clusters, tenants, environments, graph databases, replication links, warehouse sources and tables, workloads, the workload-to-table reads and analytics jobs. Standard SQL that runs on effectively any engine; role is avoided as a table name because it is a reserved word in Virtuoso.

CREATE TABLE ScaleKG.kidehen.region (region_id INTEGER NOT NULL PRIMARY KEY, region_name VARCHAR(64) NOT NULL, cloud VARCHAR(16) NOT NULL, country_code VARCHAR(2) NOT NULL);

CREATE TABLE ScaleKG.kidehen.db_cluster (cluster_id INTEGER NOT NULL PRIMARY KEY, cluster_name VARCHAR(64) NOT NULL, region_id INTEGER NOT NULL, cluster_role VARCHAR(16) NOT NULL, ram_gb INTEGER NOT NULL, storage_gb INTEGER NOT NULL, edition VARCHAR(32) NOT NULL, FOREIGN KEY (region_id) REFERENCES ScaleKG.kidehen.region (region_id));

CREATE TABLE ScaleKG.kidehen.tenant (tenant_id INTEGER NOT NULL PRIMARY KEY, tenant_name VARCHAR(64) NOT NULL, tier VARCHAR(16) NOT NULL, region_id INTEGER NOT NULL, FOREIGN KEY (region_id) REFERENCES ScaleKG.kidehen.region (region_id));

CREATE TABLE ScaleKG.kidehen.environment (env_id INTEGER NOT NULL PRIMARY KEY, env_name VARCHAR(16) NOT NULL);

CREATE TABLE ScaleKG.kidehen.graph_database (db_id INTEGER NOT NULL PRIMARY KEY, db_name VARCHAR(64) NOT NULL, cluster_id INTEGER NOT NULL, tenant_id INTEGER NOT NULL, env_id INTEGER NOT NULL, purpose VARCHAR(96) NOT NULL, FOREIGN KEY (cluster_id) REFERENCES ScaleKG.kidehen.db_cluster (cluster_id), FOREIGN KEY (tenant_id) REFERENCES ScaleKG.kidehen.tenant (tenant_id), FOREIGN KEY (env_id) REFERENCES ScaleKG.kidehen.environment (env_id));

CREATE TABLE ScaleKG.kidehen.replication_link (link_id INTEGER NOT NULL PRIMARY KEY, source_db_id INTEGER NOT NULL, target_db_id INTEGER NOT NULL, sync_mode VARCHAR(32) NOT NULL, topology VARCHAR(16) NOT NULL, rbac_replicated INTEGER NOT NULL, FOREIGN KEY (source_db_id) REFERENCES ScaleKG.kidehen.graph_database (db_id), FOREIGN KEY (target_db_id) REFERENCES ScaleKG.kidehen.graph_database (db_id));

CREATE TABLE ScaleKG.kidehen.warehouse_source (src_id INTEGER NOT NULL PRIMARY KEY, src_name VARCHAR(32) NOT NULL, vendor VARCHAR(32) NOT NULL);

CREATE TABLE ScaleKG.kidehen.warehouse_table (wt_id INTEGER NOT NULL PRIMARY KEY, src_id INTEGER NOT NULL, table_name VARCHAR(32) NOT NULL, row_count INTEGER NOT NULL, FOREIGN KEY (src_id) REFERENCES ScaleKG.kidehen.warehouse_source (src_id));

CREATE TABLE ScaleKG.kidehen.workload (wl_id INTEGER NOT NULL PRIMARY KEY, wl_name VARCHAR(64) NOT NULL, wl_kind VARCHAR(16) NOT NULL, tenant_id INTEGER NOT NULL, db_id INTEGER, src_id INTEGER, latency_class VARCHAR(16) NOT NULL, FOREIGN KEY (tenant_id) REFERENCES ScaleKG.kidehen.tenant (tenant_id), FOREIGN KEY (db_id) REFERENCES ScaleKG.kidehen.graph_database (db_id), FOREIGN KEY (src_id) REFERENCES ScaleKG.kidehen.warehouse_source (src_id));

CREATE TABLE ScaleKG.kidehen.workload_reads (wl_id INTEGER NOT NULL, wt_id INTEGER NOT NULL, PRIMARY KEY (wl_id, wt_id), FOREIGN KEY (wl_id) REFERENCES ScaleKG.kidehen.workload (wl_id), FOREIGN KEY (wt_id) REFERENCES ScaleKG.kidehen.warehouse_table (wt_id));

CREATE TABLE ScaleKG.kidehen.analytics_job (job_id INTEGER NOT NULL PRIMARY KEY, db_id INTEGER NOT NULL, job_kind VARCHAR(24) NOT NULL, run_date DATE NOT NULL, billed_seconds INTEGER NOT NULL, FOREIGN KEY (db_id) REFERENCES ScaleKG.kidehen.graph_database (db_id));

Synthetic rows, one per table shown

SQL

Seventy-six rows in all. The data is synthetic and illustrative: it models the scenario in the article and is not Neo4j data.

-- One representative row per table; the batch script carries all 76.
INSERT INTO ScaleKG.kidehen.region VALUES (1, 'gcp-us-central1', 'Google Cloud', 'US');
INSERT INTO ScaleKG.kidehen.db_cluster VALUES (1, 'graph-bc-prod-us', 1, 'primary', 2048, 5000, 'business-critical');
INSERT INTO ScaleKG.kidehen.tenant VALUES (1, 'Acme Retail', 'enterprise', 1);
INSERT INTO ScaleKG.kidehen.environment VALUES (1, 'dev');
INSERT INTO ScaleKG.kidehen.graph_database VALUES (1, 'acme_prod', 1, 1, 4, 'customer-360 knowledge graph');
INSERT INTO ScaleKG.kidehen.replication_link VALUES (1, 1, 14, 'transaction-pull', 'active-passive', 0);
INSERT INTO ScaleKG.kidehen.warehouse_source VALUES (1, 'Snowflake', 'Snowflake Inc.');
INSERT INTO ScaleKG.kidehen.warehouse_table VALUES (1, 1, 'CUSTOMERS', 2400000);
INSERT INTO ScaleKG.kidehen.workload VALUES (1, 'support-copilot', 'agent', 1, 1, NULL, 'millisecond');
INSERT INTO ScaleKG.kidehen.workload_reads VALUES (2, 1);
INSERT INTO ScaleKG.kidehen.analytics_job VALUES (1, 1, 'ml-feature-prep', stringdate('2026-09-20'), 5400);

Ten IRI classes

SPARQL

Each IRI class turns a key column into a dereferenceable IRI. Through isql the statement needs the SPARQL keyword in front and the class name as an angle-bracket IRI. Each one took minutes on the shared demo server.

SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/region_iri> "http://demo.openlinksw.com/ScaleKG/region/%d#this" (in region_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri> "http://demo.openlinksw.com/ScaleKG/cluster/%d#this" (in cluster_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri> "http://demo.openlinksw.com/ScaleKG/tenant/%d#this" (in tenant_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/environment_iri> "http://demo.openlinksw.com/ScaleKG/environment/%d#this" (in env_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/database_iri> "http://demo.openlinksw.com/ScaleKG/database/%d#this" (in db_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri> "http://demo.openlinksw.com/ScaleKG/replication/%d#this" (in link_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/source_iri> "http://demo.openlinksw.com/ScaleKG/source/%d#this" (in src_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/wtable_iri> "http://demo.openlinksw.com/ScaleKG/table/%d#this" (in wt_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri> "http://demo.openlinksw.com/ScaleKG/workload/%d#this" (in wl_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/job_iri> "http://demo.openlinksw.com/ScaleKG/job/%d#this" (in job_id integer not null);

The ontology: every term the view uses, declared

Turtle

The vocabulary for the view's graph: 11 classes and 33 properties with labels, comments, domains and ranges, cross-referenced to schema.org supertypes, a DataAsset class hierarchy and a dependsOn property hierarchy. A check against the live graph found all 32 properties and 10 classes the view emits declared here; the only declared terms the view does not emit are the two abstract super-terms. Loaded into http://demo.openlinksw.com/schemas/ScaleKG/ and used to derive the urn:scalekg:inference rule set.

@prefix :       <http://demo.openlinksw.com/schemas/ScaleKG/> .
@prefix skg:    <http://demo.openlinksw.com/schemas/ScaleKG/> .
@prefix schema: <http://schema.org/> .
@prefix xsd:    <http://www.w3.org/2001/XMLSchema#> .
@prefix rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs:   <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl:    <http://www.w3.org/2002/07/owl#> .
@prefix skos:   <http://www.w3.org/2004/02/skos/core#> .
@prefix cdx:    <https://linkeddata.uriburner.com/DAV/demos/daas/ontology-terms#> .

# TBox for the ScaleKG RDF View on demo.openlinksw.com. The ontology is the entity
# <http://demo.openlinksw.com/schemas/ScaleKG/>; this document is a separate CreativeWork.

<http://demo.openlinksw.com/schemas/ScaleKG/ontology-document> a schema:CreativeWork ;
    schema:name "ScaleKG ontology (TBox)"@en ;
    schema:description "RDFS/OWL vocabulary for the ScaleKG demonstration estate: regions, clusters, tenants, graph databases, replication links, warehouse sources and tables, workloads and analytics jobs. Loaded into the named graph http://demo.openlinksw.com/schemas/ScaleKG/ on demo.openlinksw.com and used to derive the urn:scalekg:inference rule set."@en ;
    schema:dateCreated "2026-09-30T00:00:00Z"^^xsd:dateTime ;
    schema:dateModified "2026-09-30T00:00:00Z"^^xsd:dateTime ;
    schema:author <https://www.linkedin.com/in/kidehen#this> ;
    schema:about <http://demo.openlinksw.com/schemas/ScaleKG/> .

<http://demo.openlinksw.com/schemas/ScaleKG/> a owl:Ontology ;
    rdfs:label "ScaleKG ontology"@en ;
    rdfs:comment "Vocabulary for describing a graph-database estate (tenants, clusters, databases, replication) and the warehouse sources that virtual-graph workloads read in place."@en ;
    owl:versionInfo "1.0"@en .

# ── Classes ────────────────────────────────────────────────────────────────

skg:Region a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Region"@en ;
    rdfs:comment "A cloud region hosting one or more clusters."@en ;
    rdfs:subClassOf schema:Place .

skg:Cluster a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Cluster"@en ;
    rdfs:comment "A database cluster or instance with a fixed amount of memory and storage that hosts one or more graph databases."@en ;
    rdfs:subClassOf schema:Thing .

skg:Tenant a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Tenant"@en ;
    rdfs:comment "A customer organisation whose data is isolated in its own databases."@en ;
    rdfs:subClassOf schema:Organization .

skg:Environment a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Environment"@en ;
    rdfs:comment "A lifecycle stage such as dev, test, staging or prod."@en ;
    rdfs:subClassOf schema:DefinedTerm .

skg:DataAsset a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Data asset"@en ;
    rdfs:comment "Anything that stores queryable data: a natively stored graph database or a warehouse table read in place."@en ;
    rdfs:subClassOf schema:Dataset .

skg:GraphDatabase a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Graph database"@en ;
    rdfs:comment "One database inside a cluster, owned by a single tenant in a single environment."@en ;
    rdfs:subClassOf skg:DataAsset .

skg:WarehouseTable a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Warehouse table"@en ;
    rdfs:comment "A table in a data warehouse or lakehouse that a workload queries where it lives."@en ;
    rdfs:subClassOf skg:DataAsset .

skg:WarehouseSource a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Warehouse source"@en ;
    rdfs:comment "A warehouse or lakehouse platform that holds warehouse tables."@en ;
    rdfs:subClassOf schema:DataCatalog .

skg:ReplicationLink a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Replication link"@en ;
    rdfs:comment "A one-way link that keeps a target database in step with a source database on another cluster."@en ;
    rdfs:subClassOf schema:Intangible .

skg:Workload a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Workload"@en ;
    rdfs:comment "An agent, GraphRAG application, analytics batch or SaaS application that reads a database or a warehouse."@en ;
    rdfs:subClassOf schema:SoftwareApplication .

skg:AnalyticsJob a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Analytics job"@en ;
    rdfs:comment "A run of a graph-analytics job against a database, billed for the seconds it runs."@en ;
    rdfs:subClassOf schema:Action .

# ── Object properties ──────────────────────────────────────────────────────

skg:dependsOn a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "depends on"@en ;
    rdfs:comment "Super-property: the subject cannot operate without the object. runsOn, readsFrom, queriesVirtually, hostedOn and replicatedTo are all specialisations."@en ;
    rdfs:subPropertyOf cdx:dependsOn .

skg:runsOn a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "runs on"@en ;
    rdfs:comment "The natively stored graph database a workload uses."@en ;
    rdfs:domain skg:Workload ; rdfs:range skg:GraphDatabase ;
    rdfs:subPropertyOf skg:dependsOn .

skg:readsFrom a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "reads from"@en ;
    rdfs:comment "A warehouse table a virtual-graph workload reads in place."@en ;
    rdfs:domain skg:Workload ; rdfs:range skg:WarehouseTable ;
    rdfs:subPropertyOf skg:dependsOn .

skg:queriesVirtually a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "queries virtually"@en ;
    rdfs:comment "The warehouse source a workload queries through a virtual graph instead of a copy."@en ;
    rdfs:domain skg:Workload ; rdfs:range skg:WarehouseSource ;
    rdfs:subPropertyOf skg:dependsOn .

skg:hostedOn a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "hosted on"@en ;
    rdfs:comment "The cluster a graph database lives in."@en ;
    rdfs:domain skg:GraphDatabase ; rdfs:range skg:Cluster ;
    rdfs:subPropertyOf skg:dependsOn .

skg:replicatedTo a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "replicated to"@en ;
    rdfs:comment "The target database that continuously receives this database's changes."@en ;
    rdfs:domain skg:GraphDatabase ; rdfs:range skg:GraphDatabase ;
    rdfs:subPropertyOf skg:dependsOn .

skg:inRegion a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "in region"@en ;
    rdfs:comment "The region a cluster runs in."@en ;
    rdfs:domain skg:Cluster ; rdfs:range skg:Region .

skg:homeRegion a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "home region"@en ;
    rdfs:comment "The region a tenant is primarily served from."@en ;
    rdfs:domain skg:Tenant ; rdfs:range skg:Region .

skg:ownedBy a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "owned by"@en ;
    rdfs:comment "The tenant that owns a database."@en ;
    rdfs:domain skg:GraphDatabase ; rdfs:range skg:Tenant .

skg:forTenant a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "for tenant"@en ;
    rdfs:comment "The tenant a workload serves."@en ;
    rdfs:domain skg:Workload ; rdfs:range skg:Tenant .

skg:environment a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "environment"@en ;
    rdfs:comment "The lifecycle stage a database belongs to."@en ;
    rdfs:domain skg:GraphDatabase ; rdfs:range skg:Environment .

skg:inSource a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "in source"@en ;
    rdfs:comment "The warehouse source that holds a table."@en ;
    rdfs:domain skg:WarehouseTable ; rdfs:range skg:WarehouseSource .

skg:replicatesFrom a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "replicates from"@en ;
    rdfs:comment "The source database of a replication link."@en ;
    rdfs:domain skg:ReplicationLink ; rdfs:range skg:GraphDatabase .

skg:replicatesTo a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "replicates to"@en ;
    rdfs:comment "The target database of a replication link."@en ;
    rdfs:domain skg:ReplicationLink ; rdfs:range skg:GraphDatabase .

skg:ranOn a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "ran on"@en ;
    rdfs:comment "The database an analytics job ran against."@en ;
    rdfs:domain skg:AnalyticsJob ; rdfs:range skg:GraphDatabase .

# ── Datatype properties ────────────────────────────────────────────────────

skg:cloud a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "cloud"@en ; rdfs:comment "The cloud provider of a region."@en ;
    rdfs:domain skg:Region ; rdfs:range xsd:string .
skg:countryCode a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "country code"@en ; rdfs:comment "ISO 3166-1 alpha-2 country code of a region."@en ;
    rdfs:domain skg:Region ; rdfs:range xsd:string .
skg:clusterRole a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "cluster role"@en ; rdfs:comment "primary or secondary."@en ;
    rdfs:domain skg:Cluster ; rdfs:range xsd:string .
skg:ramGb a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "RAM (GB)"@en ; rdfs:comment "Memory of a cluster in gigabytes."@en ;
    rdfs:domain skg:Cluster ; rdfs:range xsd:integer .
skg:storageGb a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "storage (GB)"@en ; rdfs:comment "Storage of a cluster in gigabytes."@en ;
    rdfs:domain skg:Cluster ; rdfs:range xsd:integer .
skg:edition a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "edition"@en ; rdfs:comment "The service edition a cluster runs."@en ;
    rdfs:domain skg:Cluster ; rdfs:range xsd:string .
skg:tier a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "tier"@en ; rdfs:comment "The commercial tier of a tenant."@en ;
    rdfs:domain skg:Tenant ; rdfs:range xsd:string .
skg:purpose a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "purpose"@en ; rdfs:comment "What a database is for."@en ;
    rdfs:domain skg:GraphDatabase ; rdfs:range xsd:string .
skg:syncMode a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "sync mode"@en ; rdfs:comment "transaction-pull or differential-backup-pull."@en ;
    rdfs:domain skg:ReplicationLink ; rdfs:range xsd:string .
skg:topology a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "topology"@en ; rdfs:comment "The replication topology, active-passive here."@en ;
    rdfs:domain skg:ReplicationLink ; rdfs:range xsd:string .
skg:rbacReplicated a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "RBAC replicated"@en ; rdfs:comment "1 when role-based access rules travel with the replica, 0 when they must be recreated on the target."@en ;
    rdfs:domain skg:ReplicationLink ; rdfs:range xsd:integer .
skg:vendor a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "vendor"@en ; rdfs:comment "The company behind a warehouse source."@en ;
    rdfs:domain skg:WarehouseSource ; rdfs:range xsd:string .
skg:rowCount a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "row count"@en ; rdfs:comment "Approximate rows in a warehouse table."@en ;
    rdfs:domain skg:WarehouseTable ; rdfs:range xsd:integer .
skg:workloadKind a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "workload kind"@en ; rdfs:comment "agent, graphrag, analytics or saas-app."@en ;
    rdfs:domain skg:Workload ; rdfs:range xsd:string .
skg:latencyClass a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "latency class"@en ; rdfs:comment "millisecond for natively stored databases, second for warehouse-backed virtual graphs."@en ;
    rdfs:domain skg:Workload ; rdfs:range xsd:string .
skg:jobKind a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "job kind"@en ; rdfs:comment "ml-feature-prep, entity-resolution or exploratory-science."@en ;
    rdfs:domain skg:AnalyticsJob ; rdfs:range xsd:string .
skg:runDate a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "run date"@en ; rdfs:comment "The day an analytics job ran."@en ;
    rdfs:domain skg:AnalyticsJob ; rdfs:range xsd:date .
skg:billedSeconds a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "billed seconds"@en ; rdfs:comment "Seconds a job was billed, which is the seconds it ran."@en ;
    rdfs:domain skg:AnalyticsJob ; rdfs:range xsd:integer .

The RDF View: one ALTER QUAD STORAGE statement

SPARQL

One statement maps all eleven tables to 347 triples at query time in the named graph http://demo.openlinksw.com/ScaleKG#. Every table in the FROM list is fully qualified, and the two nullable foreign keys on workload carry an IS NOT NULL guard; without it the view raised sprintf errors on the rows where the key is NULL.

SPARQL
ALTER QUAD STORAGE virtrdf:DefaultQuadStorage
  FROM ScaleKG.kidehen.region AS r
  FROM ScaleKG.kidehen.db_cluster AS c
  FROM ScaleKG.kidehen.tenant AS t
  FROM ScaleKG.kidehen.environment AS e
  FROM ScaleKG.kidehen.graph_database AS d
  FROM ScaleKG.kidehen.replication_link AS l
  FROM ScaleKG.kidehen.warehouse_source AS ws
  FROM ScaleKG.kidehen.warehouse_table AS wt
  FROM ScaleKG.kidehen.workload AS w
  FROM ScaleKG.kidehen.workload_reads AS rd
  FROM ScaleKG.kidehen.analytics_job AS j
{
  GRAPH <http://demo.openlinksw.com/ScaleKG#>
  {
    <http://demo.openlinksw.com/schemas/ScaleKG/region_iri>(r.region_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/Region> as virtrdf:ScaleKG-region-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/region_iri>(r.region_id) <http://schema.org/name> r.region_name as virtrdf:ScaleKG-region-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/region_iri>(r.region_id) <http://demo.openlinksw.com/schemas/ScaleKG/cloud> r.cloud as virtrdf:ScaleKG-region-cloud .
    <http://demo.openlinksw.com/schemas/ScaleKG/region_iri>(r.region_id) <http://demo.openlinksw.com/schemas/ScaleKG/countryCode> r.country_code as virtrdf:ScaleKG-region-country .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/Cluster> as virtrdf:ScaleKG-cluster-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://schema.org/name> c.cluster_name as virtrdf:ScaleKG-cluster-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://demo.openlinksw.com/schemas/ScaleKG/clusterRole> c.cluster_role as virtrdf:ScaleKG-cluster-role .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://demo.openlinksw.com/schemas/ScaleKG/ramGb> c.ram_gb as virtrdf:ScaleKG-cluster-ram .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://demo.openlinksw.com/schemas/ScaleKG/storageGb> c.storage_gb as virtrdf:ScaleKG-cluster-storage .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://demo.openlinksw.com/schemas/ScaleKG/edition> c.edition as virtrdf:ScaleKG-cluster-edition .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://demo.openlinksw.com/schemas/ScaleKG/inRegion> <http://demo.openlinksw.com/schemas/ScaleKG/region_iri>(c.region_id) as virtrdf:ScaleKG-cluster-region .
    <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri>(t.tenant_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/Tenant> as virtrdf:ScaleKG-tenant-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri>(t.tenant_id) <http://schema.org/name> t.tenant_name as virtrdf:ScaleKG-tenant-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri>(t.tenant_id) <http://demo.openlinksw.com/schemas/ScaleKG/tier> t.tier as virtrdf:ScaleKG-tenant-tier .
    <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri>(t.tenant_id) <http://demo.openlinksw.com/schemas/ScaleKG/homeRegion> <http://demo.openlinksw.com/schemas/ScaleKG/region_iri>(t.region_id) as virtrdf:ScaleKG-tenant-region .
    <http://demo.openlinksw.com/schemas/ScaleKG/environment_iri>(e.env_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/Environment> as virtrdf:ScaleKG-env-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/environment_iri>(e.env_id) <http://schema.org/name> e.env_name as virtrdf:ScaleKG-env-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(d.db_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/GraphDatabase> as virtrdf:ScaleKG-db-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(d.db_id) <http://schema.org/name> d.db_name as virtrdf:ScaleKG-db-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(d.db_id) <http://demo.openlinksw.com/schemas/ScaleKG/purpose> d.purpose as virtrdf:ScaleKG-db-purpose .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(d.db_id) <http://demo.openlinksw.com/schemas/ScaleKG/hostedOn> <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(d.cluster_id) as virtrdf:ScaleKG-db-cluster .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(d.db_id) <http://demo.openlinksw.com/schemas/ScaleKG/ownedBy> <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri>(d.tenant_id) as virtrdf:ScaleKG-db-tenant .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(d.db_id) <http://demo.openlinksw.com/schemas/ScaleKG/environment> <http://demo.openlinksw.com/schemas/ScaleKG/environment_iri>(d.env_id) as virtrdf:ScaleKG-db-env .
    <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri>(l.link_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/ReplicationLink> as virtrdf:ScaleKG-link-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri>(l.link_id) <http://demo.openlinksw.com/schemas/ScaleKG/syncMode> l.sync_mode as virtrdf:ScaleKG-link-mode .
    <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri>(l.link_id) <http://demo.openlinksw.com/schemas/ScaleKG/topology> l.topology as virtrdf:ScaleKG-link-topology .
    <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri>(l.link_id) <http://demo.openlinksw.com/schemas/ScaleKG/rbacReplicated> l.rbac_replicated as virtrdf:ScaleKG-link-rbac .
    <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri>(l.link_id) <http://demo.openlinksw.com/schemas/ScaleKG/replicatesFrom> <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(l.source_db_id) as virtrdf:ScaleKG-link-from .
    <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri>(l.link_id) <http://demo.openlinksw.com/schemas/ScaleKG/replicatesTo> <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(l.target_db_id) as virtrdf:ScaleKG-link-to .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(l.source_db_id) <http://demo.openlinksw.com/schemas/ScaleKG/replicatedTo> <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(l.target_db_id) as virtrdf:ScaleKG-db-replicated-to .
    <http://demo.openlinksw.com/schemas/ScaleKG/source_iri>(ws.src_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/WarehouseSource> as virtrdf:ScaleKG-src-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/source_iri>(ws.src_id) <http://schema.org/name> ws.src_name as virtrdf:ScaleKG-src-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/source_iri>(ws.src_id) <http://demo.openlinksw.com/schemas/ScaleKG/vendor> ws.vendor as virtrdf:ScaleKG-src-vendor .
    <http://demo.openlinksw.com/schemas/ScaleKG/wtable_iri>(wt.wt_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/WarehouseTable> as virtrdf:ScaleKG-wt-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/wtable_iri>(wt.wt_id) <http://schema.org/name> wt.table_name as virtrdf:ScaleKG-wt-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/wtable_iri>(wt.wt_id) <http://demo.openlinksw.com/schemas/ScaleKG/rowCount> wt.row_count as virtrdf:ScaleKG-wt-rows .
    <http://demo.openlinksw.com/schemas/ScaleKG/wtable_iri>(wt.wt_id) <http://demo.openlinksw.com/schemas/ScaleKG/inSource> <http://demo.openlinksw.com/schemas/ScaleKG/source_iri>(wt.src_id) as virtrdf:ScaleKG-wt-source .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/Workload> as virtrdf:ScaleKG-wl-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://schema.org/name> w.wl_name as virtrdf:ScaleKG-wl-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://demo.openlinksw.com/schemas/ScaleKG/workloadKind> w.wl_kind as virtrdf:ScaleKG-wl-kind .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://demo.openlinksw.com/schemas/ScaleKG/latencyClass> w.latency_class as virtrdf:ScaleKG-wl-latency .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://demo.openlinksw.com/schemas/ScaleKG/forTenant> <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri>(w.tenant_id) as virtrdf:ScaleKG-wl-tenant .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://demo.openlinksw.com/schemas/ScaleKG/runsOn> <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(w.db_id) where (^{w.}^.db_id is not null) as virtrdf:ScaleKG-wl-db .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://demo.openlinksw.com/schemas/ScaleKG/queriesVirtually> <http://demo.openlinksw.com/schemas/ScaleKG/source_iri>(w.src_id) where (^{w.}^.src_id is not null) as virtrdf:ScaleKG-wl-src .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(rd.wl_id) <http://demo.openlinksw.com/schemas/ScaleKG/readsFrom> <http://demo.openlinksw.com/schemas/ScaleKG/wtable_iri>(rd.wt_id) as virtrdf:ScaleKG-wl-reads .
    <http://demo.openlinksw.com/schemas/ScaleKG/job_iri>(j.job_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/AnalyticsJob> as virtrdf:ScaleKG-job-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/job_iri>(j.job_id) <http://demo.openlinksw.com/schemas/ScaleKG/jobKind> j.job_kind as virtrdf:ScaleKG-job-kind .
    <http://demo.openlinksw.com/schemas/ScaleKG/job_iri>(j.job_id) <http://demo.openlinksw.com/schemas/ScaleKG/runDate> j.run_date as virtrdf:ScaleKG-job-date .
    <http://demo.openlinksw.com/schemas/ScaleKG/job_iri>(j.job_id) <http://demo.openlinksw.com/schemas/ScaleKG/billedSeconds> j.billed_seconds as virtrdf:ScaleKG-job-seconds .
    <http://demo.openlinksw.com/schemas/ScaleKG/job_iri>(j.job_id) <http://demo.openlinksw.com/schemas/ScaleKG/ranOn> <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(j.db_id) as virtrdf:ScaleKG-job-db .
  }
} ;

URL rewrite rules: making the entity IRIs resolve

SQL

The RDF View defines the IRIs but does not by itself make them resolve: before these rules were installed every entity IRI answered 404. The generated script, from the OpenLink RDFVIEW_GENERATE_DATA_RULES function, defines two virtual directories, /ScaleKG for the data and /schemas/ScaleKG for the vocabulary. The describe rules were then edited to the pattern wanted for these demos, /describe/?uri={encoded entity IRI}&graph={encoded view graph IRI}, for example http://demo.openlinksw.com/describe/?uri=http%3A%2F%2Fdemo.openlinksw.com%2FScaleKG%2Ftenant%2F1%23this&graph=http%3A%2F%2Fdemo.openlinksw.com%2FScaleKG%23, so a browser is sent by a 303 redirect to a description page scoped to the view's named graph; clients that ask for RDF are routed to a DESCRIBE.

DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'scalekg_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=DESCRIBE+%%3Chttp%%3A//^{URIQADefaultHost}^%U%%23this%%3E+FROM+%%3Chttp%%3A//^{URIQADefaultHost}^/ScaleKG%%23%%3E&format=%U',
vector('path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)|(text/n3)|(application/json)|(text/turtle)',
2,
null
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'scalekg_rule4',
1,
'/ScaleKG/stat([^#]*)',
vector('path'),
1,
'/sparql?query=DESCRIBE+%%3Chttp%%3A//^{URIQADefaultHost}^/ScaleKG/stat%%23%%3E+%%3Fo+FROM+%%3Chttp%%3A//^{URIQADefaultHost}^/ScaleKG%%23%%3E+WHERE+{+%%3Chttp%%3A//^{URIQADefaultHost}^/ScaleKG/stat%%23%%3E+%%3Fp+%%3Fo+}&format=%U',
vector('*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)|(text/n3)|(application/json)|(text/turtle)',
2,
null
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'scalekg_rule6',
1,
'/ScaleKG/objects/([^#]*)',
vector('path'),
1,
'/sparql?query=DESCRIBE+%%3Chttp%%3A//^{URIQADefaultHost}^/ScaleKG/objects/%U%%3E+FROM+%%3Chttp%%3A//^{URIQADefaultHost}^/ScaleKG%%23%%3E&format=%U',
vector('path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)|(text/n3)|(application/json)|(text/turtle)',
2,
null
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'scalekg_rule1',
1,
'([^#]*)',
vector('path'),
1,
'/describe/?uri=http%%3A%%2F%%2F^{URIQADefaultHost}^%U%%23this&graph=http%%3A%%2F%%2F^{URIQADefaultHost}^%%2FScaleKG%%23',
vector('path'),
null,
null,
2,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'scalekg_rule7',
1,
'/ScaleKG/stat([^#]*)',
vector('path'),
1,
'/describe/?uri=http%%3A%%2F%%2F^{URIQADefaultHost}^%%2FScaleKG%%2Fstat%%23&graph=http%%3A%%2F%%2F^{URIQADefaultHost}^%%2FScaleKG%%23',
vector('path'),
null,
null,
2,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'scalekg_rule5',
1,
'/ScaleKG/objects/(.*)',
vector('path'),
1,
'/services/rdf/object.binary?path=%%2FScaleKG%%2Fobjects%%2F%U&accept=%U',
vector('path', '*accept*'),
null,
null,
2,
null
);
DB.DBA.URLREWRITE_CREATE_RULELIST ( 'scalekg_rule_list1', 1, vector ( 'scalekg_rule1', 'scalekg_rule7', 'scalekg_rule5', 'scalekg_rule2', 'scalekg_rule4', 'scalekg_rule6'));
DB.DBA.VHOST_REMOVE (lpath=>'/ScaleKG');
DB.DBA.VHOST_DEFINE (lpath=>'/ScaleKG', ppath=>'/', vsp_user=>'dba', is_dav=>0,
is_brws=>0, opts=>vector ('url_rewrite', 'scalekg_rule_list1')
);DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'scalekg_owl_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=DESCRIBE+%%3Chttp%%3A//^{URIQADefaultHost}^%U%%3E+FROM+%%3Chttp%%3A//^{URIQADefaultHost}^/schemas/ScaleKG%%23%%3E&format=%U',
vector('path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)|(text/n3)|(application/json)|(text/turtle)',
2,
null
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'scalekg_owl_rule1',
1,
'([^#]*)',
vector('path'),
1,
'/describe/?uri=http%%3A%%2F%%2F^{URIQADefaultHost}^%U&graph=http%%3A%%2F%%2F^{URIQADefaultHost}^%%2Fschemas%%2FScaleKG%%2F',
vector('path'),
null,
null,
2,
303
);
DB.DBA.URLREWRITE_CREATE_RULELIST ( 'scalekg_owl_rule_list1', 1, vector ( 'scalekg_owl_rule1', 'scalekg_owl_rule2'));
DB.DBA.VHOST_REMOVE (lpath=>'/schemas/ScaleKG');
DB.DBA.VHOST_DEFINE (lpath=>'/schemas/ScaleKG', ppath=>'/', vsp_user=>'dba', is_dav=>0,
is_brws=>0, opts=>vector ('url_rewrite', 'scalekg_owl_rule_list1')
);

Access: the view inherits SQL grants

SQL

An RDF View has no access rules of its own; it inherits the SQL privileges of its source tables. SPARQL serves the anonymous endpoint, PUBLIC the rest, and demo and vdb the SPASQL Query Builder.

GRANT SELECT ON ScaleKG.kidehen.region TO "SPARQL";
GRANT SELECT ON ScaleKG.kidehen.region TO PUBLIC;
GRANT SELECT ON ScaleKG.kidehen.region TO "demo";
GRANT SELECT ON ScaleKG.kidehen.region TO "vdb";
-- ...repeated for each of the 11 tables (44 statements in the batch script)

One script: tables, rows, IRI classes, RDF View, grants

SQL

The consolidated copy-paste script for running the whole demonstration on your own Virtuoso. Its purpose is execution, not exposition: the same statements as the seven cards above in the order a fresh database needs them. The table and row statements are standard SQL; the IRI class and quad map statements are Virtuoso-specific and are the part most likely to need adjusting on another version. Two grants name accounts that exist on demo.openlinksw.com and should be dropped elsewhere.

-- scalekg-scale-ai-production.sql
-- Consolidated batch for the ScaleKG estate used by the Neo4j "Scale AI into production" meshup.
-- Run:  isql <host>:1111 <user> <password> < scalekg-scale-ai-production.sql
--       or paste into Virtuoso Conductor > Database > Interactive SQL.
-- Order: tables, rows, IRI classes, ontology, the RDF View (quad map), grants, URL rewrite rules. Every statement below was
-- executed on demo.openlinksw.com as user kidehen; the data is synthetic and illustrative.
-- Part 1 (tables, rows, grants) is standard SQL. Parts 2 and 3 (CREATE IRI CLASS and ALTER QUAD
-- STORAGE) are Virtuoso-specific and need the SPARQL keyword in front when sent through isql.

-- ── Part 1a: tables ─────────────────────────────────────────────────────────

CREATE TABLE ScaleKG.kidehen.region (region_id INTEGER NOT NULL PRIMARY KEY, region_name VARCHAR(64) NOT NULL, cloud VARCHAR(16) NOT NULL, country_code VARCHAR(2) NOT NULL);
CREATE TABLE ScaleKG.kidehen.db_cluster (cluster_id INTEGER NOT NULL PRIMARY KEY, cluster_name VARCHAR(64) NOT NULL, region_id INTEGER NOT NULL, cluster_role VARCHAR(16) NOT NULL, ram_gb INTEGER NOT NULL, storage_gb INTEGER NOT NULL, edition VARCHAR(32) NOT NULL, FOREIGN KEY (region_id) REFERENCES ScaleKG.kidehen.region (region_id));
CREATE TABLE ScaleKG.kidehen.tenant (tenant_id INTEGER NOT NULL PRIMARY KEY, tenant_name VARCHAR(64) NOT NULL, tier VARCHAR(16) NOT NULL, region_id INTEGER NOT NULL, FOREIGN KEY (region_id) REFERENCES ScaleKG.kidehen.region (region_id));
CREATE TABLE ScaleKG.kidehen.environment (env_id INTEGER NOT NULL PRIMARY KEY, env_name VARCHAR(16) NOT NULL);
CREATE TABLE ScaleKG.kidehen.graph_database (db_id INTEGER NOT NULL PRIMARY KEY, db_name VARCHAR(64) NOT NULL, cluster_id INTEGER NOT NULL, tenant_id INTEGER NOT NULL, env_id INTEGER NOT NULL, purpose VARCHAR(96) NOT NULL, FOREIGN KEY (cluster_id) REFERENCES ScaleKG.kidehen.db_cluster (cluster_id), FOREIGN KEY (tenant_id) REFERENCES ScaleKG.kidehen.tenant (tenant_id), FOREIGN KEY (env_id) REFERENCES ScaleKG.kidehen.environment (env_id));
CREATE TABLE ScaleKG.kidehen.replication_link (link_id INTEGER NOT NULL PRIMARY KEY, source_db_id INTEGER NOT NULL, target_db_id INTEGER NOT NULL, sync_mode VARCHAR(32) NOT NULL, topology VARCHAR(16) NOT NULL, rbac_replicated INTEGER NOT NULL, FOREIGN KEY (source_db_id) REFERENCES ScaleKG.kidehen.graph_database (db_id), FOREIGN KEY (target_db_id) REFERENCES ScaleKG.kidehen.graph_database (db_id));
CREATE TABLE ScaleKG.kidehen.warehouse_source (src_id INTEGER NOT NULL PRIMARY KEY, src_name VARCHAR(32) NOT NULL, vendor VARCHAR(32) NOT NULL);
CREATE TABLE ScaleKG.kidehen.warehouse_table (wt_id INTEGER NOT NULL PRIMARY KEY, src_id INTEGER NOT NULL, table_name VARCHAR(32) NOT NULL, row_count INTEGER NOT NULL, FOREIGN KEY (src_id) REFERENCES ScaleKG.kidehen.warehouse_source (src_id));
CREATE TABLE ScaleKG.kidehen.workload (wl_id INTEGER NOT NULL PRIMARY KEY, wl_name VARCHAR(64) NOT NULL, wl_kind VARCHAR(16) NOT NULL, tenant_id INTEGER NOT NULL, db_id INTEGER, src_id INTEGER, latency_class VARCHAR(16) NOT NULL, FOREIGN KEY (tenant_id) REFERENCES ScaleKG.kidehen.tenant (tenant_id), FOREIGN KEY (db_id) REFERENCES ScaleKG.kidehen.graph_database (db_id), FOREIGN KEY (src_id) REFERENCES ScaleKG.kidehen.warehouse_source (src_id));
CREATE TABLE ScaleKG.kidehen.workload_reads (wl_id INTEGER NOT NULL, wt_id INTEGER NOT NULL, PRIMARY KEY (wl_id, wt_id), FOREIGN KEY (wl_id) REFERENCES ScaleKG.kidehen.workload (wl_id), FOREIGN KEY (wt_id) REFERENCES ScaleKG.kidehen.warehouse_table (wt_id));
CREATE TABLE ScaleKG.kidehen.analytics_job (job_id INTEGER NOT NULL PRIMARY KEY, db_id INTEGER NOT NULL, job_kind VARCHAR(24) NOT NULL, run_date DATE NOT NULL, billed_seconds INTEGER NOT NULL, FOREIGN KEY (db_id) REFERENCES ScaleKG.kidehen.graph_database (db_id));

-- ── Part 1b: rows (76) ──────────────────────────────────────────────────────

INSERT INTO ScaleKG.kidehen.region VALUES (1, 'gcp-us-central1', 'Google Cloud', 'US');
INSERT INTO ScaleKG.kidehen.region VALUES (2, 'gcp-europe-west4', 'Google Cloud', 'NL');
INSERT INTO ScaleKG.kidehen.region VALUES (3, 'aws-us-east-1', 'AWS', 'US');
INSERT INTO ScaleKG.kidehen.region VALUES (4, 'azure-westeurope', 'Azure', 'NL');
INSERT INTO ScaleKG.kidehen.db_cluster VALUES (1, 'graph-bc-prod-us', 1, 'primary', 2048, 5000, 'business-critical');
INSERT INTO ScaleKG.kidehen.db_cluster VALUES (2, 'graph-bc-dr-eu', 2, 'secondary', 512, 1500, 'business-critical');
INSERT INTO ScaleKG.kidehen.db_cluster VALUES (3, 'graph-vdc-shared', 3, 'primary', 256, 1000, 'virtual-dedicated');
INSERT INTO ScaleKG.kidehen.db_cluster VALUES (4, 'graph-selfmanaged-eu', 4, 'primary', 128, 800, 'self-managed-enterprise');
INSERT INTO ScaleKG.kidehen.tenant VALUES (1, 'Acme Retail', 'enterprise', 1);
INSERT INTO ScaleKG.kidehen.tenant VALUES (2, 'Borealis Bank', 'enterprise', 1);
INSERT INTO ScaleKG.kidehen.tenant VALUES (3, 'Cobalt Health', 'enterprise', 1);
INSERT INTO ScaleKG.kidehen.tenant VALUES (4, 'Dunmore Logistics', 'growth', 3);
INSERT INTO ScaleKG.kidehen.tenant VALUES (5, 'Ember Media', 'growth', 3);
INSERT INTO ScaleKG.kidehen.tenant VALUES (6, 'Fjord Energy', 'enterprise', 4);
INSERT INTO ScaleKG.kidehen.environment VALUES (1, 'dev');
INSERT INTO ScaleKG.kidehen.environment VALUES (2, 'test');
INSERT INTO ScaleKG.kidehen.environment VALUES (3, 'staging');
INSERT INTO ScaleKG.kidehen.environment VALUES (4, 'prod');
INSERT INTO ScaleKG.kidehen.graph_database VALUES (1, 'acme_prod', 1, 1, 4, 'customer-360 knowledge graph');
INSERT INTO ScaleKG.kidehen.graph_database VALUES (2, 'acme_staging', 1, 1, 3, 'customer-360 staging');
INSERT INTO ScaleKG.kidehen.graph_database VALUES (3, 'acme_dev', 3, 1, 1, 'customer-360 development');
INSERT INTO ScaleKG.kidehen.graph_database VALUES (4, 'borealis_prod', 1, 2, 4, 'fraud-ring detection');
INSERT INTO ScaleKG.kidehen.graph_database VALUES (5, 'borealis_test', 3, 2, 2, 'fraud-ring detection test');
INSERT INTO ScaleKG.kidehen.graph_database VALUES (6, 'cobalt_prod', 1, 3, 4, 'clinical-trial knowledge domain');
INSERT INTO ScaleKG.kidehen.graph_database VALUES (7, 'cobalt_agent_kb', 1, 3, 4, 'agent knowledge domain: trial protocols');
INSERT INTO ScaleKG.kidehen.graph_database VALUES (8, 'dunmore_prod', 3, 4, 4, 'route network graph');
INSERT INTO ScaleKG.kidehen.graph_database VALUES (9, 'dunmore_analytics', 3, 4, 4, 'analytical graph kept apart from transactional');
INSERT INTO ScaleKG.kidehen.graph_database VALUES (10, 'ember_prod', 3, 5, 4, 'content graph');
INSERT INTO ScaleKG.kidehen.graph_database VALUES (11, 'ember_dev', 3, 5, 1, 'content graph development');
INSERT INTO ScaleKG.kidehen.graph_database VALUES (12, 'fjord_prod', 4, 6, 4, 'asset dependency graph');
INSERT INTO ScaleKG.kidehen.graph_database VALUES (13, 'fjord_staging', 4, 6, 3, 'asset dependency staging');
INSERT INTO ScaleKG.kidehen.graph_database VALUES (14, 'acme_prod_replica', 2, 1, 4, 'replica of acme_prod');
INSERT INTO ScaleKG.kidehen.graph_database VALUES (15, 'borealis_prod_replica', 2, 2, 4, 'replica of borealis_prod');
INSERT INTO ScaleKG.kidehen.graph_database VALUES (16, 'cobalt_prod_replica', 2, 3, 4, 'replica of cobalt_prod');
INSERT INTO ScaleKG.kidehen.replication_link VALUES (1, 1, 14, 'transaction-pull', 'active-passive', 0);
INSERT INTO ScaleKG.kidehen.replication_link VALUES (2, 4, 15, 'differential-backup-pull', 'active-passive', 0);
INSERT INTO ScaleKG.kidehen.replication_link VALUES (3, 6, 16, 'transaction-pull', 'active-passive', 0);
INSERT INTO ScaleKG.kidehen.warehouse_source VALUES (1, 'Snowflake', 'Snowflake Inc.');
INSERT INTO ScaleKG.kidehen.warehouse_source VALUES (2, 'Databricks', 'Databricks Inc.');
INSERT INTO ScaleKG.kidehen.warehouse_source VALUES (3, 'BigQuery', 'Google');
INSERT INTO ScaleKG.kidehen.warehouse_table VALUES (1, 1, 'CUSTOMERS', 2400000);
INSERT INTO ScaleKG.kidehen.warehouse_table VALUES (2, 1, 'ORDERS', 18000000);
INSERT INTO ScaleKG.kidehen.warehouse_table VALUES (3, 1, 'PRODUCTS', 85000);
INSERT INTO ScaleKG.kidehen.warehouse_table VALUES (4, 2, 'CLAIMS', 6200000);
INSERT INTO ScaleKG.kidehen.warehouse_table VALUES (5, 2, 'PROVIDERS', 41000);
INSERT INTO ScaleKG.kidehen.warehouse_table VALUES (6, 3, 'SHIPMENTS', 9300000);
INSERT INTO ScaleKG.kidehen.warehouse_table VALUES (7, 3, 'DEPOTS', 620);
INSERT INTO ScaleKG.kidehen.warehouse_table VALUES (8, 2, 'TRANSACTIONS', 51000000);
INSERT INTO ScaleKG.kidehen.warehouse_table VALUES (9, 2, 'ACCOUNTS', 1800000);
INSERT INTO ScaleKG.kidehen.workload VALUES (1, 'support-copilot', 'agent', 1, 1, NULL, 'millisecond');
INSERT INTO ScaleKG.kidehen.workload VALUES (2, 'warehouse-graphrag', 'graphrag', 1, NULL, 1, 'second');
INSERT INTO ScaleKG.kidehen.workload VALUES (3, 'fraud-ring-scorer', 'agent', 2, 4, NULL, 'millisecond');
INSERT INTO ScaleKG.kidehen.workload VALUES (4, 'txn-multihop-explorer', 'graphrag', 2, NULL, 2, 'second');
INSERT INTO ScaleKG.kidehen.workload VALUES (5, 'trial-protocol-agent', 'agent', 3, 7, NULL, 'millisecond');
INSERT INTO ScaleKG.kidehen.workload VALUES (6, 'claims-enrichment-batch', 'analytics', 3, NULL, 2, 'second');
INSERT INTO ScaleKG.kidehen.workload VALUES (7, 'route-optimizer', 'saas-app', 4, 8, NULL, 'millisecond');
INSERT INTO ScaleKG.kidehen.workload VALUES (8, 'shipment-analyst', 'graphrag', 4, NULL, 3, 'second');
INSERT INTO ScaleKG.kidehen.workload VALUES (9, 'content-recs', 'saas-app', 5, 10, NULL, 'millisecond');
INSERT INTO ScaleKG.kidehen.workload VALUES (10, 'asset-dependency-agent', 'agent', 6, 12, NULL, 'millisecond');
INSERT INTO ScaleKG.kidehen.workload_reads VALUES (2, 1);
INSERT INTO ScaleKG.kidehen.workload_reads VALUES (2, 2);
INSERT INTO ScaleKG.kidehen.workload_reads VALUES (2, 3);
INSERT INTO ScaleKG.kidehen.workload_reads VALUES (4, 8);
INSERT INTO ScaleKG.kidehen.workload_reads VALUES (4, 9);
INSERT INTO ScaleKG.kidehen.workload_reads VALUES (6, 4);
INSERT INTO ScaleKG.kidehen.workload_reads VALUES (6, 5);
INSERT INTO ScaleKG.kidehen.workload_reads VALUES (8, 6);
INSERT INTO ScaleKG.kidehen.workload_reads VALUES (8, 7);
INSERT INTO ScaleKG.kidehen.analytics_job VALUES (1, 1, 'ml-feature-prep', stringdate('2026-09-20'), 5400);
INSERT INTO ScaleKG.kidehen.analytics_job VALUES (2, 4, 'entity-resolution', stringdate('2026-09-21'), 3600);
INSERT INTO ScaleKG.kidehen.analytics_job VALUES (3, 9, 'exploratory-science', stringdate('2026-09-22'), 1800);
INSERT INTO ScaleKG.kidehen.analytics_job VALUES (4, 1, 'ml-feature-prep', stringdate('2026-09-27'), 5100);
INSERT INTO ScaleKG.kidehen.analytics_job VALUES (5, 4, 'entity-resolution', stringdate('2026-09-28'), 4200);
INSERT INTO ScaleKG.kidehen.analytics_job VALUES (6, 9, 'ml-feature-prep', stringdate('2026-09-25'), 7200);
INSERT INTO ScaleKG.kidehen.analytics_job VALUES (7, 12, 'exploratory-science', stringdate('2026-09-26'), 900);
INSERT INTO ScaleKG.kidehen.analytics_job VALUES (8, 6, 'entity-resolution', stringdate('2026-09-29'), 2700);

-- ── Part 2: IRI classes (one per entity; each can take minutes on a busy server) ──

SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/region_iri> "http://demo.openlinksw.com/ScaleKG/region/%d#this" (in region_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri> "http://demo.openlinksw.com/ScaleKG/cluster/%d#this" (in cluster_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri> "http://demo.openlinksw.com/ScaleKG/tenant/%d#this" (in tenant_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/environment_iri> "http://demo.openlinksw.com/ScaleKG/environment/%d#this" (in env_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/database_iri> "http://demo.openlinksw.com/ScaleKG/database/%d#this" (in db_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri> "http://demo.openlinksw.com/ScaleKG/replication/%d#this" (in link_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/source_iri> "http://demo.openlinksw.com/ScaleKG/source/%d#this" (in src_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/wtable_iri> "http://demo.openlinksw.com/ScaleKG/table/%d#this" (in wt_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri> "http://demo.openlinksw.com/ScaleKG/workload/%d#this" (in wl_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/job_iri> "http://demo.openlinksw.com/ScaleKG/job/%d#this" (in job_id integer not null);

-- ── Part 2b: the ontology (TBox) and the inference rule set derived from it ──

DB.DBA.TTLP('@prefix :       <http://demo.openlinksw.com/schemas/ScaleKG/> .
@prefix skg:    <http://demo.openlinksw.com/schemas/ScaleKG/> .
@prefix schema: <http://schema.org/> .
@prefix xsd:    <http://www.w3.org/2001/XMLSchema#> .
@prefix rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs:   <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl:    <http://www.w3.org/2002/07/owl#> .
@prefix skos:   <http://www.w3.org/2004/02/skos/core#> .
@prefix cdx:    <https://linkeddata.uriburner.com/DAV/demos/daas/ontology-terms#> .

# TBox for the ScaleKG RDF View on demo.openlinksw.com. The ontology is the entity
# <http://demo.openlinksw.com/schemas/ScaleKG/>; this document is a separate CreativeWork.

<http://demo.openlinksw.com/schemas/ScaleKG/ontology-document> a schema:CreativeWork ;
    schema:name "ScaleKG ontology (TBox)"@en ;
    schema:description "RDFS/OWL vocabulary for the ScaleKG demonstration estate: regions, clusters, tenants, graph databases, replication links, warehouse sources and tables, workloads and analytics jobs. Loaded into the named graph http://demo.openlinksw.com/schemas/ScaleKG/ on demo.openlinksw.com and used to derive the urn:scalekg:inference rule set."@en ;
    schema:dateCreated "2026-09-30T00:00:00Z"^^xsd:dateTime ;
    schema:dateModified "2026-09-30T00:00:00Z"^^xsd:dateTime ;
    schema:author <https://www.linkedin.com/in/kidehen#this> ;
    schema:about <http://demo.openlinksw.com/schemas/ScaleKG/> .

<http://demo.openlinksw.com/schemas/ScaleKG/> a owl:Ontology ;
    rdfs:label "ScaleKG ontology"@en ;
    rdfs:comment "Vocabulary for describing a graph-database estate (tenants, clusters, databases, replication) and the warehouse sources that virtual-graph workloads read in place."@en ;
    owl:versionInfo "1.0"@en .

# ── Classes ────────────────────────────────────────────────────────────────

skg:Region a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Region"@en ;
    rdfs:comment "A cloud region hosting one or more clusters."@en ;
    rdfs:subClassOf schema:Place .

skg:Cluster a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Cluster"@en ;
    rdfs:comment "A database cluster or instance with a fixed amount of memory and storage that hosts one or more graph databases."@en ;
    rdfs:subClassOf schema:Thing .

skg:Tenant a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Tenant"@en ;
    rdfs:comment "A customer organisation whose data is isolated in its own databases."@en ;
    rdfs:subClassOf schema:Organization .

skg:Environment a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Environment"@en ;
    rdfs:comment "A lifecycle stage such as dev, test, staging or prod."@en ;
    rdfs:subClassOf schema:DefinedTerm .

skg:DataAsset a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Data asset"@en ;
    rdfs:comment "Anything that stores queryable data: a natively stored graph database or a warehouse table read in place."@en ;
    rdfs:subClassOf schema:Dataset .

skg:GraphDatabase a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Graph database"@en ;
    rdfs:comment "One database inside a cluster, owned by a single tenant in a single environment."@en ;
    rdfs:subClassOf skg:DataAsset .

skg:WarehouseTable a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Warehouse table"@en ;
    rdfs:comment "A table in a data warehouse or lakehouse that a workload queries where it lives."@en ;
    rdfs:subClassOf skg:DataAsset .

skg:WarehouseSource a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Warehouse source"@en ;
    rdfs:comment "A warehouse or lakehouse platform that holds warehouse tables."@en ;
    rdfs:subClassOf schema:DataCatalog .

skg:ReplicationLink a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Replication link"@en ;
    rdfs:comment "A one-way link that keeps a target database in step with a source database on another cluster."@en ;
    rdfs:subClassOf schema:Intangible .

skg:Workload a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Workload"@en ;
    rdfs:comment "An agent, GraphRAG application, analytics batch or SaaS application that reads a database or a warehouse."@en ;
    rdfs:subClassOf schema:SoftwareApplication .

skg:AnalyticsJob a owl:Class ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "Analytics job"@en ;
    rdfs:comment "A run of a graph-analytics job against a database, billed for the seconds it runs."@en ;
    rdfs:subClassOf schema:Action .

# ── Object properties ──────────────────────────────────────────────────────

skg:dependsOn a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "depends on"@en ;
    rdfs:comment "Super-property: the subject cannot operate without the object. runsOn, readsFrom, queriesVirtually, hostedOn and replicatedTo are all specialisations."@en ;
    rdfs:subPropertyOf cdx:dependsOn .

skg:runsOn a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "runs on"@en ;
    rdfs:comment "The natively stored graph database a workload uses."@en ;
    rdfs:domain skg:Workload ; rdfs:range skg:GraphDatabase ;
    rdfs:subPropertyOf skg:dependsOn .

skg:readsFrom a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "reads from"@en ;
    rdfs:comment "A warehouse table a virtual-graph workload reads in place."@en ;
    rdfs:domain skg:Workload ; rdfs:range skg:WarehouseTable ;
    rdfs:subPropertyOf skg:dependsOn .

skg:queriesVirtually a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "queries virtually"@en ;
    rdfs:comment "The warehouse source a workload queries through a virtual graph instead of a copy."@en ;
    rdfs:domain skg:Workload ; rdfs:range skg:WarehouseSource ;
    rdfs:subPropertyOf skg:dependsOn .

skg:hostedOn a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "hosted on"@en ;
    rdfs:comment "The cluster a graph database lives in."@en ;
    rdfs:domain skg:GraphDatabase ; rdfs:range skg:Cluster ;
    rdfs:subPropertyOf skg:dependsOn .

skg:replicatedTo a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "replicated to"@en ;
    rdfs:comment "The target database that continuously receives this database''s changes."@en ;
    rdfs:domain skg:GraphDatabase ; rdfs:range skg:GraphDatabase ;
    rdfs:subPropertyOf skg:dependsOn .

skg:inRegion a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "in region"@en ;
    rdfs:comment "The region a cluster runs in."@en ;
    rdfs:domain skg:Cluster ; rdfs:range skg:Region .

skg:homeRegion a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "home region"@en ;
    rdfs:comment "The region a tenant is primarily served from."@en ;
    rdfs:domain skg:Tenant ; rdfs:range skg:Region .

skg:ownedBy a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "owned by"@en ;
    rdfs:comment "The tenant that owns a database."@en ;
    rdfs:domain skg:GraphDatabase ; rdfs:range skg:Tenant .

skg:forTenant a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "for tenant"@en ;
    rdfs:comment "The tenant a workload serves."@en ;
    rdfs:domain skg:Workload ; rdfs:range skg:Tenant .

skg:environment a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "environment"@en ;
    rdfs:comment "The lifecycle stage a database belongs to."@en ;
    rdfs:domain skg:GraphDatabase ; rdfs:range skg:Environment .

skg:inSource a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "in source"@en ;
    rdfs:comment "The warehouse source that holds a table."@en ;
    rdfs:domain skg:WarehouseTable ; rdfs:range skg:WarehouseSource .

skg:replicatesFrom a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "replicates from"@en ;
    rdfs:comment "The source database of a replication link."@en ;
    rdfs:domain skg:ReplicationLink ; rdfs:range skg:GraphDatabase .

skg:replicatesTo a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "replicates to"@en ;
    rdfs:comment "The target database of a replication link."@en ;
    rdfs:domain skg:ReplicationLink ; rdfs:range skg:GraphDatabase .

skg:ranOn a owl:ObjectProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "ran on"@en ;
    rdfs:comment "The database an analytics job ran against."@en ;
    rdfs:domain skg:AnalyticsJob ; rdfs:range skg:GraphDatabase .

# ── Datatype properties ────────────────────────────────────────────────────

skg:cloud a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "cloud"@en ; rdfs:comment "The cloud provider of a region."@en ;
    rdfs:domain skg:Region ; rdfs:range xsd:string .
skg:countryCode a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "country code"@en ; rdfs:comment "ISO 3166-1 alpha-2 country code of a region."@en ;
    rdfs:domain skg:Region ; rdfs:range xsd:string .
skg:clusterRole a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "cluster role"@en ; rdfs:comment "primary or secondary."@en ;
    rdfs:domain skg:Cluster ; rdfs:range xsd:string .
skg:ramGb a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "RAM (GB)"@en ; rdfs:comment "Memory of a cluster in gigabytes."@en ;
    rdfs:domain skg:Cluster ; rdfs:range xsd:integer .
skg:storageGb a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "storage (GB)"@en ; rdfs:comment "Storage of a cluster in gigabytes."@en ;
    rdfs:domain skg:Cluster ; rdfs:range xsd:integer .
skg:edition a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "edition"@en ; rdfs:comment "The service edition a cluster runs."@en ;
    rdfs:domain skg:Cluster ; rdfs:range xsd:string .
skg:tier a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "tier"@en ; rdfs:comment "The commercial tier of a tenant."@en ;
    rdfs:domain skg:Tenant ; rdfs:range xsd:string .
skg:purpose a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "purpose"@en ; rdfs:comment "What a database is for."@en ;
    rdfs:domain skg:GraphDatabase ; rdfs:range xsd:string .
skg:syncMode a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "sync mode"@en ; rdfs:comment "transaction-pull or differential-backup-pull."@en ;
    rdfs:domain skg:ReplicationLink ; rdfs:range xsd:string .
skg:topology a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "topology"@en ; rdfs:comment "The replication topology, active-passive here."@en ;
    rdfs:domain skg:ReplicationLink ; rdfs:range xsd:string .
skg:rbacReplicated a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "RBAC replicated"@en ; rdfs:comment "1 when role-based access rules travel with the replica, 0 when they must be recreated on the target."@en ;
    rdfs:domain skg:ReplicationLink ; rdfs:range xsd:integer .
skg:vendor a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "vendor"@en ; rdfs:comment "The company behind a warehouse source."@en ;
    rdfs:domain skg:WarehouseSource ; rdfs:range xsd:string .
skg:rowCount a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "row count"@en ; rdfs:comment "Approximate rows in a warehouse table."@en ;
    rdfs:domain skg:WarehouseTable ; rdfs:range xsd:integer .
skg:workloadKind a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "workload kind"@en ; rdfs:comment "agent, graphrag, analytics or saas-app."@en ;
    rdfs:domain skg:Workload ; rdfs:range xsd:string .
skg:latencyClass a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "latency class"@en ; rdfs:comment "millisecond for natively stored databases, second for warehouse-backed virtual graphs."@en ;
    rdfs:domain skg:Workload ; rdfs:range xsd:string .
skg:jobKind a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "job kind"@en ; rdfs:comment "ml-feature-prep, entity-resolution or exploratory-science."@en ;
    rdfs:domain skg:AnalyticsJob ; rdfs:range xsd:string .
skg:runDate a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "run date"@en ; rdfs:comment "The day an analytics job ran."@en ;
    rdfs:domain skg:AnalyticsJob ; rdfs:range xsd:date .
skg:billedSeconds a owl:DatatypeProperty ;
    rdfs:isDefinedBy <http://demo.openlinksw.com/schemas/ScaleKG/> ;
    rdfs:label "billed seconds"@en ; rdfs:comment "Seconds a job was billed, which is the seconds it ran."@en ;
    rdfs:domain skg:AnalyticsJob ; rdfs:range xsd:integer .', 'http://demo.openlinksw.com/schemas/ScaleKG/', 'http://demo.openlinksw.com/schemas/ScaleKG/');
DB.DBA.rdfs_rule_set('urn:scalekg:inference', 'http://demo.openlinksw.com/schemas/ScaleKG/');

-- ── Part 3: the RDF View. One statement per target graph: a second ALTER QUAD STORAGE
-- for the same graph REPLACES the first. Nullable foreign keys carry an IS NOT NULL guard. ──

SPARQL
ALTER QUAD STORAGE virtrdf:DefaultQuadStorage
  FROM ScaleKG.kidehen.region AS r
  FROM ScaleKG.kidehen.db_cluster AS c
  FROM ScaleKG.kidehen.tenant AS t
  FROM ScaleKG.kidehen.environment AS e
  FROM ScaleKG.kidehen.graph_database AS d
  FROM ScaleKG.kidehen.replication_link AS l
  FROM ScaleKG.kidehen.warehouse_source AS ws
  FROM ScaleKG.kidehen.warehouse_table AS wt
  FROM ScaleKG.kidehen.workload AS w
  FROM ScaleKG.kidehen.workload_reads AS rd
  FROM ScaleKG.kidehen.analytics_job AS j
{
  GRAPH <http://demo.openlinksw.com/ScaleKG#>
  {
    <http://demo.openlinksw.com/schemas/ScaleKG/region_iri>(r.region_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/Region> as virtrdf:ScaleKG-region-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/region_iri>(r.region_id) <http://schema.org/name> r.region_name as virtrdf:ScaleKG-region-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/region_iri>(r.region_id) <http://demo.openlinksw.com/schemas/ScaleKG/cloud> r.cloud as virtrdf:ScaleKG-region-cloud .
    <http://demo.openlinksw.com/schemas/ScaleKG/region_iri>(r.region_id) <http://demo.openlinksw.com/schemas/ScaleKG/countryCode> r.country_code as virtrdf:ScaleKG-region-country .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/Cluster> as virtrdf:ScaleKG-cluster-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://schema.org/name> c.cluster_name as virtrdf:ScaleKG-cluster-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://demo.openlinksw.com/schemas/ScaleKG/clusterRole> c.cluster_role as virtrdf:ScaleKG-cluster-role .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://demo.openlinksw.com/schemas/ScaleKG/ramGb> c.ram_gb as virtrdf:ScaleKG-cluster-ram .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://demo.openlinksw.com/schemas/ScaleKG/storageGb> c.storage_gb as virtrdf:ScaleKG-cluster-storage .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://demo.openlinksw.com/schemas/ScaleKG/edition> c.edition as virtrdf:ScaleKG-cluster-edition .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://demo.openlinksw.com/schemas/ScaleKG/inRegion> <http://demo.openlinksw.com/schemas/ScaleKG/region_iri>(c.region_id) as virtrdf:ScaleKG-cluster-region .
    <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri>(t.tenant_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/Tenant> as virtrdf:ScaleKG-tenant-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri>(t.tenant_id) <http://schema.org/name> t.tenant_name as virtrdf:ScaleKG-tenant-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri>(t.tenant_id) <http://demo.openlinksw.com/schemas/ScaleKG/tier> t.tier as virtrdf:ScaleKG-tenant-tier .
    <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri>(t.tenant_id) <http://demo.openlinksw.com/schemas/ScaleKG/homeRegion> <http://demo.openlinksw.com/schemas/ScaleKG/region_iri>(t.region_id) as virtrdf:ScaleKG-tenant-region .
    <http://demo.openlinksw.com/schemas/ScaleKG/environment_iri>(e.env_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/Environment> as virtrdf:ScaleKG-env-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/environment_iri>(e.env_id) <http://schema.org/name> e.env_name as virtrdf:ScaleKG-env-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(d.db_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/GraphDatabase> as virtrdf:ScaleKG-db-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(d.db_id) <http://schema.org/name> d.db_name as virtrdf:ScaleKG-db-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(d.db_id) <http://demo.openlinksw.com/schemas/ScaleKG/purpose> d.purpose as virtrdf:ScaleKG-db-purpose .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(d.db_id) <http://demo.openlinksw.com/schemas/ScaleKG/hostedOn> <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(d.cluster_id) as virtrdf:ScaleKG-db-cluster .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(d.db_id) <http://demo.openlinksw.com/schemas/ScaleKG/ownedBy> <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri>(d.tenant_id) as virtrdf:ScaleKG-db-tenant .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(d.db_id) <http://demo.openlinksw.com/schemas/ScaleKG/environment> <http://demo.openlinksw.com/schemas/ScaleKG/environment_iri>(d.env_id) as virtrdf:ScaleKG-db-env .
    <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri>(l.link_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/ReplicationLink> as virtrdf:ScaleKG-link-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri>(l.link_id) <http://demo.openlinksw.com/schemas/ScaleKG/syncMode> l.sync_mode as virtrdf:ScaleKG-link-mode .
    <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri>(l.link_id) <http://demo.openlinksw.com/schemas/ScaleKG/topology> l.topology as virtrdf:ScaleKG-link-topology .
    <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri>(l.link_id) <http://demo.openlinksw.com/schemas/ScaleKG/rbacReplicated> l.rbac_replicated as virtrdf:ScaleKG-link-rbac .
    <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri>(l.link_id) <http://demo.openlinksw.com/schemas/ScaleKG/replicatesFrom> <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(l.source_db_id) as virtrdf:ScaleKG-link-from .
    <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri>(l.link_id) <http://demo.openlinksw.com/schemas/ScaleKG/replicatesTo> <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(l.target_db_id) as virtrdf:ScaleKG-link-to .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(l.source_db_id) <http://demo.openlinksw.com/schemas/ScaleKG/replicatedTo> <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(l.target_db_id) as virtrdf:ScaleKG-db-replicated-to .
    <http://demo.openlinksw.com/schemas/ScaleKG/source_iri>(ws.src_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/WarehouseSource> as virtrdf:ScaleKG-src-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/source_iri>(ws.src_id) <http://schema.org/name> ws.src_name as virtrdf:ScaleKG-src-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/source_iri>(ws.src_id) <http://demo.openlinksw.com/schemas/ScaleKG/vendor> ws.vendor as virtrdf:ScaleKG-src-vendor .
    <http://demo.openlinksw.com/schemas/ScaleKG/wtable_iri>(wt.wt_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/WarehouseTable> as virtrdf:ScaleKG-wt-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/wtable_iri>(wt.wt_id) <http://schema.org/name> wt.table_name as virtrdf:ScaleKG-wt-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/wtable_iri>(wt.wt_id) <http://demo.openlinksw.com/schemas/ScaleKG/rowCount> wt.row_count as virtrdf:ScaleKG-wt-rows .
    <http://demo.openlinksw.com/schemas/ScaleKG/wtable_iri>(wt.wt_id) <http://demo.openlinksw.com/schemas/ScaleKG/inSource> <http://demo.openlinksw.com/schemas/ScaleKG/source_iri>(wt.src_id) as virtrdf:ScaleKG-wt-source .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/Workload> as virtrdf:ScaleKG-wl-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://schema.org/name> w.wl_name as virtrdf:ScaleKG-wl-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://demo.openlinksw.com/schemas/ScaleKG/workloadKind> w.wl_kind as virtrdf:ScaleKG-wl-kind .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://demo.openlinksw.com/schemas/ScaleKG/latencyClass> w.latency_class as virtrdf:ScaleKG-wl-latency .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://demo.openlinksw.com/schemas/ScaleKG/forTenant> <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri>(w.tenant_id) as virtrdf:ScaleKG-wl-tenant .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://demo.openlinksw.com/schemas/ScaleKG/runsOn> <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(w.db_id) where (^{w.}^.db_id is not null) as virtrdf:ScaleKG-wl-db .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://demo.openlinksw.com/schemas/ScaleKG/queriesVirtually> <http://demo.openlinksw.com/schemas/ScaleKG/source_iri>(w.src_id) where (^{w.}^.src_id is not null) as virtrdf:ScaleKG-wl-src .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(rd.wl_id) <http://demo.openlinksw.com/schemas/ScaleKG/readsFrom> <http://demo.openlinksw.com/schemas/ScaleKG/wtable_iri>(rd.wt_id) as virtrdf:ScaleKG-wl-reads .
    <http://demo.openlinksw.com/schemas/ScaleKG/job_iri>(j.job_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/AnalyticsJob> as virtrdf:ScaleKG-job-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/job_iri>(j.job_id) <http://demo.openlinksw.com/schemas/ScaleKG/jobKind> j.job_kind as virtrdf:ScaleKG-job-kind .
    <http://demo.openlinksw.com/schemas/ScaleKG/job_iri>(j.job_id) <http://demo.openlinksw.com/schemas/ScaleKG/runDate> j.run_date as virtrdf:ScaleKG-job-date .
    <http://demo.openlinksw.com/schemas/ScaleKG/job_iri>(j.job_id) <http://demo.openlinksw.com/schemas/ScaleKG/billedSeconds> j.billed_seconds as virtrdf:ScaleKG-job-seconds .
    <http://demo.openlinksw.com/schemas/ScaleKG/job_iri>(j.job_id) <http://demo.openlinksw.com/schemas/ScaleKG/ranOn> <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(j.db_id) as virtrdf:ScaleKG-job-db .
  }
} ;

-- ── Part 4: access. The view inherits SQL table privileges. SPARQL serves the anonymous
-- endpoint; demo and vdb are accounts on demo.openlinksw.com that serve SPASQL and the Query
-- Builder: on another server, drop the two lines that grant to them. ──

GRANT SELECT ON ScaleKG.kidehen.region TO "SPARQL";
GRANT SELECT ON ScaleKG.kidehen.region TO PUBLIC;
GRANT SELECT ON ScaleKG.kidehen.region TO "demo";
GRANT SELECT ON ScaleKG.kidehen.region TO "vdb";
GRANT SELECT ON ScaleKG.kidehen.db_cluster TO "SPARQL";
GRANT SELECT ON ScaleKG.kidehen.db_cluster TO PUBLIC;
GRANT SELECT ON ScaleKG.kidehen.db_cluster TO "demo";
GRANT SELECT ON ScaleKG.kidehen.db_cluster TO "vdb";
GRANT SELECT ON ScaleKG.kidehen.tenant TO "SPARQL";
GRANT SELECT ON ScaleKG.kidehen.tenant TO PUBLIC;
GRANT SELECT ON ScaleKG.kidehen.tenant TO "demo";
GRANT SELECT ON ScaleKG.kidehen.tenant TO "vdb";
GRANT SELECT ON ScaleKG.kidehen.environment TO "SPARQL";
GRANT SELECT ON ScaleKG.kidehen.environment TO PUBLIC;
GRANT SELECT ON ScaleKG.kidehen.environment TO "demo";
GRANT SELECT ON ScaleKG.kidehen.environment TO "vdb";
GRANT SELECT ON ScaleKG.kidehen.graph_database TO "SPARQL";
GRANT SELECT ON ScaleKG.kidehen.graph_database TO PUBLIC;
GRANT SELECT ON ScaleKG.kidehen.graph_database TO "demo";
GRANT SELECT ON ScaleKG.kidehen.graph_database TO "vdb";
GRANT SELECT ON ScaleKG.kidehen.replication_link TO "SPARQL";
GRANT SELECT ON ScaleKG.kidehen.replication_link TO PUBLIC;
GRANT SELECT ON ScaleKG.kidehen.replication_link TO "demo";
GRANT SELECT ON ScaleKG.kidehen.replication_link TO "vdb";
GRANT SELECT ON ScaleKG.kidehen.warehouse_source TO "SPARQL";
GRANT SELECT ON ScaleKG.kidehen.warehouse_source TO PUBLIC;
GRANT SELECT ON ScaleKG.kidehen.warehouse_source TO "demo";
GRANT SELECT ON ScaleKG.kidehen.warehouse_source TO "vdb";
GRANT SELECT ON ScaleKG.kidehen.warehouse_table TO "SPARQL";
GRANT SELECT ON ScaleKG.kidehen.warehouse_table TO PUBLIC;
GRANT SELECT ON ScaleKG.kidehen.warehouse_table TO "demo";
GRANT SELECT ON ScaleKG.kidehen.warehouse_table TO "vdb";
GRANT SELECT ON ScaleKG.kidehen.workload TO "SPARQL";
GRANT SELECT ON ScaleKG.kidehen.workload TO PUBLIC;
GRANT SELECT ON ScaleKG.kidehen.workload TO "demo";
GRANT SELECT ON ScaleKG.kidehen.workload TO "vdb";
GRANT SELECT ON ScaleKG.kidehen.workload_reads TO "SPARQL";
GRANT SELECT ON ScaleKG.kidehen.workload_reads TO PUBLIC;
GRANT SELECT ON ScaleKG.kidehen.workload_reads TO "demo";
GRANT SELECT ON ScaleKG.kidehen.workload_reads TO "vdb";
GRANT SELECT ON ScaleKG.kidehen.analytics_job TO "SPARQL";
GRANT SELECT ON ScaleKG.kidehen.analytics_job TO PUBLIC;
GRANT SELECT ON ScaleKG.kidehen.analytics_job TO "demo";
GRANT SELECT ON ScaleKG.kidehen.analytics_job TO "vdb";

-- ── Part 5: URL rewrite rules, so every entity IRI resolves (303 to a description page; RDF
-- requests routed to DESCRIBE). Generated by the OpenLink RDFVIEW_GENERATE_DATA_RULES function with
-- iri_path_segment=ScaleKG. Change the path segment and graph names if you rename the view. ──

DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'scalekg_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=DESCRIBE+%%3Chttp%%3A//^{URIQADefaultHost}^%U%%23this%%3E+FROM+%%3Chttp%%3A//^{URIQADefaultHost}^/ScaleKG%%23%%3E&format=%U',
vector('path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)|(text/n3)|(application/json)|(text/turtle)',
2,
null
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'scalekg_rule4',
1,
'/ScaleKG/stat([^#]*)',
vector('path'),
1,
'/sparql?query=DESCRIBE+%%3Chttp%%3A//^{URIQADefaultHost}^/ScaleKG/stat%%23%%3E+%%3Fo+FROM+%%3Chttp%%3A//^{URIQADefaultHost}^/ScaleKG%%23%%3E+WHERE+{+%%3Chttp%%3A//^{URIQADefaultHost}^/ScaleKG/stat%%23%%3E+%%3Fp+%%3Fo+}&format=%U',
vector('*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)|(text/n3)|(application/json)|(text/turtle)',
2,
null
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'scalekg_rule6',
1,
'/ScaleKG/objects/([^#]*)',
vector('path'),
1,
'/sparql?query=DESCRIBE+%%3Chttp%%3A//^{URIQADefaultHost}^/ScaleKG/objects/%U%%3E+FROM+%%3Chttp%%3A//^{URIQADefaultHost}^/ScaleKG%%23%%3E&format=%U',
vector('path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)|(text/n3)|(application/json)|(text/turtle)',
2,
null
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'scalekg_rule1',
1,
'([^#]*)',
vector('path'),
1,
'/describe/?uri=http%%3A%%2F%%2F^{URIQADefaultHost}^%U%%23this&graph=http%%3A%%2F%%2F^{URIQADefaultHost}^%%2FScaleKG%%23',
vector('path'),
null,
null,
2,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'scalekg_rule7',
1,
'/ScaleKG/stat([^#]*)',
vector('path'),
1,
'/describe/?uri=http%%3A%%2F%%2F^{URIQADefaultHost}^%%2FScaleKG%%2Fstat%%23&graph=http%%3A%%2F%%2F^{URIQADefaultHost}^%%2FScaleKG%%23',
vector('path'),
null,
null,
2,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'scalekg_rule5',
1,
'/ScaleKG/objects/(.*)',
vector('path'),
1,
'/services/rdf/object.binary?path=%%2FScaleKG%%2Fobjects%%2F%U&accept=%U',
vector('path', '*accept*'),
null,
null,
2,
null
);
DB.DBA.URLREWRITE_CREATE_RULELIST ( 'scalekg_rule_list1', 1, vector ( 'scalekg_rule1', 'scalekg_rule7', 'scalekg_rule5', 'scalekg_rule2', 'scalekg_rule4', 'scalekg_rule6'));
DB.DBA.VHOST_REMOVE (lpath=>'/ScaleKG');
DB.DBA.VHOST_DEFINE (lpath=>'/ScaleKG', ppath=>'/', vsp_user=>'dba', is_dav=>0,
is_brws=>0, opts=>vector ('url_rewrite', 'scalekg_rule_list1')
);DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'scalekg_owl_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=DESCRIBE+%%3Chttp%%3A//^{URIQADefaultHost}^%U%%3E+FROM+%%3Chttp%%3A//^{URIQADefaultHost}^/schemas/ScaleKG%%23%%3E&format=%U',
vector('path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)|(text/n3)|(application/json)|(text/turtle)',
2,
null
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'scalekg_owl_rule1',
1,
'([^#]*)',
vector('path'),
1,
'/describe/?uri=http%%3A%%2F%%2F^{URIQADefaultHost}^%U&graph=http%%3A%%2F%%2F^{URIQADefaultHost}^%%2Fschemas%%2FScaleKG%%2F',
vector('path'),
null,
null,
2,
303
);
DB.DBA.URLREWRITE_CREATE_RULELIST ( 'scalekg_owl_rule_list1', 1, vector ( 'scalekg_owl_rule1', 'scalekg_owl_rule2'));
DB.DBA.VHOST_REMOVE (lpath=>'/schemas/ScaleKG');
DB.DBA.VHOST_DEFINE (lpath=>'/schemas/ScaleKG', ppath=>'/', vsp_user=>'dba', is_dav=>0,
is_brws=>0, opts=>vector ('url_rewrite', 'scalekg_owl_rule_list1')
);

Nine live queries

The SPARQL links run anonymously against the public endpoint. The Query Builder links run SQL, SPARQL and SPASQL alike, but it asks you to sign in to demo.openlinksw.com first, so the three SPASQL and SQL queries have no anonymous link. Each result below is the result that came back. Every published SELECT, SPARQL or SPASQL, projects the IRI of the entity each row is about beside its label, so every row is a key that can be followed; only the compiled-SQL query, which returns text rather than entities, is exempt.

Three hops from tenant to warehouse table

Query 1 · SPARQL

The GraphRAG-shaped question from the article: which warehouse tables do each tenant's workloads read, and in which warehouse? Four patterns walk tenant, workload, table and source. The relational data is never copied; every row is computed from the live tables.

PREFIX skg: <http://demo.openlinksw.com/schemas/ScaleKG/>
PREFIX schema: <http://schema.org/>
SELECT ?tenantIri ?tenant ?workloadIri ?workload ?tableIri ?tableName ?source
FROM <http://demo.openlinksw.com/ScaleKG#>
WHERE {
  ?tenantIri a skg:Tenant ; schema:name ?tenant .
  ?workloadIri skg:forTenant ?tenantIri ; schema:name ?workload ; skg:readsFrom ?tableIri .
  ?tableIri schema:name ?tableName ; skg:inSource ?sourceIri .
  ?sourceIri schema:name ?source .
}
ORDER BY ?tenant ?workload ?tableName

Verified result: 9 rows: Acme Retail reads CUSTOMERS, ORDERS and PRODUCTS in Snowflake; Borealis Bank reads ACCOUNTS and TRANSACTIONS and Cobalt Health reads CLAIMS and PROVIDERS, all in Databricks; Dunmore Logistics reads DEPOTS and SHIPMENTS in BigQuery.

Databases per cluster

Query 2 · SPARQL

How many databases share each cluster, with the cluster's memory beside the count. An OPTIONAL and a COUNT over the hostedOn edge.

PREFIX skg: <http://demo.openlinksw.com/schemas/ScaleKG/>
PREFIX schema: <http://schema.org/>
SELECT ?clusterIri ?cluster ?ramGb (COUNT(?db) AS ?databases)
FROM <http://demo.openlinksw.com/ScaleKG#>
WHERE {
  ?clusterIri a skg:Cluster ; schema:name ?cluster ; skg:ramGb ?ramGb .
  OPTIONAL { ?db skg:hostedOn ?clusterIri }
}
GROUP BY ?clusterIri ?cluster ?ramGb
ORDER BY DESC(?databases)

Verified result: 4 rows: graph-vdc-shared 256 GB hosts 6 databases, graph-bc-prod-us 2048 GB hosts 5, graph-bc-dr-eu 512 GB hosts 3 and graph-selfmanaged-eu 128 GB hosts 2.

Replication topology and the access-control gap

Query 3 · SPARQL

Every replication link with its source and target database, the region each lives in, the sync mode and the rbacReplicated flag. A two-step property path from database to cluster to region to name. The flag models the article's stated limit that role-based access control is not replicated.

PREFIX skg: <http://demo.openlinksw.com/schemas/ScaleKG/>
PREFIX schema: <http://schema.org/>
SELECT ?linkIri ?sourceDb ?fromRegion ?targetDb ?toRegion ?syncMode ?rbacReplicated
FROM <http://demo.openlinksw.com/ScaleKG#>
WHERE {
  ?linkIri a skg:ReplicationLink ;
           skg:replicatesFrom ?sourceIri ; skg:replicatesTo ?targetIri ;
           skg:syncMode ?syncMode ; skg:rbacReplicated ?rbacReplicated .
  ?sourceIri schema:name ?sourceDb ; skg:hostedOn/skg:inRegion/schema:name ?fromRegion .
  ?targetIri schema:name ?targetDb ; skg:hostedOn/skg:inRegion/schema:name ?toRegion .
}
ORDER BY ?sourceDb

Verified result: 3 rows, all from gcp-us-central1 to gcp-europe-west4: acme_prod and cobalt_prod by transaction-pull, borealis_prod by differential-backup-pull, each with rbacReplicated 0.

The article's 5-per-GB rule as SQL over SPARQL output

Query 4 · SPASQL

A SPARQL aggregate nested in a SQL SELECT. The graph side counts databases per cluster and passes the cluster's IRI through as a column, so each row is a key that resolves to the entity and can be joined to anything else that names it; the SQL side applies the article's rule of up to 5 databases per GB of RAM, capped at 100 per instance in preview and 250 after general availability, and computes the headroom.

SELECT c, cluster_name, ram_gb, dbs,
       ram_gb * 5 AS by_ram,
       CASE WHEN ram_gb * 5 > 100 THEN 100 ELSE ram_gb * 5 END - dbs AS headroom_preview,
       CASE WHEN ram_gb * 5 > 250 THEN 250 ELSE ram_gb * 5 END - dbs AS headroom_ga
FROM (SPARQL
  PREFIX skg: <http://demo.openlinksw.com/schemas/ScaleKG/>
  PREFIX schema: <http://schema.org/>
  SELECT ?c ?cluster_name ?ram_gb (COUNT(?db) AS ?dbs)
  FROM <http://demo.openlinksw.com/ScaleKG#>
  WHERE {
    ?c a skg:Cluster ; schema:name ?cluster_name ; skg:ramGb ?ram_gb .
    OPTIONAL { ?db skg:hostedOn ?c }
  }
  GROUP BY ?c ?cluster_name ?ram_gb
) AS x
ORDER BY dbs DESC

Verified result: 4 rows, each led by the cluster IRI. Memory never binds: even 128 GB allows 640 databases by the per-GB rule, so the instance cap does. Headroom in preview is 94, 95, 97 and 98 databases, and after general availability 244, 245, 247 and 248.

Graph result joined to a native SQL table

Query 5 · SPASQL

The demonstration with no counterpart in the article: SPARQL walks tenant-owns-database in the graph, and SQL joins those solutions to the native analytics_job table and sums billed seconds per tenant, keeping the tenant IRI beside its name. One statement, one round trip.

SELECT t.tenant_iri, t.tenant, COUNT(*) AS jobs, SUM(j.billed_seconds) AS billed_seconds
FROM (SPARQL
  PREFIX skg: <http://demo.openlinksw.com/schemas/ScaleKG/>
  PREFIX schema: <http://schema.org/>
  SELECT ?tenant_iri ?tenant ?db_name
  FROM <http://demo.openlinksw.com/ScaleKG#>
  WHERE {
    ?tenant_iri a skg:Tenant ; schema:name ?tenant .
    ?db skg:ownedBy ?tenant_iri ; schema:name ?db_name .
  }
) AS t
JOIN ScaleKG.kidehen.graph_database d ON d.db_name = t.db_name
JOIN ScaleKG.kidehen.analytics_job j ON j.db_id = d.db_id
GROUP BY t.tenant_iri, t.tenant
ORDER BY billed_seconds DESC

Verified result: 5 rows, each led by the tenant IRI: Acme Retail 2 jobs and 10,500 billed seconds, Dunmore Logistics 2 and 9,000, Borealis Bank 2 and 7,800, Cobalt Health 1 and 2,700, Fjord Energy 1 and 900.

Entailment: what is a data asset?

Query 6 · SPARQL

Nothing in the data is typed skg:DataAsset; databases are typed GraphDatabase and warehouse tables WarehouseTable. The TBox says both are subclasses of DataAsset, and one DEFINE input:inference pragma activates the rule set derived from it.

DEFINE input:inference "urn:scalekg:inference"
PREFIX skg: <http://demo.openlinksw.com/schemas/ScaleKG/>
PREFIX schema: <http://schema.org/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?kindIri ?kind (COUNT(DISTINCT ?assetIri) AS ?assets)
FROM <http://demo.openlinksw.com/ScaleKG#>
FROM <http://demo.openlinksw.com/schemas/ScaleKG/>
WHERE {
  ?assetIri a skg:DataAsset ; a ?kindIri .
  ?kindIri rdfs:label ?kind .
  FILTER(?kindIri IN (skg:DataAsset, skg:GraphDatabase, skg:WarehouseTable))
}
GROUP BY ?kindIri ?kind
ORDER BY DESC(?assets)

Verified result: 3 rows: DataAsset 25, GraphDatabase 16, WarehouseTable 9. Without the pragma the same DataAsset query returns 0.

Worth knowing: Sub-property entailment over the view did not fire on this build: asking for skg:dependsOn under the same rule set returned no rows. Combining SELECT DISTINCT, ORDER BY and inference raised error SQ142, so this query has no ORDER BY on its DISTINCT.

The property hierarchy, read from the TBox

Query 7 · SPARQL

Because sub-property entailment did not fire over the view, this query joins the TBox graph in explicitly: it finds every property declared a sub-property of skg:dependsOn and follows it from each workload.

PREFIX skg: <http://demo.openlinksw.com/schemas/ScaleKG/>
PREFIX schema: <http://schema.org/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT DISTINCT ?workloadIri ?workload ?relation ?dependencyIri ?dependency
FROM <http://demo.openlinksw.com/ScaleKG#>
FROM <http://demo.openlinksw.com/schemas/ScaleKG/>
WHERE {
  ?workloadIri a skg:Workload ; schema:name ?workload ; ?relationIri ?dependencyIri .
  ?relationIri rdfs:subPropertyOf skg:dependsOn ; rdfs:label ?relation .
  ?dependencyIri schema:name ?dependency .
}

Verified result: 19 rows: 9 reads-from, 6 runs-on and 4 queries-virtually dependencies.

The SQL Virtuoso compiles a SPARQL query into

Query 8 · SQL

The counterpart of the article's sentence that Neo4j translates the Cypher query into SQL and runs it in the source system. sparql_to_sql_text returns the SQL Virtuoso generates for a SPARQL query, so the translation can be read. Shown here for a two-pattern query over the tenant table.

SELECT length(sparql_to_sql_text('SPARQL PREFIX skg: <http://demo.openlinksw.com/schemas/ScaleKG/> PREFIX schema: <http://schema.org/> SELECT ?tenant ?tier FROM <http://demo.openlinksw.com/ScaleKG#> WHERE { ?t a skg:Tenant ; schema:name ?tenant ; skg:tier ?tier }')) AS sql_length,
       subseq(sparql_to_sql_text('SPARQL PREFIX skg: <http://demo.openlinksw.com/schemas/ScaleKG/> PREFIX schema: <http://schema.org/> SELECT ?tenant ?tier FROM <http://demo.openlinksw.com/ScaleKG#> WHERE { ?t a skg:Tenant ; schema:name ?tenant ; skg:tier ?tier }'), 0, 2500) AS sql_head

Verified result: One row: the length of the generated SQL, 22,712 characters, and its first 2,500 characters, beginning with a join of DB.DBA.RDF_QUAD and the ScaleKG.kidehen tables.

Worth knowing: The generated SQL is large because the compiler considers every quad map that could supply each pattern and prunes with filters; the answer is still computed from the live rows.

Two instances, one query: the collection graph on URIBurner joined to the view on demo

Query 9 · SPARQL

Run on URIBurner. A Dataset entity in this collection's own graph, hosted on linkeddata.uriburner.com, names the ScaleKG view graph; a SERVICE call then asks demo.openlinksw.com for the class counts of that graph. Two Virtuoso instances, two named graphs and one statement, with no copy of either graph in the other.

PREFIX schema: <http://schema.org/>
SELECT ?datasetIri ?datasetName ?classIri ?entities
FROM <https://linkeddata.uriburner.com/DAV/demos/daas/neo4j-scale-ai-production-vs-virtuoso-agent-rdf-memory-meshup-claude_sonnet_5_5-1.ttl>
WHERE {
  ?datasetIri a schema:Dataset ; schema:name ?datasetName ; schema:url ?viewGraph .
  FILTER(STR(?viewGraph) = "http://demo.openlinksw.com/ScaleKG#")
  SERVICE <https://demo.openlinksw.com/sparql> {
    SELECT ?classIri (COUNT(DISTINCT ?entityIri) AS ?entities)
    FROM <http://demo.openlinksw.com/ScaleKG#>
    WHERE { ?entityIri a ?classIri }
    GROUP BY ?classIri
  }
}
ORDER BY DESC(?entities)

Verified result: 10 rows, one per class, all tied to the ScaleKG RDF View entity: GraphDatabase 16, Workload 10, WarehouseTable 9, AnalyticsJob 8, Tenant 6, Environment 4, Cluster 4, Region 4, WarehouseSource 3 and ReplicationLink 3, which sum to the 67 entities in the view.

Worth knowing: Asking demo itself the same question with the view graph as a variable failed, because the planner also tried an unrelated remote DSN registered on that server; running from URIBurner with the graph as a constant avoids it.

What the build taught

Four findings from deploying it, stated as they happened, including the two places Virtuoso did not do what was expected.

A nullable foreign key needs an IS NOT NULL guard in the quad map

The first deployment projected 357 triples, ten more than the rows justify, and any query touching workload.db_id or workload.src_id failed with a sprintf error on the NULL rows. Adding where (^{w.}^.db_id is not null) to the two mappings gave 347 triples, matching a hand count.

SELECT DISTINCT with ORDER BY under inference raised SQ142

On this build the combination returned 'Different number of expected and generated columns in a select'. Dropping ORDER BY fixed it; the XMLA path also raised the error for some COUNT queries under a DEFINE input:inference pragma that the HTTP endpoint answered correctly.

Class entailment works over the view; sub-property entailment did not

With the rule set urn:scalekg:inference, asking for skg:DataAsset returned 25 assets that are only typed as subclasses. Asking for skg:dependsOn, which is a super-property of five mapped predicates, returned no rows even after rebuilding the rule set. Query 7 reads the hierarchy from the TBox instead.

An RDF View defines entity IRIs but does not make them resolve; that needs URL rewrite rules

Right after the quad map was deployed, every ScaleKG entity IRI returned 404 even though SPARQL answered correctly. The rules generated by RDFVIEW_GENERATE_DATA_RULES fixed it: each IRI now answers with a 303 to a description page that returns 200, and a DESCRIBE through the endpoint returns the entity's triples. As with the earlier MovieKG deployment on this host, asking the bare IRI for Turtle returns 406, so the page claims only the two paths that were verified.

The demo server's only write path for DDL was SELECT exec() over authenticated XMLA

The XMLA endpoint rejects non-SELECT statements directly, but SELECT exec('<statement>') runs DDL and DML as the authenticated user. Each CREATE IRI CLASS took minutes and outlived the client timeout, so completion was checked by querying the virtrdf schema graph rather than by reissuing the statement.

The Harness Layer

agent-rdf-memory: Domains as Graphs, Not Databases

For agentic applications the article suggests a separate database per knowledge domain. The agent-rdf-memory harness takes the opposite shape: one named graph per memory document, all in the same Virtuoso store, all queryable with SPARQL. A database boundary gives each domain hard isolation; a graph per document gives provenance, cross-domain queries and rules an agent can retrieve and reason over before it acts.

511
Named graphs
One per memory document, of 514 files on disk at the start of this session.
36,701
Triples
Queryable with the same SPARQL that queries the estate above.
1,336
HowToSteps
Each standing rule is a schema:HowToStep an agent can retrieve and follow.
184
HowTo documents
Procedures an agent re-reads when a task triggers one.

The counts come from the harness's own memory-graph verification run at the start of this session, which compares files on disk with graphs loaded in Virtuoso and reported three session files not yet loaded. The same store serves the deployment on this page: the RDF View, the ontology and the inference rule set are the kind of artefact the harness records as reusable, rather than something rebuilt for each task.

How-To

How-To Guide

1

Create the tables

Run the CREATE TABLE statements for the eleven tables under a qualifier and owner you control, referencing parents before children. The demonstration used ScaleKG.kidehen.

2

Load the rows

Insert the 76 rows. Virtuoso has no multi-row VALUES, so send one INSERT per row; parents before children.

3

Create the IRI classes

Run the ten SPARQL CREATE IRI CLASS statements, one per entity. On a busy server each can take minutes; confirm completion by querying the virtrdf schema graph rather than reissuing.

4

Load the ontology

Load scalekg-ontology-claude_sonnet_5_5-1.ttl into http://demo.openlinksw.com/schemas/ScaleKG/ with DB.DBA.TTLP, then create the rule set with DB.DBA.rdfs_rule_set('urn:scalekg:inference', 'http://demo.openlinksw.com/schemas/ScaleKG/').

5

Declare the RDF View

Send the single ALTER QUAD STORAGE statement. Keep every mapping for the graph in one statement, because a second statement for the same graph replaces the first, and guard nullable foreign keys with IS NOT NULL.

6

Grant access

GRANT SELECT on each table to the SPARQL account and PUBLIC, plus any accounts that run SPASQL. The view inherits these privileges.

7

Install the rewrite rules

Call RDFVIEW_GENERATE_DATA_RULES with the IRI path segment and run the script it returns, which defines the two virtual directories. Then request an entity IRI: it should answer with a 303 to a description page, where before it returned 404.

8

Check the count

SELECT COUNT(*) over the named graph should return 347. If it is higher, look for NULL foreign keys missing their guard.

9

Run the queries

Run Queries 1 to 9: Queries 1 to 7 from the demo SPARQL endpoint or SPASQL Query Builder, and Query 9 from the URIBurner SPARQL endpoint. Expect 9, 4, 3, 4, 5, 3 and 19 rows, one row of compiled SQL for Query 8, and 10 rows for Query 9.

FAQ

Frequently Asked Questions

It lets you build and query a knowledge graph directly over data held in Snowflake, Databricks and Google BigQuery without copying it, so the data stays under its existing governance. Neo4j rewrites each Cypher query as SQL and executes it inside the source system. It is in public preview for every Aura customer, with general availability expected in a couple of months.

Yes: an RDF View, declared with one ALTER QUAD STORAGE statement that maps tables to triples computed at query time. On this page eleven SQL tables on demo.openlinksw.com are projected to 347 triples without copying a row, and the statement is shown in full.

The SPARQL compiler rewrites the query into SQL over the mapped tables and runs it. The generated SQL can be read with sparql_to_sql_text; for a two-pattern query over the tenant table it is 22,712 characters, because the compiler considers every quad map that could supply each pattern.

Not one-for-one, and Virtuoso has no need for a database-count ceiling. Neo4j puts separate databases inside one instance, by default up to 5 per GB of RAM and capped at 100 at preview and 250 after general availability. Virtuoso holds each domain in its own named graph with graph-level permissions, lets an RDF View inherit SQL grants, and scales by federating graphs and instances into a Semantic Web of purpose-specific graphs. Query 9 does exactly that: one statement on URIBurner joins this collection's graph there to the ScaleKG view on demo.

It keeps a database continuously replicated to an independent cluster, active-passive, with only the primary taking writes until the replica is promoted. A replica catches up by pulling transactions from the upstream cluster or by pulling differential backups from object storage. Sharded databases are not yet supported and role-based access control does not replicate. It is generally available in Neo4j Enterprise Edition and coming soon to Aura.

Transactional replication, one-way or bi-directional with conflict resolution; snapshot replication, incremental or not; and RDF graph replication, where named graphs are published and subscribed in chain, star or bi-directional topologies. The documentation consulted does not say whether SQL users and roles replicate, so that should be checked before it is relied on.

Per the article, agents that can work at the pace of seconds suit Virtual Graph, while those that must respond in milliseconds, such as online fraud scoring, live identity resolution or graphs updated continuously with ACID writes, need the graph stored natively in AuraDB.

The same SPARQL runs against an RDF View over SQL tables or against triples in the physical quad store, and a view can be copied into a physical graph, so the tier is a deployment choice rather than a change of language. That does not make a warehouse-backed query as fast as a native one.

It supports GQL, the open-standards variant of Cypher, alongside SPARQL, SQL, GraphQL and SPASQL. This page demonstrates SPARQL, SQL and SPASQL and does not exercise GQL, so the Cypher-versus-GQL point is stated rather than shown.

SPASQL nests a SPARQL query inside a SQL SELECT so a graph result set can be joined to native relational tables in one statement. Query 5 joins tenant-owns-database from the graph to the analytics_job table in SQL and sums billed seconds per tenant. The article describes no counterpart.

On the evidence gathered, nowhere clearly. Its nearest advantage is a generally available, vendor-run managed service in AuraDB, which Virtuoso answers with natural-language configuration and administration through its MCP tooling and packaged skills, the widest deployment choice, and an OpenLink managed service announced for this month; Neo4j also offers a self-managed edition. Two Neo4j claims were not benchmarked here: its undeclared-key model proposal and its dedicated analytics tier, which the article describes as an Early Access Program.

It shows the mechanism against a SQL system of record: tables holding and governing the rows, an RDF View projecting them at query time, resolvable entity IRIs, and SPARQL and SPASQL over the result. Snowflake, Databricks and BigQuery are SQL systems, so they are further systems of record for the same mechanism. It does not exercise a connection to one particular remote engine. Sub-property entailment over the view did not fire on this build, and the data is synthetic.

Yes, after URL rewrite rules were installed; before that they returned 404. All 67 entities in the view, including every IRI the queries return, answer with a 303 to the describe URL and that page returns 200. On direct arrival the server's describe page first shows an 'Open this link?' confirmation; after Continue it shows the entity, for example a cluster's name, edition, RAM and storage. A DESCRIBE through the SPARQL endpoint also returns its triples. Asking the bare IRI for Turtle returns 406 on this host, so content negotiation on the IRI itself is not claimed.

The article suggests separate databases per knowledge domain for agentic applications. The harness takes the opposite shape: one named graph per memory document, 511 graphs and 36,701 triples at the start of this session, queried with the same SPARQL as the estate above and carrying each standing rule as a queryable HowToStep.

Glossary

Glossary of Terms

Data virtualization

Presenting data from several sources as one queryable layer without moving it. Virtual Graph and an RDF View are both forms of it.

Zero-copy

Querying data in the system that owns it instead of duplicating it into another store, so the source's governance still applies and there is no refresh pipeline.

Virtual graph

Neo4j's name for a graph view over warehouse tables that translates Cypher to SQL and runs it in the source system.

RDF View

A declarative mapping from relational tables to RDF triples computed at query time. In Virtuoso it is declared with ALTER QUAD STORAGE and is also called a quad map.

IRI class

A Virtuoso template that builds a dereferenceable IRI from a key column, such as http://demo.openlinksw.com/ScaleKG/tenant/%d#this.

SPASQL

A SPARQL query nested inside a SQL SELECT, so a graph result set joins native relational tables in one statement.

Multitenancy

One platform serving several customers whose data must stay separate. Neo4j's answer is a database per tenant; Virtuoso's is graph permissions and SQL grants.

Replication

Keeping a copy of data synchronised with its source. The article's version is active-passive across clusters.

Disaster recovery

Restoring service after losing a region or cluster, for which a live replica in a second region is the article's answer.

Cypher

The property-graph query language Neo4j uses, including against a virtual graph.

GQL

The ISO standard graph query language, the open-standards variant of Cypher. Virtuoso supports it alongside SPARQL, SQL and GraphQL.

SPARQL

The W3C query language for RDF, used here against the RDF View.

SQL

The relational query language. Both Virtual Graph and an RDF View compile graph queries into it.

Knowledge graph

A graph of entities and relationships with meaning attached. Here it is computed from relational tables rather than stored separately.

Retrieval-augmented generation

Grounding a model's answers in retrieved data; GraphRAG retrieves by following graph relationships for multi-hop questions.

Named graph

An RDF graph identified by an IRI. The ScaleKG view lives in http://demo.openlinksw.com/ScaleKG# and its TBox in http://demo.openlinksw.com/schemas/ScaleKG/.

Entailment

Deriving facts not stored explicitly from a declared ontology, such as a database being a DataAsset because GraphDatabase is a subclass of it.

Knowledge Graph Explorer 161 nodes · 287 links

Interactive graph visualization derived from the companion RDF. Click nodes to resolve, drag to explore. Graph data embedded from companion RDF at generation time.

Scale AI into Production: Neo4j's Five Scale Capabilities Meshed with Virtuoso and agent-rdf-memory

Nodes: 0 Links: 0
Click SVG to activate zoom, click outside to release | Drag nodes to pin, double-click to unpin
Classes Properties Instances

SPARQL Workbench 19 sample queries

Query this knowledge graph on URIBurner. The editor opens on the canonical SAMPLE entity-type summary (DAV named graph). Pick a recipe, edit freely, then run live or copy.

Sample Queries

Reproduced verbatim from the companion RDF. Execute loads the query into the workbench below and runs it live.

Three hops from tenant to warehouse table
PREFIX skg: <http://demo.openlinksw.com/schemas/ScaleKG/>
PREFIX schema: <http://schema.org/>
SELECT ?tenantIri ?tenant ?workloadIri ?workload ?tableIri ?tableName ?source
FROM <http://demo.openlinksw.com/ScaleKG#>
WHERE {
  ?tenantIri a skg:Tenant ; schema:name ?tenant .
  ?workloadIri skg:forTenant ?tenantIri ; schema:name ?workload ; skg:readsFrom ?tableIri .
  ?tableIri schema:name ?tableName ; skg:inSource ?sourceIri .
  ?sourceIri schema:name ?source .
}
ORDER BY ?tenant ?workload ?tableName
Databases per cluster
PREFIX skg: <http://demo.openlinksw.com/schemas/ScaleKG/>
PREFIX schema: <http://schema.org/>
SELECT ?clusterIri ?cluster ?ramGb (COUNT(?db) AS ?databases)
FROM <http://demo.openlinksw.com/ScaleKG#>
WHERE {
  ?clusterIri a skg:Cluster ; schema:name ?cluster ; skg:ramGb ?ramGb .
  OPTIONAL { ?db skg:hostedOn ?clusterIri }
}
GROUP BY ?clusterIri ?cluster ?ramGb
ORDER BY DESC(?databases)
Replication topology and the access-control gap
PREFIX skg: <http://demo.openlinksw.com/schemas/ScaleKG/>
PREFIX schema: <http://schema.org/>
SELECT ?linkIri ?sourceDb ?fromRegion ?targetDb ?toRegion ?syncMode ?rbacReplicated
FROM <http://demo.openlinksw.com/ScaleKG#>
WHERE {
  ?linkIri a skg:ReplicationLink ;
           skg:replicatesFrom ?sourceIri ; skg:replicatesTo ?targetIri ;
           skg:syncMode ?syncMode ; skg:rbacReplicated ?rbacReplicated .
  ?sourceIri schema:name ?sourceDb ; skg:hostedOn/skg:inRegion/schema:name ?fromRegion .
  ?targetIri schema:name ?targetDb ; skg:hostedOn/skg:inRegion/schema:name ?toRegion .
}
ORDER BY ?sourceDb
Entailment: what is a data asset?
DEFINE input:inference "urn:scalekg:inference"
PREFIX skg: <http://demo.openlinksw.com/schemas/ScaleKG/>
PREFIX schema: <http://schema.org/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?kindIri ?kind (COUNT(DISTINCT ?assetIri) AS ?assets)
FROM <http://demo.openlinksw.com/ScaleKG#>
FROM <http://demo.openlinksw.com/schemas/ScaleKG/>
WHERE {
  ?assetIri a skg:DataAsset ; a ?kindIri .
  ?kindIri rdfs:label ?kind .
  FILTER(?kindIri IN (skg:DataAsset, skg:GraphDatabase, skg:WarehouseTable))
}
GROUP BY ?kindIri ?kind
ORDER BY DESC(?assets)
The property hierarchy, read from the TBox
PREFIX skg: <http://demo.openlinksw.com/schemas/ScaleKG/>
PREFIX schema: <http://schema.org/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT DISTINCT ?workloadIri ?workload ?relation ?dependencyIri ?dependency
FROM <http://demo.openlinksw.com/ScaleKG#>
FROM <http://demo.openlinksw.com/schemas/ScaleKG/>
WHERE {
  ?workloadIri a skg:Workload ; schema:name ?workload ; ?relationIri ?dependencyIri .
  ?relationIri rdfs:subPropertyOf skg:dependsOn ; rdfs:label ?relation .
  ?dependencyIri schema:name ?dependency .
}
Two instances, one query: the collection graph on URIBurner joined to the view on demo
PREFIX schema: <http://schema.org/>
SELECT ?datasetIri ?datasetName ?classIri ?entities
FROM <https://linkeddata.uriburner.com/DAV/demos/daas/neo4j-scale-ai-production-vs-virtuoso-agent-rdf-memory-meshup-claude_sonnet_5_5-1.ttl>
WHERE {
  ?datasetIri a schema:Dataset ; schema:name ?datasetName ; schema:url ?viewGraph .
  FILTER(STR(?viewGraph) = "http://demo.openlinksw.com/ScaleKG#")
  SERVICE <https://demo.openlinksw.com/sparql> {
    SELECT ?classIri (COUNT(DISTINCT ?entityIri) AS ?entities)
    FROM <http://demo.openlinksw.com/ScaleKG#>
    WHERE { ?entityIri a ?classIri }
    GROUP BY ?classIri
  }
}
ORDER BY DESC(?entities)
Ten IRI classes
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/region_iri> "http://demo.openlinksw.com/ScaleKG/region/%d#this" (in region_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri> "http://demo.openlinksw.com/ScaleKG/cluster/%d#this" (in cluster_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri> "http://demo.openlinksw.com/ScaleKG/tenant/%d#this" (in tenant_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/environment_iri> "http://demo.openlinksw.com/ScaleKG/environment/%d#this" (in env_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/database_iri> "http://demo.openlinksw.com/ScaleKG/database/%d#this" (in db_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri> "http://demo.openlinksw.com/ScaleKG/replication/%d#this" (in link_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/source_iri> "http://demo.openlinksw.com/ScaleKG/source/%d#this" (in src_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/wtable_iri> "http://demo.openlinksw.com/ScaleKG/table/%d#this" (in wt_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri> "http://demo.openlinksw.com/ScaleKG/workload/%d#this" (in wl_id integer not null);
SPARQL CREATE IRI CLASS <http://demo.openlinksw.com/schemas/ScaleKG/job_iri> "http://demo.openlinksw.com/ScaleKG/job/%d#this" (in job_id integer not null);
The RDF View: one ALTER QUAD STORAGE statement
SPARQL
ALTER QUAD STORAGE virtrdf:DefaultQuadStorage
  FROM ScaleKG.kidehen.region AS r
  FROM ScaleKG.kidehen.db_cluster AS c
  FROM ScaleKG.kidehen.tenant AS t
  FROM ScaleKG.kidehen.environment AS e
  FROM ScaleKG.kidehen.graph_database AS d
  FROM ScaleKG.kidehen.replication_link AS l
  FROM ScaleKG.kidehen.warehouse_source AS ws
  FROM ScaleKG.kidehen.warehouse_table AS wt
  FROM ScaleKG.kidehen.workload AS w
  FROM ScaleKG.kidehen.workload_reads AS rd
  FROM ScaleKG.kidehen.analytics_job AS j
{
  GRAPH <http://demo.openlinksw.com/ScaleKG#>
  {
    <http://demo.openlinksw.com/schemas/ScaleKG/region_iri>(r.region_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/Region> as virtrdf:ScaleKG-region-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/region_iri>(r.region_id) <http://schema.org/name> r.region_name as virtrdf:ScaleKG-region-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/region_iri>(r.region_id) <http://demo.openlinksw.com/schemas/ScaleKG/cloud> r.cloud as virtrdf:ScaleKG-region-cloud .
    <http://demo.openlinksw.com/schemas/ScaleKG/region_iri>(r.region_id) <http://demo.openlinksw.com/schemas/ScaleKG/countryCode> r.country_code as virtrdf:ScaleKG-region-country .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/Cluster> as virtrdf:ScaleKG-cluster-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://schema.org/name> c.cluster_name as virtrdf:ScaleKG-cluster-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://demo.openlinksw.com/schemas/ScaleKG/clusterRole> c.cluster_role as virtrdf:ScaleKG-cluster-role .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://demo.openlinksw.com/schemas/ScaleKG/ramGb> c.ram_gb as virtrdf:ScaleKG-cluster-ram .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://demo.openlinksw.com/schemas/ScaleKG/storageGb> c.storage_gb as virtrdf:ScaleKG-cluster-storage .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://demo.openlinksw.com/schemas/ScaleKG/edition> c.edition as virtrdf:ScaleKG-cluster-edition .
    <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(c.cluster_id) <http://demo.openlinksw.com/schemas/ScaleKG/inRegion> <http://demo.openlinksw.com/schemas/ScaleKG/region_iri>(c.region_id) as virtrdf:ScaleKG-cluster-region .
    <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri>(t.tenant_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/Tenant> as virtrdf:ScaleKG-tenant-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri>(t.tenant_id) <http://schema.org/name> t.tenant_name as virtrdf:ScaleKG-tenant-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri>(t.tenant_id) <http://demo.openlinksw.com/schemas/ScaleKG/tier> t.tier as virtrdf:ScaleKG-tenant-tier .
    <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri>(t.tenant_id) <http://demo.openlinksw.com/schemas/ScaleKG/homeRegion> <http://demo.openlinksw.com/schemas/ScaleKG/region_iri>(t.region_id) as virtrdf:ScaleKG-tenant-region .
    <http://demo.openlinksw.com/schemas/ScaleKG/environment_iri>(e.env_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/Environment> as virtrdf:ScaleKG-env-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/environment_iri>(e.env_id) <http://schema.org/name> e.env_name as virtrdf:ScaleKG-env-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(d.db_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/GraphDatabase> as virtrdf:ScaleKG-db-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(d.db_id) <http://schema.org/name> d.db_name as virtrdf:ScaleKG-db-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(d.db_id) <http://demo.openlinksw.com/schemas/ScaleKG/purpose> d.purpose as virtrdf:ScaleKG-db-purpose .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(d.db_id) <http://demo.openlinksw.com/schemas/ScaleKG/hostedOn> <http://demo.openlinksw.com/schemas/ScaleKG/cluster_iri>(d.cluster_id) as virtrdf:ScaleKG-db-cluster .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(d.db_id) <http://demo.openlinksw.com/schemas/ScaleKG/ownedBy> <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri>(d.tenant_id) as virtrdf:ScaleKG-db-tenant .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(d.db_id) <http://demo.openlinksw.com/schemas/ScaleKG/environment> <http://demo.openlinksw.com/schemas/ScaleKG/environment_iri>(d.env_id) as virtrdf:ScaleKG-db-env .
    <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri>(l.link_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/ReplicationLink> as virtrdf:ScaleKG-link-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri>(l.link_id) <http://demo.openlinksw.com/schemas/ScaleKG/syncMode> l.sync_mode as virtrdf:ScaleKG-link-mode .
    <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri>(l.link_id) <http://demo.openlinksw.com/schemas/ScaleKG/topology> l.topology as virtrdf:ScaleKG-link-topology .
    <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri>(l.link_id) <http://demo.openlinksw.com/schemas/ScaleKG/rbacReplicated> l.rbac_replicated as virtrdf:ScaleKG-link-rbac .
    <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri>(l.link_id) <http://demo.openlinksw.com/schemas/ScaleKG/replicatesFrom> <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(l.source_db_id) as virtrdf:ScaleKG-link-from .
    <http://demo.openlinksw.com/schemas/ScaleKG/replication_iri>(l.link_id) <http://demo.openlinksw.com/schemas/ScaleKG/replicatesTo> <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(l.target_db_id) as virtrdf:ScaleKG-link-to .
    <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(l.source_db_id) <http://demo.openlinksw.com/schemas/ScaleKG/replicatedTo> <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(l.target_db_id) as virtrdf:ScaleKG-db-replicated-to .
    <http://demo.openlinksw.com/schemas/ScaleKG/source_iri>(ws.src_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/WarehouseSource> as virtrdf:ScaleKG-src-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/source_iri>(ws.src_id) <http://schema.org/name> ws.src_name as virtrdf:ScaleKG-src-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/source_iri>(ws.src_id) <http://demo.openlinksw.com/schemas/ScaleKG/vendor> ws.vendor as virtrdf:ScaleKG-src-vendor .
    <http://demo.openlinksw.com/schemas/ScaleKG/wtable_iri>(wt.wt_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/WarehouseTable> as virtrdf:ScaleKG-wt-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/wtable_iri>(wt.wt_id) <http://schema.org/name> wt.table_name as virtrdf:ScaleKG-wt-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/wtable_iri>(wt.wt_id) <http://demo.openlinksw.com/schemas/ScaleKG/rowCount> wt.row_count as virtrdf:ScaleKG-wt-rows .
    <http://demo.openlinksw.com/schemas/ScaleKG/wtable_iri>(wt.wt_id) <http://demo.openlinksw.com/schemas/ScaleKG/inSource> <http://demo.openlinksw.com/schemas/ScaleKG/source_iri>(wt.src_id) as virtrdf:ScaleKG-wt-source .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/Workload> as virtrdf:ScaleKG-wl-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://schema.org/name> w.wl_name as virtrdf:ScaleKG-wl-name .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://demo.openlinksw.com/schemas/ScaleKG/workloadKind> w.wl_kind as virtrdf:ScaleKG-wl-kind .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://demo.openlinksw.com/schemas/ScaleKG/latencyClass> w.latency_class as virtrdf:ScaleKG-wl-latency .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://demo.openlinksw.com/schemas/ScaleKG/forTenant> <http://demo.openlinksw.com/schemas/ScaleKG/tenant_iri>(w.tenant_id) as virtrdf:ScaleKG-wl-tenant .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://demo.openlinksw.com/schemas/ScaleKG/runsOn> <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(w.db_id) where (^{w.}^.db_id is not null) as virtrdf:ScaleKG-wl-db .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(w.wl_id) <http://demo.openlinksw.com/schemas/ScaleKG/queriesVirtually> <http://demo.openlinksw.com/schemas/ScaleKG/source_iri>(w.src_id) where (^{w.}^.src_id is not null) as virtrdf:ScaleKG-wl-src .
    <http://demo.openlinksw.com/schemas/ScaleKG/workload_iri>(rd.wl_id) <http://demo.openlinksw.com/schemas/ScaleKG/readsFrom> <http://demo.openlinksw.com/schemas/ScaleKG/wtable_iri>(rd.wt_id) as virtrdf:ScaleKG-wl-reads .
    <http://demo.openlinksw.com/schemas/ScaleKG/job_iri>(j.job_id) <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://demo.openlinksw.com/schemas/ScaleKG/AnalyticsJob> as virtrdf:ScaleKG-job-type .
    <http://demo.openlinksw.com/schemas/ScaleKG/job_iri>(j.job_id) <http://demo.openlinksw.com/schemas/ScaleKG/jobKind> j.job_kind as virtrdf:ScaleKG-job-kind .
    <http://demo.openlinksw.com/schemas/ScaleKG/job_iri>(j.job_id) <http://demo.openlinksw.com/schemas/ScaleKG/runDate> j.run_date as virtrdf:ScaleKG-job-date .
    <http://demo.openlinksw.com/schemas/ScaleKG/job_iri>(j.job_id) <http://demo.openlinksw.com/schemas/ScaleKG/billedSeconds> j.billed_seconds as virtrdf:ScaleKG-job-seconds .
    <http://demo.openlinksw.com/schemas/ScaleKG/job_iri>(j.job_id) <http://demo.openlinksw.com/schemas/ScaleKG/ranOn> <http://demo.openlinksw.com/schemas/ScaleKG/database_iri>(j.db_id) as virtrdf:ScaleKG-job-db .
  }
} ;

Query editor

▶ Run live on URIBurner SELECT: text/x-html+tr | DESCRIBE/CONSTRUCT: text/x-html-nice-turtle