Tutorial | AllegroGraph 9.0.1
Author: Franz Incorporated

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

# AllegroGraph 9.0.1 Tutorial

- 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.

- Starting Allegro CL and loading AllegroGraph
- Creating or Opening a triple-store
- Namespaces and the reader macro for nodes
- AllegroGraph Notation
- Creating a triple programmatically
  - Notes on add-triple
- Printing a triple
  - Printing nodes again
- Querying for triples
  - A cursor version
- Deleting triples
- Using Prolog (without the triple-store)
  - Using Prolog with the triple-store
  - Using the select macro as a wrapper around Prolog
- In conclusion

Documentation Index

This document introduces AllegroGraph. It assumes that you are somewhat familiar with RDF (Resource Description Framework), RDFS (RDF Schema), and OWL (Web Ontology Language). The following resources provide more details on each of these:

- RDF: http://www.w3.org/TR/rdf-primer/,
- RDFS: http://www.w3.org/TR/rdf-schema/, and
- OWL: http://www.w3.org/TR/owl-guide/.

# The AllegroGraph Tutorial

AllegroGraph only works with Allegro CL 8.2 or higher. Please contact sales@franz.com to obtain a copy of Allegro CL 8.2 and AllegroGraph.

This tutorial shows AllegroGraph in action. If you want to work along, you will need to download and install AllegroGraph before executing the examples shown below.

The code examples used in this tutorial are installed along with AllegroGraph, and reside in the agraph/tutorial-files/ subdirectory of the Allegro directory. On Windows, the Allegro directory is usually c:/Program Files/acl81.

To make it easier to follow along, we suggest that you open agraph-tutorial.lisp now in your IDE of choice. The examples that follow assume that the files are located in agraph/ subdirectory of the Allegro CL installation directory. Note that the triple IDs that are returned as you work through the tutorial may differ from those displayed in this document; there is no need to be concerned about this.

## Starting Allegro CL and loading AllegroGraph

AllegroGraph works best with mlisp (Modern case-sensitive Lisp). It also supports alisp (ANSI case-insensitive Lisp). All of the examples in this document are from mlisp. To use AllegroGraph, start Allegro CL and evaluate the following form:

    ;; load AllegroGraph
    (require :agraph)

Next, set up some basic niceties for interacting with AllegroGraph: the !-reader for reading URIs and literals in Lisp expressions by prefixing them with a ‘!’ character, and a package in which AllegroGraph symbols are available. We'll also set up some tracing options for easier printing.

    ;; Switch to the AllegrGraph package
    (in-package :db.agraph.user)
    ;; turn on the convenience !-reader
    (enable-!-reader)
    ;; tell AllegroGraph to print triples more readably
    (enable-print-decoded t)

If the (require :agraph) fails, please make sure the installation was performed correctly.

## Creating or Opening a triple-store

The first thing we need to do is to create a triple-store. Most of the functions described below will not work without an open triple-store. So when you are experimenting always have a triple-store open.

The function create-triple-store creates a new triple-store and opens it. If you use the triple-store name "ag-test"

    > (create-triple-store "ag-test")
    #<db.agraph::triple-db ag-test, 0, open @ #x10039e58e2>

It may takes several seconds for AllegroGraph to create (or re-open) a triple-store because it is starting multiple maintenance processes and readying on-disk data structures.

We will use `ag-test` throughout this document but you can use any name you'd like! When you're done with a triple-store, you can close it with close-triple-store

    > (close-triple-store)
    nil

and re-open it with open-triple-store:

    > (open-triple-store "ag-test")
    #<db.agraph::triple-db ag-test, 0, open @ #x1003cc39e2>

## Namespaces and the reader macro for nodes

When working in Lisp with AllegroGraph, you will spend a lot of time inspecting triples and trying to find triples by typing in URIs. To save typing the namespace part of a URI over and over again, we use the exclamation mark to introduce a shorthand. To see ! in action, let's register a namespace:

    > (register-namespace "ex" "http://franz.com/things#"
       :errorp nil)
    "http://franz.com/things#"

