Prismatic Storage KuzuDB

Prismatic Storage KuzuDB

110 files Storage

Overview

Prismatic Storage KuzuDB implements the storage adapter protocol using KuzuDB, an embedded graph database optimized for analytical graph queries. It stores entity relationships, ownership chains, communication networks, and infrastructure topology as native graph structures, enabling efficient traversal, pattern matching, and community detection queries that are impractical in relational databases.

As an embedded database, KuzuDB runs within the BEAM process without requiring an external server. This eliminates network latency for graph queries and simplifies deployment. The adapter manages the database lifecycle through OTP supervision, handles schema evolution for node and edge types, and provides a Cypher query interface that intelligence analysts can use to express complex relationship traversals.

Graph storage is the natural complement to the platform's relational (PostgreSQL) and search (Meilisearch) layers. While PostgreSQL stores entity attributes and Meilisearch indexes text, KuzuDB captures the relationships between entities -- corporate ownership hierarchies, network infrastructure dependencies, communication patterns, and social connections.

Architecture

Application Code
       |
  PrismaticStorageCore Behaviour (Protocol)
       |
  KuzuDB Adapter
       |
  +----+----+----+
  |         |         |
Graph     Query     Schema
Manager   Engine    Manager
  |         |         |
  +----+----+----+
       |
  KuzuDB Embedded Engine
       |
  +----+----+
  |         |
Node      Edge
Tables    Tables

The Graph Manager GenServer owns the KuzuDB database connection and coordinates write operations. The Query Engine translates both structured API calls and raw Cypher queries into KuzuDB operations. The Schema Manager handles node and edge type definitions, property schemas, and index creation for frequently queried attributes.

Adapter Pattern and PrismaticStorageCore.Behaviour

The KuzuDB adapter implements the Prismatic Storage Core contract with a trait set tailored for graph operations: Storable, Identifiable, Queryable, GraphTraversable, Batchable, and Streamable. The inclusion of the GraphTraversable trait distinguishes this adapter from all others in the platform and provides the foundation for relationship-centric intelligence analysis.

The Storable trait implementation handles the unique challenge of mapping flat Elixir maps to KuzuDB's property graph model. Entity maps are stored as node properties, with the entity type determining the node label. The to_storage/1 callback extracts the entity's type, key, and properties, mapping them to KuzuDB's node creation syntax. The from_storage/2 callback reconstructs Elixir maps from KuzuDB query results, handling the translation between KuzuDB's type system (which includes graph-specific types like NODE and REL) and standard Elixir terms.

The GraphTraversable trait is the adapter's defining capability. It provides callbacks for multi-hop traversal (traverse/3), shortest path computation (shortest_path/3), neighbor discovery (neighbors/2), and community detection (detect_communities/3). These operations have no meaningful equivalent in relational or key-value stores -- attempting them through SQL joins would produce prohibitively expensive queries as hop depth increases, while key-value stores lack the structural awareness to traverse relationships at all.

The Queryable trait implementation translates the platform's generic query interface into Cypher, KuzuDB's query language. Simple key-value lookups translate to MATCH (n:Type {key: $value}) RETURN n patterns, while filter-sort-paginate queries generate more complex Cypher with WHERE, ORDER BY, and LIMIT clauses. The adapter also accepts raw Cypher queries for analysts who need the full expressive power of the query language.

The Batchable trait is critical for graph population workflows. When OSINT collection produces thousands of entity relationships, the adapter uses KuzuDB's bulk loader to insert nodes and edges in large batches rather than individual transactions. Batch insertion bypasses the normal transactional overhead and writes directly to the columnar storage backend, achieving throughput orders of magnitude higher than row-by-row insertion.

Contract testing through PrismaticStorageCore.ContractTest verifies standard CRUD and query operations, while graph-specific tests exercise traversal depth, cycle detection, and community clustering accuracy.

Key Features

Graph Storage

  • Native node and edge storage with typed properties
  • Cypher query language support for expressive graph traversals
  • Schema-flexible property graphs with runtime type evolution
  • Embedded deployment -- no external server, no network overhead
  • Automatic indexing on frequently queried node properties

Graph Queries

  • Multi-hop relationship traversal with variable-length path patterns
  • Shortest path computation between any two entities
  • Pattern matching with complex structural constraints
  • Graph projection for analytical subgraph extraction
  • Community detection for identifying entity clusters

