Skip to content

Latest commit

 

History

History
341 lines (280 loc) · 9.66 KB

File metadata and controls

341 lines (280 loc) · 9.66 KB

Combined Multi-Model Examples

Demonstrates how Relational, NoSQL, RDF, and LPG models work together in IndentiaDB. Each example shows cross-model transactions and unified queries.


Table of Contents

  1. Relational / SQL Style
  2. NoSQL / Document
  3. Graph RDF (Triples)
  4. Graph LPG (Property Graph)
  5. Combined: Document + RDF + LPG in One Transaction

1. Relational / SQL Style

Standard typed tables with fields, aggregates, subqueries, and updates.

-- Schema: typed tables
DEFINE TABLE employee SCHEMAFULL;
DEFINE FIELD name      ON employee TYPE string;
DEFINE FIELD department ON employee TYPE string;
DEFINE FIELD salary    ON employee TYPE number;
DEFINE FIELD hire_date ON employee TYPE string;

DEFINE TABLE department SCHEMAFULL;
DEFINE FIELD name     ON department TYPE string;
DEFINE FIELD budget   ON department TYPE number;
DEFINE FIELD location ON department TYPE string;

-- Data
CREATE department:engineering CONTENT {
    name: "Engineering", budget: 500000, location: "Amsterdam"
};
CREATE department:research CONTENT {
    name: "Research", budget: 300000, location: "Utrecht"
};

CREATE employee:alice CONTENT {
    name: "Alice van den Berg", department: "Engineering",
    salary: 85000, hire_date: "2023-03-15"
};
CREATE employee:bob CONTENT {
    name: "Bob de Vries", department: "Engineering",
    salary: 92000, hire_date: "2022-01-10"
};
CREATE employee:carol CONTENT {
    name: "Carol Jansen", department: "Research",
    salary: 78000, hire_date: "2024-06-01"
};

-- Queries
SELECT name, salary FROM employee WHERE salary > 80000 ORDER BY salary DESC;
-- Bob (92000), Alice (85000)

SELECT department, math::mean(salary) AS avg_salary FROM employee GROUP BY department;

-- Subquery: employees in departments with budget > 400k
SELECT name, department FROM employee
WHERE department IN (SELECT VALUE name FROM department WHERE budget > 400000);
-- Alice and Bob (Engineering)

UPDATE employee:alice SET salary = 90000;

2. NoSQL / Document

Schemaless tables with nested objects, arrays, and record links.

DEFINE TABLE project SCHEMALESS;
DEFINE TABLE task SCHEMALESS;

CREATE project:indentiagraph CONTENT {
    name: "IndentiaGraph",
    status: "active",
    tags: ["database", "graph", "rdf", "lpg"],
    metadata: {
        created: "2024-01-15",
        lead: "Alice",
        priority: "high"
    },
    milestones: [
        { name: "v1.0", date: "2025-06-01", completed: true },
        { name: "v2.0", date: "2026-03-01", completed: false }
    ]
};

CREATE task:lpg_csr CONTENT {
    title: "Implement CSR adjacency",
    project: project:indentiagraph,
    assignee: "Bob", status: "done",
    labels: ["performance", "lpg"]
};
CREATE task:lpg_pagerank CONTENT {
    title: "Add PageRank algorithm",
    project: project:indentiagraph,
    assignee: "Bob", status: "done",
    labels: ["algorithm", "lpg"],
    depends_on: [task:lpg_csr]
};
CREATE task:acl_integration CONTENT {
    title: "ACL integration for LPG",
    project: project:indentiagraph,
    assignee: "Carol", status: "in_progress",
    labels: ["security", "lpg"]
};

-- Nested field access
SELECT name, metadata.lead FROM project WHERE status = "active";
-- "IndentiaGraph", lead: "Alice"

-- Array contains
SELECT title, assignee FROM task WHERE labels CONTAINS "lpg";
-- 3 tasks

-- Nested array filter
SELECT milestones[WHERE completed = true] AS done FROM project:indentiagraph;
-- [{name: "v1.0", ...}]

-- Record link traversal
SELECT title, project.name AS project_name FROM task WHERE assignee = "Bob";
-- Both of Bob's tasks show project_name: "IndentiaGraph"

3. Graph RDF

RDF triples stored in the triples table with subject/predicate/object structure.

-- Ontology: Person class
CREATE triples CONTENT {
    subject: { "_rdf_type": "NamedNode", "iri": "http://example.org/Person" },
    predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
    object: { "_rdf_type": "NamedNode", "iri": "http://www.w3.org/2002/07/owl#Class" },
    graph: "default"
};

-- Instances with properties and relationships
CREATE triples CONTENT {
    subject: { "_rdf_type": "NamedNode", "iri": "http://example.org/alice" },
    predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
    object: { "_rdf_type": "NamedNode", "iri": "http://example.org/Person" },
    graph: "default"
};
CREATE triples CONTENT {
    subject: { "_rdf_type": "NamedNode", "iri": "http://example.org/alice" },
    predicate: "http://xmlns.com/foaf/0.1/name",
    object: { "_rdf_type": "Literal", "value": "Alice van den Berg",
              "datatype": "http://www.w3.org/2001/XMLSchema#string" },
    graph: "default"
};
CREATE triples CONTENT {
    subject: { "_rdf_type": "NamedNode", "iri": "http://example.org/alice" },
    predicate: "http://xmlns.com/foaf/0.1/knows",
    object: { "_rdf_type": "NamedNode", "iri": "http://example.org/bob" },
    graph: "default"
};