AllegroGraph already registered several common RDF(S) and OWL namespaces for you. You can see them using display-namespaces:

    > (display-namespaces)
    rdf => http://www.w3.org/1999/02/22-rdf-syntax-ns#
    xsd => http://www.w3.org/2001/XMLSchema#
    ex => http://franz.com/things#
    rdfs => http://www.w3.org/2000/01/rdf-schema#
    fn => http://www.w3.org/2005/xpath-functions#
    err => http://www.w3.org/2005/xqt-errors#
    owl => http://www.w3.org/2002/07/owl#
    xs => http://www.w3.org/2001/XMLSchema#

Now we are ready to experiment with the !-reader macro.

! expands namespace prefixes and understands both quotation marks and Unicode. For example, the following two nodes are the same:

    > !ex:Dog
    !ex:Dog

    > !<http://franz.com/things#Dog>
    !<http://franz.com/things#Dog>

    > (part= !ex:Dog !<http://franz.com/things#Dog>)
    t

    ;; the literal string "Dog"
    > !"Dog"

Evaluating these forms puts the following nodes into the string dictionary:

    "http://franz.com/things#Dog"
    "Dog"

The function part->string reverses the mapping from node to the URI string. In this case, use the value that lisp returned earlier for !ex:Dog.

    > (part->string !ex:Dog)
    "<http://franz.com/things#Dog>"

When you are developing your application in the listener, you may not want to look at the entire URI. The function part->concise is like part->string but presents a best-guess abbreviation of the URI.

    > (part->concise !ex:Cat)
    "ex:Cat"

part->concise will return just the string when called on a UPI that refers to a literal.

    > (part->concise !"A string")
    "A string"

## AllegroGraph Notation

Before we go much further, we'll describe the notation that AllegroGraph uses to represent resources and literals as strings, future-parts and Unique Part Identifiers (UPIs).

AllegroGraph strikes a balance between displaying complete but lengthy URIs and concise but meaningless abbreviations. The output format also depends on whether it is displaying a string representation of a UPI, a future-part or a bare UPI. For strings, AllegroGraph adopts the N-Triples notation for URIs and provides several different output formats for you to choose from. These are:

- :ntriple - ASCII escaping (i.e., non 7-bit ASCII and control characters are printed in N-Triples format) plus N-Triple syntax for resources, blanks and literals

- :long - N-Triple syntax for resources, blanks and literals. Prints characters using Unicode.

- :concise - ASCII escaping, no extra literal information (i.e., any language and type information is suppressed in the output). If a namespace mapping is available, it will be used.

- :terse - the string contents of the UPI without additional type or language data for literals (as in :concise); namespace information will be suppressed.

Future-parts are displayed using namespace plus local name (if a namespace mapping is available). Finally, depended on whether or not you have used the function enable-print-decoded, UPIs will display themselves as length 12 octet vectors or in the terse string notation surrounded by curly brackets.

The following are thus all representative of the same RDF literal "Dürst" (note the umlaut over the `u`):

- as an undecoded UPI : #(5 0 0 0 0 116 115 114 60 195 68 7)
- as a decoded UPI : {Dürst}
- as a future-part : !"Dürst"
- String in N-triples format : "\"D\\u00FCrst\""
- String in long format : "\"Dürst\""
- String in concise format : "D\\u00FCrst"
- String in terse format : "Dürst"

Here is another brief example:

    > (enable-print-decoded nil)
    nil

    > (upi !rdf:type)                            ;no decoding
    #(232 179 38 248 194 24 210 86 213 0 183 0)

    > (enable-print-decoded t)
    t

    > (setf u (upi !rdf:type))                   ;terse format
    {type}

    > (part->string u :format :ntriples)
    "<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>"

    > (part->string u :format :long)             ;just like :ntriples in this case
    "<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>"

    > (part->string u :format :concise)          ;concise includes namespace
    "rdf:type"

    > (part->string u :format :terse)            ;terse does not
    "type"

You'll see many examples of the different formats as you work through this tutorial. When in doubt, experiment!

## Creating a triple programmatically

Now that we know how to enter nodes we will add some triples programmatically. (Note: The triple id numbers returned below are session dependent, and you may get different numbers in your experiment. Make sure to use a number returned by one of the expressions as you continue this tutorial.)

    > (add-triple !ex:Mammal !rdf:type !owl:Class)
    1
    > (add-triple !ex:Dog !rdfs:subClassOf !ex:Mammal)
    2
    > (add-triple !ex:Fido !rdf:type !ex:Dog)
    3
    > (add-triple !ex:Fido !ex:has-owner !ex:John)
    4
    > (add-triple !ex:Company !rdf:type !owl:Class)
    5
    > (add-triple !ex:CommercialCompany !rdfs:subClassOf !ex:Company)
    6
    > (add-triple !ex:Franz !rdf:type !owl:CommercialCompany)
    7
    > (add-triple !ex:John !ex:works-at !ex:Franz)
    8
    > (add-triple !ex:Franz !ex:has-product !ex:AllegroGraph)
    9

The numbers that are returned by add-triple are the unique triple-ids of the just added triple. We can use these numbers to look at a triple. Let's look at triple ID 4.

    > (setf tr (get-triple-by-id 4))
    <Fido has-owner John>

A triple data structure is returned. 1 This is a vector of 56 octets representing the four (!) parts of the triple and its triple ID. The parts are the subject, predicate, object and graph. You can use accessor functions subject, predicate, object, graph and triple-id to get at a triple's sub-structure.

    > (triple-id tr)
    4
    > (subject tr)
    {Fido}

The four nodes of a triple are represented as Unique Part Identifiers (or UPIs). These are either 12-byte hashed representations of URIs and literals or directly encoded values. See the AllegroGraph Introduction and the reference for more information. To see the triple in its native representation, we can turn off enable-print-decoded:

    > (enable-print-decoded nil)
    nil
    > tr
    #(78 134 60 220 246 40 208 148 75 219 198 0 119 141 131 175 192 18 161
      94 17 1 23 0 202 224 162 157 147 62 130 139 128 204 27 0 0 0 0 0 167
      99 152 67 0 0 0 31 4 0 0 0 18 40 2 16)

    ;; let's turn it back on for now
    > (enable-print-decoded t)
    t