Integration

  • Automatic graph population from OSINT data through adapter hooks
  • Entity resolution with graph merge for deduplicating nodes from multiple sources
  • Temporal graph versioning for tracking relationship changes over time
  • Export to visualization tools (GraphML, DOT, JSON) for analyst consumption

Graph Schema Design

The adapter implements a typed property graph schema where node labels correspond to entity types and edge labels correspond to relationship types. The schema is defined declaratively and managed by the Schema Manager, which creates KuzuDB node and edge tables on application boot and handles schema evolution as new entity or relationship types are introduced.

Node LabelPropertiesExample
Companyico, name, country, risk_scoreCzech business entity
Personname, nationality, rolesIndividual associated with entities
Domainname, registrar, created_atInternet domain name
IPaddress, asn, geolocationNetwork address
Certificatesubject, issuer, expiryTLS certificate
Edge LabelSourceTargetProperties
OWNSCompanyCompanyshare, since, source
EMPLOYSCompanyPersonrole, since, until
RESOLVES_TODomainIPfirst_seen, last_seen
ISSUED_FORCertificateDomainvalid_from, valid_until

The schema supports temporal graph versioning through edge properties. Rather than deleting edges when relationships change, new edges are created with updated timestamps and the old edges are marked with an until property. This preserves the complete history of entity relationships, enabling point-in-time queries that reconstruct the graph as it existed at any historical moment.

Usage

# Store an entity relationship as a graph edge
PrismaticStorageKuzudb.create_edge(:owns, company_node, subsidiary_node, %{
  share: 0.75,
  since: ~D[2020-01-15],
  source: :business_registry
})

# Traverse an ownership chain up to 5 hops deep
{:ok, chain} = PrismaticStorageKuzudb.query("""
  MATCH (root:Company {ico: '12345678'})-[:OWNS*1..5]->(subsidiary:Company)
  RETURN subsidiary.name, subsidiary.ico, length(path) AS depth
  ORDER BY depth
""")
# => {:ok, [%{name: "Sub Corp A", ico: "87654321", depth: 1}, ...]}

# Find shortest path between two entities
{:ok, path} = PrismaticStorageKuzudb.shortest_path(entity_a, entity_b)
# => {:ok, %Path{nodes: [...], edges: [...], length: 3}}

# Community detection for network analysis
{:ok, communities} = PrismaticStorageKuzudb.detect_communities(:Company,
  algorithm: :label_propagation,
  min_size: 3
)
# => {:ok, [%Community{id: 1, members: ["e-1", "e-2", "e-3"], density: 0.85}]}

# Export subgraph for visualization
{:ok, graphml} = PrismaticStorageKuzudb.export(
  "MATCH (n:Company)-[r:OWNS]->(m:Company) RETURN n, r, m",
  format: :graphml
)

Testing

mix test apps/prismatic_storage_kuzudb/test
mix test apps/prismatic_storage_kuzudb/test --cover
Test CategoryTestsWhat It Verifies
Adapter ContractShared suiteAll declared trait compliance
Graph Traversal12Multi-hop paths, cycle handling, depth limits
Shortest Path6Path correctness, disconnected graph handling
Community Detection4Clustering accuracy, minimum size filtering
Schema Evolution6Node/edge type addition, property migration
Temporal Queries8Point-in-time reconstruction, edge versioning

Integration Points

The graph store receives entity relationships from multiple platform sources. Prismatic Tracking feeds infrastructure topology changes as graph mutations. Social media intelligence contributes social connection edges between person entities. Prismatic Modalities cross-modal entity resolution creates edges linking entities discovered across different intelligence modalities. The Prismatic HAWKEYE visitor intelligence system queries graph paths to assess whether visitor IP addresses are associated with known threat infrastructure.

NABLA Compliance

Graph operations maintain full epistemic provenance through edge properties that record the source, timestamp, and confidence of each relationship assertion. Multiple edges between the same pair of nodes from different sources implement Signal Plurality at the relationship level -- contradictory relationship claims are preserved as parallel edges rather than being silently resolved. The Contradiction Preservation axiom is naturally satisfied by the graph model's ability to represent multiple, potentially conflicting relationships between the same entities. Temporal graph versioning satisfies Time Decay by enabling queries that weight recent observations more heavily than historical ones.

Performance

MetricValue
Single-hop traversalSub-millisecond
Multi-hop traversal (5 hops)Low milliseconds
Bulk node insertion100,000+ nodes/second
Community detectionSeconds for 10K-node graphs
Shortest pathMilliseconds for typical graph sizes

Connect & Contribute

Created by Tomáš Korcak (korczis) | Open Source under GHL