Skip to content

Transformers

Your sources become graph data, by configuration rather than code

A Transformer is an independent processor that reads one kind of source and emits the graph data your model describes. It is configured against the model you published in Studio, not written against a schema, so refining the model does not mean rewriting an application.

How it works

The mapping is the program

A Transformer has no opinion about your domain. It carries the mapping you published and applies it, record by record, until the source is exhausted.

mechanism

A field becomes a property because the model said so

You point a Transformer at a source and hand it a mapping. For each record it resolves an identity, applies the mapping and emits triples, or nodes and edges if you are building a property graph. Where a value needs work before it fits, over a hundred built-in functions cover the usual cases, string handling, dates, arithmetic, hashing and lookups, and you can write your own for anything specific to you. The mappings themselves are RML and R2RML, which are open specifications, so what decides the meaning of your data is a file you can read and diff rather than a codebase you have to maintain.

The consequence: changing your mind about the model costs an afternoon of configuration, not a development cycle.

customers.json · transform mapping customer-v14
gbo:Customer/88213 gbo:Customer
gbo:Customer/88213 Ardent Logistics
gbo:Customer/88213 gbo:Account/GB-4471
gbo:Account/GB-4471 2019-04-02 (date)

n-triples 11 emitted from one record, validated against customer.ontology all passed
unmapped: 0 · records that do not fit go to the failure topic with their reason

one call bash
# a source, and the mapping that gives it meaning
curl -X POST http://transformer:8080/process \
-H 'Content-Type: application/json' \
-d '{
"inputFileURL": "https://api.internal/v2/customers",
"logicalSource": "customers",
"mappingURL": "file:///var/local/customer-v14.ttl"
}'
# it answers with the graph data it wrote
/var/local/graphbuild-output/customers.nq
# or give it a topic and it never needs calling again
kafkaConsumerTopic: cdc.customers · ingesting

Choosing

One per kind of source, and you run as many as you need

Each Transformer specialises in how it reaches data, not in what the data means. Meaning comes from the model, which is why a setup can start as one container against one source and grow without the model being touched.

Semi-structured files

JSON, XML, CSV, XLSX and ODS. Point it at a path or a URL and it reads the file; give it a Kafka topic and it reads messages as they arrive. Several mappings can run from one source, so one file can populate more than one part of the model.

SQL databases

Anything with a JDBC driver, which in practice means MySQL, SQL Server, Oracle, Postgres and the rest. Queries can be iterated in pages so a table too large to hold in memory is still a single configured job rather than a script somebody babysits.

REST endpoints

A RESTful endpoint that returns JSON or XML is a URL, and a URL is something the semi-structured Transformer already reads. Cloud applications and internal services come in the same way a file does, with the same mapping and the same output.

The other option

For a relational source, you do not have to move the data at all

Everything above copies your source into a graph. There is a second way to use the same model, and it is worth knowing about before you assume the copy is compulsory.

materialise or virtualise

The same model, answered at query time

A materialised graph is built by a Transformer and loaded by a Writer. The data is copied, it is fast to traverse, and it is as current as its last run or its change feed. Virtualisation uses the same Studio model and the same R2RML mapping, and copies nothing: a SPARQL query is translated into SQL against your relational database as it is asked, and the answer comes back shaped by the ontology. Build the model, connect the database, write the query. It is relational sources only, because R2RML maps tables, and the things that come with an ingest do not apply. There is no provenance, no change data capture, and no graph left behind when you close the connection.

The consequence: nothing to store and nothing to keep in step, in exchange for your source database's own query performance. It suits data that is not allowed to move, and it suits trying a model out before committing a database to it.

virtual · customers · query time sparql → sql, nothing stored
0 ms sparql · asked ?c gbo:holdsAccount ?a
2 ms customer-v14 · translated to sql, 2 joins
310 ms postgres · returned 1,180 rows
312 ms answered 590 customers · 1,180 accounts
stored nothing

Change data capture

The graph keeps itself in step with the systems it came from

A graph that is rebuilt every night is a graph people learn not to trust between rebuilds. Change data capture removes the gap.

staying current

A row changes, and so does the graph

Debezium watches the source database and writes every create, update and delete to Kafka. Because that payload arrives as JSON, the semi-structured Transformer picks it off the topic and maps it exactly as it maps anything else, producing RDF or CSV for just the part that moved. The output lands as a file, its URL goes back onto a topic, and the Writer applies it to your graph. Setups are documented for MySQL, Postgres and MongoDB.

The consequence: the same mapping serves the first full load and every change after it. There is no second pipeline to write and no second thing to keep correct.

cdc · customers · live debezium → kafka → transformer
11:04:18 debezium · update customers/88213
11:04:18 transform · mapped 6 triples
11:04:19 writer · update ~ 1 node
11:04:22 debezium · delete accounts/GB-3390
11:04:22 writer · delete - 1 node · - 3 edges

Whichever you run

Four things you get without configuring them

These are properties of the platform rather than of any one connector, which is the point of the connectors being interchangeable.

Provenance, as standard

Every ingest records where the data came from and when, using PROV-O rather than a convention of ours. You get a record of the data over time, so what the graph said last quarter is still answerable this quarter.

Horizontal scale

Transformers are separate containers with no shared state, so a load that is taking too long is answered by running more of them. Volume is a deployment question rather than a rewrite.

Functions, and your own

Over a hundred built-in functions handle the transformations that come up in every project. When your domain needs something they do not cover, you add a custom function rather than pre-processing the source somewhere else.

A queue for what does not fit

Records that fail the mapping are not dropped and do not stop the run. They go to a Kafka failure topic with the reason attached, so they can be reviewed and processed later once the model or the source is corrected.

Also available

Two more Transformers, by arrangement

These sit outside the standard set and are scoped with you rather than listed with a price. If one of them is the source that matters to you, a conversation is the right place to start.

RESTful Transformer

For cloud applications, internal services and third-party APIs where the endpoint needs more than a URL: authentication, pagination, rate limits and the particular shape a given vendor returns. Configured against the same model as every other Transformer, producing the same output.

Document Transformer

For DOCX and PDF, where there is no schema to map because the structure is prose. It reads the documents with an LLM and pulls out a graph, and the thing that makes that trustworthy rather than creative is that it is aimed at an ontology you have already published. The model still comes first. The LLM is finding your classes and properties in the text, not deciding what the classes should be.

Bring us a source we have not seen

The fastest way to judge this is to watch one of your own files, tables or endpoints become graph data against a model of your domain.

  • 45 minutes, your data, no installation
  • Runs in your account, on your infrastructure
  • You keep whatever we model