### Notes on add-triple

The function add-triple takes either strings, UPIs, or future-parts. If the argument is a UPI AllegroGraph assumes that it is a valid 2 . It is slightly more complicated to understand what happens when you use strings as arguments. AllegroGraph cannot always see from a string whether you want it to be a resource or a literal. Therefore we have chosen the convention that the strings should follow the N-Triples syntax. The reader macro will do this for you automatically

    > !ex:John
    !ex:John

    > !"john"
    !"john"

so `(add-triple !ex:John !rdf:comment !"john")` will do the right thing.

Suppose, however, you need to create resource and literal strings programmatically. For that we have created the convenience functions resource and literal:

    > (resource "http://franz.com/simple#Peter")
    !<http://franz.com/simple#Peter>

    > (literal "Peter")
    !"Peter"

    > (let ((str1 "http://franz.com/simple#Peter")
            (str2 "Peter"))
        (setf triple-id
         (add-triple (resource str1) !rdf:comment (literal str2))))
    10

    > (print-triple (get-triple-by-id triple-id) :format :concise)
    <10: http://franz.com/simple#Peter rdf:comment Peter>
    #(200 74 120 93 224 212 32 42 151 60 ...)

## Printing a triple

To print out a triple, use the print-triple function (see also "Querying for triples" below). `print-triple` can print the triple in concise, long or N-Triples format.

    > (print-triple tr :format :concise)
    <4: ex:Fido ex:has-owner ex:John>       ;printed
    <Fido has-owner John>                   ;returned

    > (dolist (e (get-triples-list))
       (print-triple e :format :concise))
    <1: ex:Mammal rdf:type owl:Class>
    <2: ex:Dog rdfs:subClassOf ex:Mammal>
    <3: ex:Fido rdf:type ex:Dog>
    <4: ex:Fido ex:has-owner ex:John>
    <5: ex:Company rdf:type owl:Class>
    <6: ex:CommercialCompany rdfs:subClassOf ex:Company>
    <7: ex:Franz rdf:type owl:CommercialCompany>
    <8: ex:John ex:works-at ex:Franz>
    <9: ex:Franz ex:has-product ex:Agraph>