-- (Similar triples for bob and carol...)

-- Query: find all Person instances
SELECT subject.iri AS person FROM triples
WHERE predicate = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
  AND object.iri = "http://example.org/Person";

-- Query: who does Alice know?
SELECT object.iri AS friend FROM triples
WHERE subject.iri = "http://example.org/alice"
  AND predicate = "http://xmlns.com/foaf/0.1/knows";
-- "http://example.org/bob"

-- Query: get Alice's name
SELECT object.value AS name FROM triples
WHERE subject.iri = "http://example.org/alice"
  AND predicate = "http://xmlns.com/foaf/0.1/name";
-- "Alice van den Berg"

4. Graph LPG

Project RDF triples into an LPG for traversals, shortest path, PageRank, and connected components.

RDF data: alice knows bob, bob knows carol (all Person-typed).

LPG Traverse (1-hop from Alice):

{
  "kind": {
    "Traverse": {
      "start": { "iri": "http://example.org/alice" },
      "edge": "knows",
      "direction": "Out",
      "min_hops": 1, "max_hops": 1,
      "target_label": "Person"
    }
  },
  "limit": 10,
  "return_fields": ["id", "hop_count"]
}

Result: bob (1 hop)

LPG Traverse (2-hop, friends-of-friends): Same query with max_hops: 2. Result: bob (1 hop), carol (2 hops)

Shortest Path (Alice to Carol):

{
  "kind": {
    "ShortestPath": {
      "start": { "iri": "http://example.org/alice" },
      "target": { "iri": "http://example.org/carol" },
      "edge": "knows",
      "direction": "Out"
    }
  }
}

Result: length = 2

PageRank: Scores sum to ~1.0. All connected Person nodes contribute.

Connected Components: All Person nodes (alice, bob, carol) are in one component.

5. Combined: Document + RDF + LPG in One Transaction

This is the key multi-model pattern. A single transaction spans:

  • RDF triples for semantic types (alice/bob are Person)
  • Document table (hr_employee) for business data (salary, department)
  • LPG projection that merges both sources into a unified graph

Setup

-- RDF: alice and bob are Person instances
CREATE triples CONTENT {
    subject: { "_rdf_type": "NamedNode", "iri": "http://example.org/alice" },
    predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
    object: { "_rdf_type": "NamedNode", "iri": "http://example.org/Person" },
    graph: "default"
};
CREATE triples CONTENT {
    subject: { "_rdf_type": "NamedNode", "iri": "http://example.org/bob" },
    predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
    object: { "_rdf_type": "NamedNode", "iri": "http://example.org/Person" },
    graph: "default"
};

-- Document: HR employee data with RDF IRI linkage
DEFINE TABLE hr_employee SCHEMALESS;
CREATE hr_employee:alice CONTENT {
    name: "Alice van den Berg",
    rdf_iri: "http://example.org/alice",
    department: "Engineering",
    salary: 85000,
    colleague_iri: "http://example.org/bob"
};
CREATE hr_employee:bob CONTENT {
    name: "Bob de Vries",
    rdf_iri: "http://example.org/bob",
    department: "Engineering",
    salary: 92000
};

LPG Projection Config

{
  "document_rules": [{
    "table": "hr_employee",
    "label": "Employee",
    "iri_field": "rdf_iri",
    "include_fields": ["name", "department", "salary", "rdf_iri"],
    "edge_fields": [{
      "field": "colleague_iri",
      "edge_type": "colleague"
    }]
  }]
}

Result After Projection

Alice's LPG node has:

  • Labels: ["Person", "Employee"] (Person from RDF, Employee from document rule)
  • Properties: {department: "Engineering", salary: 85000, name: "Alice van den Berg"}
  • Edges: colleague -> bob

Traverse Colleague Edges

{
  "kind": {
    "Traverse": {
      "start": { "iri": "http://example.org/alice" },
      "edge": "colleague",
      "direction": "Out",
      "min_hops": 1, "max_hops": 1,
      "target_label": "Employee"
    }
  },
  "limit": 10,
  "return_fields": ["id", "name", "department"]
}

Result: {id: "http://example.org/bob", name: "Bob de Vries", department: "Engineering"}

Incremental RDF Delta

Add a new RDF type for Alice without rebuilding:

PREFIX ex: <http://example.org/>
INSERT DATA {
    ex:alice a ex:Manager .
}

Result: Alice now has labels ["Person", "Employee", "Manager"]. Document properties are preserved.

Incremental Document Delta

Update Bob's salary:

UPDATE hr_employee:bob SET salary = 105000;

Result: Bob's salary property in the LPG updates to 105000. All other labels and properties are preserved.

Final Graph Analysis

After both deltas:

  • PageRank: Computed across the combined graph (RDF edges + document edges)
  • Connected Components (Employee filter): Alice and Bob are in one component (connected via colleague edge)