Semogram Docs
Data PipelinesOutputs and decisions

Build ontology facts

Map two database records into Order entities and persist them to a fact store

This example turns two order records into ontology entities, then persists the fact set. It uses Postgres read, a project ontology package and Postgres's ontology fact-store capability. Mapping and materialization are distinct nodes: producing a fact set alone does not store it.

What you need

You need a Semogram account with workspace membership, a project in that workspace and permission to create and run pipelines. Reading or writing also requires access to the selected endpoints and external systems. Creating a pipeline does not grant those permissions.

Use a reachable test PostgreSQL database and its SQL client. You need installation/endpoint management access as well as pipeline read/write/execute access. The connection must be reachable from the execution runtime, not only from your laptop.

Prepare records and read access

Create the two-row source
CREATE TABLE public.pipeline_demo_orders (
  order_id integer PRIMARY KEY,
  region text NOT NULL,
  total numeric(12,2) NOT NULL
);
INSERT INTO public.pipeline_demo_orders VALUES
  (1, 'North', 120.00),
  (2, 'South', 75.50);

Open workspace Plugins → Explore, find Postgres (@craven/postgres), inspect its installed contract and install the read capability. Fill these connection fields and run its supported connection check:

Installation fieldValue
HostYour reachable database host
Port5432, or your configured port
DatabaseThe test database containing the fixture
UserA database identity with the required access
PasswordEnter in the protected installation field
SslEnable when the database requires TLS

Open workspace Data Endpoints → New data endpoint. Use name demo_orders, namespace pipelines, direction Ingress, the installed Postgres read capability and Stream (source_stream) as the source contract. In the target fields set Schema to public and Table to pipeline_demo_orders. Save and inspect its schema/sample. demo_orders is a name you choose in Semogram; public.pipeline_demo_orders is the actual database table. Keep its returned endpoint UUID for programmatic examples.

The Postgres installation guide and endpoint guide provide additional detail; the required setup for this fixture is included here.

Prepare the ontology package

In this project, open Ontology and create a package for the example. Use the authoring assistant or the supported ontology editor to define class Order, property orderId (integer), region (string) and total (number), with the properties attached to Order. Compile/validate the package and inspect the exact class/property term references it exposes. Keep its package UUID; the words here are terms you define, not preinstalled business definitions.

Use a stable entity identifier template order-{order_id}. Confirm the two IDs resolve to order-1 and order-2; choose a namespace suitable for real data before merging other systems.

Install and configure the fact store

In Plugins → Explore, choose Postgres's ontology-store fact-store capability. Fill the same Host, Port, Database, User, Password and Ssl fields listed for the source, with a user authorized for schema/table setup, materialization and readback. It is a separate capability from raw-table read or write.

Prepare a dedicated schema in the test database:

Prepare the fact-store schema
CREATE SCHEMA IF NOT EXISTS pipeline_demo_facts;

Create a workspace endpoint demo_order_facts, namespace pipelines, direction Materialization, contract ontology_fact_store, the installed fact-store capability. Set target Type postgres_ontology_fact_store, Schema pipeline_demo_facts, Table prefix orders. Save/check it. These selectors describe generated fact-store storage, not the input orders table. More installation detail is available in the Postgres guide.

Configure the graph

Create Ingress → Ontology mapping → Ontology materializer. Ingress reads demo_orders in Full load/parser mode into orders. Mapping uses the actual compiled package, output order_facts, and an ont-fact-set output port connected to the materializer's fact input.

Assistant prompt
Read demo_orders, map each row to the compiled Order class with ID order-{order_id}, integer orderId, string region and numeric total. Preserve source identity. Materialize the fact set to demo_order_facts using the selected package. Show the exact term references, store and policy before saving.

Choose the compiled Ontology package on mapping and materializer. Bind mapping input orders to source output orders. Add the Order entity rule with its ID template and property fields. Use the actual package term references. Select Data endpoint demo_order_facts on the materializer; inspect mode and validation/conflict settings before executing.

This is the node’s ontologyMapping section inside a complete pipeline document, not a standalone API/MCP action. Resource placeholders must be replaced with the installed IDs.

Node configuration
{
  "packageId": "<ONTOLOGY_PACKAGE_UUID>",
  "inputs": {
    "orders": "orders"
  },
  "output": "order_facts",
  "mode": "upsert",
  "entities": [
    {
      "class": "Order",
      "id": {
        "template": "order-{order_id}"
      },
      "properties": {
        "orderId": {
          "from": "order_id",
          "as": "integer"
        },
        "region": {
          "from": "region",
          "as": "string"
        },
        "total": {
          "from": "total",
          "as": "number"
        }
      },
      "identities": [
        {
          "sourceNamespace": "pipeline-demo",
          "sourceKey": "order_id",
          "sourceId": {
            "from": "order_id"
          }
        }
      ],
      "provenance": {
        "system": "pipeline-demo"
      }
    }
  ],
  "relationships": []
}

Materializer definition:

ontologyMaterializer section
{
  "packageId": "<ONTOLOGY_PACKAGE_UUID>",
  "inputs": {
    "facts": "order_facts"
  },
  "dataEndpointId": "<FACT_STORE_ENDPOINT_UUID>",
  "mode": "upsert",
  "validation": {
    "unknownTerms": "reject_fact_set",
    "invalidRecords": "reject_fact_set",
    "cardinality": "enforce",
    "datatype": "enforce"
  }
}

Validate, save and run

Validate the draft and resolve errors. Preflight checks configuration only; it does not produce records or run a model. Save version, inspect the active saved graph and Run once. Open the run and compare the named step's output with the expected result below. Keep the run ID and inspect errors/counts, not only the assistant's response. Programmatic launch uses HTTP POST /api/v1/projects/<PROJECT_ID>/pipelines/<PIPELINE_ID>/execute with pipelines:execute and an Idempotency-Key, or MCP pipeline_execute with pipelineId, projectId and idempotencyKey.

If the Studio result only exposes an artifact handle, open the corresponding output/artifact inspection rather than treating that handle as a row preview. To persist rows externally, add an Egress endpoint and test its write semantics; the examples below do not silently create a destination.

Verify persisted facts

Check both mapping and materialization steps. Inspect the entity IDs, term references, totals, source identity and any quarantined/rejected records. Use the project's supported ontology read binding/query workflow to read the selected store: create a read binding for this package/store and publish a query selecting Order and its orderId/region/total properties. Execute that query for the two known IDs and compare against the input. A raw database table preview is not a substitute for ontology readback.

Expect two Order entities with the known values. If no facts are visible, check the materializer output, actual package terms and read binding before rerunning. Choose conflict, snapshot/delta and atomicity behavior supported by this store; setting a serialized mode cannot expand its contract.