Note that the order of the triples returned from get-triples-list is unspecified so you may see a different result order. Developers desiring to see the entire triple URI can set the keyword :format to :long or :ntriples.

    > (print-triple tr :format :long)
    <http://franz.com/things#Fido> <http://franz.com/things#has-owner> <http://franz.com/things#John> .
    <Fido has-owner John>
    > (print-triple tr :format :ntriple)
    <http://franz.com/things#Fido> <http://franz.com/things#has-owner> <http://franz.com/things#John> .
    <Fido has-owner John>

### Printing nodes again

When developing, it is sometimes useful to print everything related to a particular node, for n levels deep. pprint-subject and pprint-object will do that for you.

    > (pprint-subject !ex:Fido :format :concise)
    ex:Fido rdf:type ex:Dog
    ex:Fido ex:has-owner ex:John

    > (pprint-subject !ex:Fido :maximum-depth 3 :format :concise)
    ex:Fido rdf:type ex:Dog
       ex:Dog rdfs:subClassOf ex:Mammal
          ex:Mammal rdf:type owl:Class
    ex:Fido ex:has-owner ex:John
       ex:John ex:works-at ex:Franz
          ex:Franz ex:has-product ex:Agraph
          ex:Franz rdf:type owl:CommercialCompany

    > (pprint-object !ex:Mammal :maximum-depth 2 :format :concise)
    ex:Dog rdfs:subClassOf ex:Mammal
       ex:Fido rdf:type ex:Dog

## Querying for triples

