SPARQL CONSTRUCT | AllegroGraph 9.0.1
Author: Franz Incorporated

Copyright (c) 2005 - 2026 Franz, Incorporated
Last updated 27 May 2026 at 10:34

# SPARQL `CONSTRUCT` in AllegroGraph

- Documentation Index
  - Release Notes
  - Quick Start
  - SSL/TLS Quick Start
  - Introduction
  - Setup and Configuration
    - Download
    - Server Installation
    - Server Configuration and Control
    - WebView
    - Database Upgrading
    - Managing Users
  - Server Management
    - Performance Tuning
    - Deleting Duplicate Triples
    - Purging Deleted Triples
    - Auditing
    - Managing Users
    - Replication
    - Point-in-Time Recovery
    - Transaction Log Archiving
    - Security Overview
    - Security Implementation
  - Tools
    - agtool
    - Data Loading
    - Data Export
    - Backup and Restore
    - Querying
    - RDFS++
    - Materializer
    - Event Scheduler
    - SHACL
  - Details
    - Triple Indices
    - Freetext Indices
    - Encoded IDs
    - Connection Pooling
    - N-dimensional Geospatial Overview
    - 2-D Geospatial
    - Temporal
    - Social Network
    - JavaScript
    - Datatypes
    - Data Conversion (Rapper)
    - Stored Procedures
    - Triple Attributes
    - Lineparse Format
  - Querying
    - SPARQL documentation summary
    - SPARQL Reference
    - SPIN
    - SPARQL Magic Properties
    - Prolog
  - 3rd-party tools
    - Solr text Indices
    - MongoDB integration
    - TopBraid Composer Plugin
    - Cloudera
  - Client APIs
    - Gruff
    - GraphTalker
    - REST/HTTP interface
    - HTTP reference
    - Javadocs (Sesame and Jena)
    - Python API
    - Lisp Reference
    - JavaScript
  - Tutorials
    - N-dimensional Geospatial
    - SPARQL Tutorial
    - Java Sesame
    - Java Jena
    - Python Sesame
    - Lisp
    - Prolog
    - More...
  - Other
    - Conferences and Seminars
    - Source Code on Github
    - Amazon EC2
    - Copyrights
  - Franz, Inc.

# Parts, stores, and `CONSTRUCT`

`SELECT`, `ASK`, and `DESCRIBE` queries have something in common: they require access only to triple parts found in the current store. (In fact, in the case of an `ASK` query, no parts are needed; the result is a boolean.)

That is to say, no result yielded by one of these queries can refer to a resource or literal that is not mentioned in the store on which you ran the query.

`CONSTRUCT`, on the other hand, can produce triples that are composed of parts not found in the triple store being queried. For example, given the dataset

    <http://example.com/a> <http://www.w3.org/2000/01/rdf-schema#label> "something" .

and the query

    CONSTRUCT {
      ?x <http://example.org/hasLiteral> ?literal .
    }
    WHERE {
      ?x ?p ?literal .
      FILTER (isLiteral(?literal))
    }

the store contains three parts (two URIs and a literal), but the output features the additional resource not present in the store: `<http://example.org/hasLiteral>`.

What would happen if a `CONSTRUCT` query returned an AllegroGraph `triple` — that is, a compact vector containing UPI representations of parts? Everything would work, right up until you tried to fetch the value of the UPI representing `<http://example.org/hasLiteral>`, which isn't in the store. You'd see an error like this:

    triple-store(11): (upi->value (db.agraph::coerce-to-upi (resource "http://example.org/hasLiteral")))
    Error: The UPI #(54 20 61 123 204 203 226 83 60 128 225 0) has not been
           added to the triple-store's string dictionary.
      [condition type: upi-not-in-string-table-error]

(Note that all query results will exhibit this problem if considered outside their originating store — AllegroGraph can only resolve the UPIs when the triple-store is available. `CONSTRUCT` is a different case.)

In order to produce triples that can later be examined, the query engine must intern these resources in the store being queried (the approach taken in AllegroGraph 2). This is not an ideal solution: — the store might be read-only, or a federation, and in any case the store's string table would grow over time as new queries were run against the store.

AllegroGraph has a mechanism for referring to RDF parts outside of a parent store: `future-part`s. These are Lisp objects that store an RDF value in its expanded form, and they're perfect for solving this problem. However, they don't fit into a `triple`, which is a vector of bytes, optimized for storing UPIs. For this reason, `CONSTRUCT` queries using the algebra query engine don't return triples; instead, they can return 3-element vectors containing `future-part`s and UPIs.

Similarly, blank nodes are meaningless outside of the context of a containing triple-store; furthermore, a blank node generated in one store could conceivably collide with a blank node already present in another. In programmatic `CONSTRUCT` output, blank nodes are represented by integers.

You can trivially take the output and insert it into a triple store by mapping back from integers to blank nodes. Here is an example using the Lisp API:

    (defun add-construct-output-to-store (faux-triples db &key (g (default-graph-upi db)))
      (let ((bnode-mappings (make-hash-table)))
        (flet ((part (x)
                 (typecase x
                   (integer
                     (or (gethash x bnode-mappings)
                         (setf (gethash x bnode-mappings)
                               (new-blank-node :db db))))
                   (t x))))
          (loop for tr in faux-triples do
                (add-triple (part (svref tr 0))  ; s
                            (part (svref tr 1))  ; p
                            (part (svref tr 2))  ; o
                            :db db
                            :g g)))))