hyper.dev

2019/07/07 - SPARQL to Scheme Generic Tuple Store (nstore)

SPARQL is Resource Description Framework (RDF) query langauge. It allows to query triple stores and quad stores (called named graph).

Scheme Generic Tuple Store is work-in-progress Scheme Request For Implementation (SRFI) dubbed 168. It embeds a triple store or quad store or set of tuples of n items in Scheme programming language.

It rely on a pattern matching query semantic similar to SPARQL upon which minikanren logic language can be bound.

In the following, I will show how to translate some SPARQL queries into Scheme code.

In what follow we consider the following two stores. A triple store:

(define triplesotre (nstore #vu8(00) '(subject predicate object)))

And a quad store:

(define quadstore (nstore (#vu8 01) '(graph subject predicate object)))

And tx is a transaction object.

Data Types

The supported data types are composition of the follow basic Scheme types:

There is no specific handling of date time objects or URIs.

Simple query

SPARQL

SELECT ?title
WHERE
{
  <http://example.org/book/book1> <http://purl.org/dc/elements/1.1/title> ?title .
}

Scheme

(nstore-query
  (nstore-from tx triplestore
               (list 'http://example.org/book/book1
                     'http://purl.org/dc/elements/1.1/title
                     (nstore-var 'title))))

SPARQL

PREFIX foaf:   <http://xmlns.com/foaf/0.1/>
SELECT ?name ?mbox
WHERE
  { ?x foaf:name ?name .
    ?x foaf:mbox ?mbox }

Scheme

(nstore-query (nstore-from tx triplestore
                           (list (nstore-var 'graph)
                                 'http://xmlns.com/foaf/0.1/name
                                 (nstore-var 'name)))
              (nstore-where tx triplestore
                            (list (nstore-var 'graph)
                                  'http://xmlns.com/foaf/0.1/mbox
                                  (nstore-var 'mbox))))

If you prefer, you can define a procedure in Scheme:

(define (foaf symbol)
  (string->symbol (string-append "http://xmlns.com/foaf/0.1/" (symbol->string symbol))))

And then the query becomes:

(nstore-query (nstore-from tx triplestore
                           (list (nstore-var 'graph)
                                 (foaf 'name)
                                 (nstore-var 'name)))
              (nstore-where tx triplestore
                            (list (nstore-var 'graph)
                                  (foaf 'mbox)
                                  (nstore-var 'mbox))))

FILTER

SPARQL

PREFIX  dc:  <http://purl.org/dc/elements/1.1/>
SELECT  ?title
WHERE   { ?x dc:title ?title
          FILTER regex(?title, "^SPARQL")
        }

Scheme

(gfilter (lambda (binding) (string-prefix? "SPARQL" (hashmap-ref binding 'title)))
  (nstore-query (nstore-from tx triplestore
                             (list (nstore-var 'x)
                                   'http://purl.org/dc/elements/1.1/title
                                   (nstore-var 'title)))))

SPARQL

PREFIX  dc:  <http://purl.org/dc/elements/1.1/>
PREFIX  ns:  <http://example.org/ns#>
SELECT  ?title ?price
WHERE   { ?x ns:price ?price .
          FILTER (?price < 30.5)
          ?x dc:title ?title . }

Scheme

(gfilter (lambda (binding) (< (hashmap-ref binding 'price) 30.5))
  (nstore-query (nstore-from tx triplestore
                             (list (nstore-var 'x)
                                   'http://example.org/ns#price
                                   (nstore-var 'price)))
                (nstore-where tx triplestore
                              (list (nstore-var 'x)
                                    'http://purl.org/dc/elements/1.1/title
                                    (nstore-var 'title)))))

OPTIONAL

SPARQL

PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?name ?mbox
WHERE  { ?x foaf:name  ?name .
         OPTIONAL { ?x  foaf:mbox  ?mbox }
       }

Scheme

JOKER!

UNION

SPARQL

PREFIX dc10:  <http://purl.org/dc/elements/1.0/>
PREFIX dc11:  <http://purl.org/dc/elements/1.1/>

SELECT ?title
WHERE  { { ?book dc10:title  ?title } UNION { ?book dc11:title  ?title } }

Scheme

(gappend
  (nstore-select (nstore-from tx triplestore
                              (list (nstore-var 'book)
                                    'http://purl.org/dc/elements/1.0/title
                                    (nstore-var 'title))))
  (nstore-select (nstore-from tx triplestore
                              (list (nstore-var 'book)
                                    'http://purl.org/dc/elements/1.1/title
                                    (nstore-var 'title)))))

You are not obliged to copy-paste and you can factor queries...

FILTER NOT EXISTS

JOKER

FILTER EXISTS

JOKER

MINUS

JOKER

BIND

Use gmap

GROUP BY

JOKER

HAVING

Use gfilter

Sub-queries

Trivial.

Graph queries

Trivial.

ORDER BY

JOKER

DISTINCT

JOKER

LIMIT ... OFFSET ...

Use gtake and gdrop.