Getting the triples back is easy. The function get-triples-list can return all the triples in the triple-store; so don't issue it casually with a large triple-store. Variations of `get-triples-list`, described later, allow you to select a specific portion of the triples in the triple-store. The following generates a list with all the triples in the triple-store.

    > (enable-print-decoded nil)
    nil
    > (get-triples-list :limit nil)
    (#(58 199 69 20 59 219 255 76 6 52 ...)
     #(95 10 54 142 106 57 232 84 206 188 ...)
     #(78 134 60 220 246 40 208 148 75 219 ...)
     #(78 134 60 220 246 40 208 148 75 219 ...)
     #(224 55 238 14 54 24 123 47 0 107 ...)
     #(119 170 85 50 93 233 51 22 180 89 ...)
     #(140 251 141 206 154 143 61 27 140 58 ...)
     #(202 224 162 157 147 62 130 139 128 204 ...)
     #(140 251 141 206 154 143 61 27 140 58 ...))

get-triples-list will take any combination of s, p, o, and g (nil is used as a wildcard and means to return all possible values for the target). The function print-triples lets you print out a list of triples more easily. Like print-triple, it takes a format keyword argument that controls whether the output is in :concise, :long or :ntriple format.

    > (print-triples (get-triples-list :o !ex:John) :format :concise)
    <4: ex:Fido ex:has-owner ex:John>

    > (print-triples (get-triples-list :s !ex:Franz :p !rdf:type) :format :concise)
    <7: ex:Franz rdf:type owl:CommercialCompany>

    > (print-triples (get-triples-list :s !ex:John) :format :concise)
    <8: ex:John ex:works-at ex:Franz>

### A cursor version

get-triples-list is built on the cursor based query function get-triples. When you call `get-triples`, the first return value will be a cursor that you can use to iterate over the results.

    > (get-triples :s !ex:Franz)
    #<db.agraph::storage-layer-cursor <{Franz}---------> @ #x10042410d2>

Here is how we might implement a variant of `get-triples-list` that uses optional arguments instead of keyword ones:

    (defun my-get-triples-list (&optional s p o g)
      (loop with cursor = (get-triples :s s :p p :o o :g g)
         while (cursor-next cursor) collect
         (copy-triple (cursor-row cursor))))

Note the use of copy-triple. The cursor reuses the same vector over and over again; if you don't make a copy, you'll probably be surprised at the results!

### Loading triples from a file

We support many formats for reading and serializing data. These include N-Triples, Turtle, TriX, and RDF/XML. Here, we load the wine ontology in N-Triples format (In the following example, you will need to provide an appropriate path to the N-Ttriples file you want to load.)

    > (load-ntriples "/home/fred/Download/wilburwine.ntriples")
    2012
    {G}

This reads the file, creates triples, and then returns the total number of triples created. The second return value is the graph into which the triples were loaded. Since we didn't specify, AllegroGraph has put the triples into the `default graph` which it represents using ` `. Note, instead of load-ntriples you also could have used load-rdf/xml on the file wilburwine.rdf. You can see the total number of triples in the store using the triple-count function.

    > (triple-count)
    2012

    > (get-triples-list :limit 50)
    (<wine type Ontology> <wine comment An example OWL ontology>
     <wine type Ontology> <wine priorVersion wine> <wine imports food>
     <wine comment Derived from the DAML Wine ontology at        http://ontolingua.stanford.edu/doc/chimaera/ontologies/wines.daml       Substantially changed, in particular the Region based relations.     >
     <wine label Wine Ontology> <Wine type Class>
     <Wine subClassOf PotableLiquid> <_anon:1 type Restriction>
     <_anon:1 onProperty hasMaker> <_anon:1 cardinality 1>
     <Wine subClassOf _anon:1> <_anon:2 type Restriction>
     <_anon:2 onProperty hasMaker> <_anon:2 allValuesFrom Winery>
     <Wine subClassOf _anon:2> <_anon:3 type Restriction>
     <_anon:3 onProperty madeFromGrape> <_anon:3 minCardinality 1>
     <Wine subClassOf _anon:3> <_anon:4 type Restriction>
     <_anon:4 onProperty hasSugar> <_anon:4 cardinality 1>
     <Wine subClassOf _anon:4> <_anon:5 type Restriction>
     <_anon:5 onProperty hasFlavor> <_anon:5 cardinality 1>
     <Wine subClassOf _anon:5> <_anon:6 type Restriction>
     <_anon:6 onProperty hasBody> <_anon:6 cardinality 1>
     <Wine subClassOf _anon:6> <_anon:7 type Restriction>
     <_anon:7 onProperty hasColor> <_anon:7 cardinality 1>
     <Wine subClassOf _anon:7> <_anon:8 type Restriction>
     <_anon:8 onProperty locatedIn> <_anon:8 someValuesFrom Region>
     <Wine subClassOf _anon:8> <Wine label wine> <Wine label vin>
     <Vintage type Class> <_anon:9 type Restriction>
     <_anon:9 onProperty hasVintageYear> <_anon:9 cardinality 1>
     <Vintage subClassOf _anon:9> <WineGrape type Class>
     <WineGrape subClassOf Grape>)
    #<db.agraph::storage-layer-cursor <------------> @ #x10043b60e2>
    > (length *)
    50

Only 50 triples appear in the result list because that is the limit we specified in the call to get-triples-list.

Before we make any other changes, we'll commit what we've done so far with commit-triple-store:

    > (commit-triple-store)
    t

Now lets find information on one node. We first register a namespace to save us some typing

    > (register-namespace
       "guide" "http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#")

    > (part->string !guide:Wine)
    "<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#Wine>"

    > (get-triples-list :s !guide:Wine)
    (<8: guide:Wine rdf:type owl:Class>
     <9: guide:Wine rdfs:subClassOf PotableLiquid>
     <13: guide:Wine rdfs:subClassOf _anon:1>
     ...)

How many did we find?

    > (length *)
    43

Now let us register another namespace,

    > (register-namespace "ex" "http://franz.com/things#"
       :errorp nil)
    "http://franz.com/things#"

and make the highly subjective statement that "Wine better-than beer".

    > (add-triple !guide:Wine !ex:better-than !ex:beer)
    2013

and now there are more triples with the subject "Wine" (case matters!):

    > (count-cursor (get-triples :s !guide:Wine))
    44

## Deleting triples

AllegroGraph also supports deleting triples. The function delete-triples takes an spog pattern and will delete every triple that matches the pattern. So the following will delete every triple that starts with !guide:Wine and ends with !ex:beer. (by the way, the function takes either strings, UPIs or future-parts). First, commit:

    > (commit-triple-store)
    t

and then delete:

    > (delete-triples :s !guide:Wine :o !ex:beer)
    1

It returns the number of triples deleted. We can use rollback-triple-store to get the deleted-triple-back:

    > (triple-count)
    2012

    > (rollback-triple-store)
    t

    > (triple-count)
    2013

## Using Prolog (without the triple-store)

Prolog is a very convenient interface to the triple-store. If you are not familiar with it, please take a look at the Prolog tutorial included in the AllegroGraph distribution and at Franz's technical reference to Prolog in Allegro Common Lisp.

### Using Prolog with the triple-store

The tutorial linked above provides a minimal introduction to Prolog. Now we will tie Prolog to AllegroGraph. Below are some basic operations. If your triple-store is still open, please close it first:

    > (close-triple-store)
    nil

Now do the following again:

    > (create-triple-store "ag-test")
    #<db.agraph::triple-db ag-test, 0, open @ #x1003c16792>

    > (load-ntriples "sys:agraph;tutorial-files;wilburwine.ntriples")
    2012
    {default-graph}

    > (get-triples-list :p !rdfs:subClassOf)
    (<9: guide:Wine rdfs:subClassOf PotableLiquid>
     <13: guide:Wine rdfs:subClassOf _anon:1>
     <17: guide:Wine rdfs:subClassOf _anon:2>
     <21: guide:Wine rdfs:subClassOf _anon:3> ...)

    > (register-namespace "ex" "http://franz.com/things#"
       :errorp nil)
    "http://franz.com/things#"

    > (register-namespace "guide"
           "http://www.w3.org/TR/2003/WD-owl-guide-20030331/"
           :errorp nil)
    "http://www.w3.org/TR/2003/WD-owl-guide-20030331/"

(Notice that we used the `:errorp` parameter to `register-namespace` to make certain that it would not complain if we were changing a namespace mapping.)

    > (add-triple !guide:wine !ex:better-than !ex:beer)
    2013

    > (let ((bn (new-blank-node)))
       (add-triple
         bn !rdf:statementAbout
         (value->upi (add-triple !guide:wine !ex:better-than !ex:beer)
                     :triple-id))
         (add-triple bn !rdf:source !ex:Jans)
         (add-triple bn !rdf:content !ex:Nonsense))
    2017

The main interface to prolog is the function q-. Let's try it out by asking for every possible binding for subject, predicate and object:

    > (?- (q- ?x ?y ?z))
    ?x = {wine}
    ?y = {rdf:type}
    ?z = {owl:Ontology}

    ?x = {wine}
    ?y = {rdfs:comment}
    ?z = {"An example OWL ontology"}.

    ;; type #\. (period) to tell Prolog to stop
    No.
    ...

This will get boring pretty quickly, you can stop it by typing a period (' . '). Let's try again with one argument to `q-` that is bound. This will find all the direct `subClassOf` relations in the triple-store. 3

    > (?- (q- ?x !rdfs:subClassOf ?y))
    ?x = {guide:Wine}
    ?y = {PotableLiquid}

    ?x = {guide:Wine}
    ?y = {_anon:1}.

    No.

Again, stop it by typing a period (' . ').

So what did Jans think is nonsense (at the pause press Enter)?

    > (?- (q- ?st !rdf:statementAbout ?id)
          (q- ?st !rdf:source !ex:Jans)
          (q- ?st !rdf:content !ex:Nonsense)
          (lisp (print-triple
                (get-triple-by-id (upi->value ?id))
                :format :concise)))

    <triple 2015: guide:wine ex:better-than ex:beer default-graph>
    ?st = {_anon:461}
    ?id = {2015}

    No.

When you get this tutorial you also get the file "kennedy-family.cl". When you complete the current tutorial, you can evaluate the forms in "kennedy-family.cl" to learn more about how Prolog interfaces to the triple-store. Do not load and compile this file all at once but execute it from top to bottom one form at a time so that you can view the output from each form interactively.

### Using the select macro as a wrapper around Prolog

When you make a Prolog query you often are not interested in 12-byte numeric UPI vectors but you instead want to see actual string values. Because it is tedious to write `(lisp (print (part->string ?x)))` repeatedly, there is a simple convenience wrapper around Prolog called select.

Here is how you use it (make sure that you have the wine triple-store open before evaluating the next form). 4

    > (select (?x ?y ?z)
        (q- ?x !rdfs:subClassOf ?y)
        (q- ?y !rdfs:subClassOf ?z))
    (("<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#DessertWine>"
      "<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#Wine>"
      "<http://www.w3.org/TR/2003/CR-owl-guide-20030818/food#PotableLiquid>")
     ("<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#DessertWine>"
      "<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#Wine>" "_:blank33")
     ("<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#DessertWine>"
      "<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#Wine>" "_:blank44")
     ("<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#DessertWine>"
      "<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#Wine>" "_:blank51")
     ("<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#DessertWine>"
      "<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#Wine>" "_:blank58")
     ("<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#DessertWine>"
      "<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#Wine>" "_:blank64")
     ("<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#DessertWine>"
      "<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#Wine>" "_:blank70")
     ("<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#DessertWine>"
      "<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#Wine>" "_:blank76")
     ("<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#DessertWine>"
      "<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#Wine>" "_:blank82")
     ("<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#LateHarvest>"
      "<http://www.w3.org/TR/2003/CR-owl-guide-20030818/wine#Wine>"
      "<http://www.w3.org/TR/2003/CR-owl-guide-20030818/food#PotableLiquid>")
     ...)

## In conclusion

This tutorial has introduced the simplest AllegroGraph operations:

- creating triple stores
- the !-reader
- adding triples one at a time using add-triple or in bulk with load-ntriples
- querying with get-triples and get-triples-list
- printing triples with print-triple, print-triples, pprint-subject and pprint-object.
- triple deletion
- Prolog and select

To continue, see the other tutorials (linked in the navigation bar at the top of this page) and the AllegroGraph Learning Center.

## Footnotes

1. It is printed readably because enable-print-decoded has been set to true; a little further along in the tutorial, we will show you what happens if `enable-print-decoded` is nil ↩
2. I.e., that the string it represents is already interned in the triple-store's string dictionary. ↩
3. The q- functor queries the triple-store's inner-triple-store and therefore will not, in general, perform reasoning. If the triple-store is a reasoning-triple-store, then the q functor can be used to also gather inferred triples. ↩
4. Remember that `select` is a macro and that using it in the REPL will produce interpreted code. This means that selects run in the REPL will be significantly slower than those that you write inside compiled functions. Both the HTTP and the Java interfaces to AllegroGraph ensure that any select calls get compiled before they run. Whether compiled queries execute significantly faster depends on whether the generated code performs a lot of backtracking or other repeated computation. ↩