SPARQL Inference – examples

Examples use a small, simple data set loosely based on the examples in "Semantic Web for the Working Ontologist" by Dean Allemang and James Hendler.

Examples assume the following prefixes:

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX prod: <http://example.com/products/>
PREFIX ex: <http://example.com/>

The data is about products in a clothing factory.

These examples can be run from Query Console, in SPARQL Update mode. SPARQL query results are shown here in JSON format, for convenience.

Overview

In this exercise we create a graph and insert triples about some products, one of which is a Henley. At this point, we know that a Henley is a shirt, but the database doesn't – so when we ask about shirts, the Henley isn't included in the results.

Then we set up inferencing. First insert some ontology data (a triple that tells us that Henley is a subclass of Shirts), then create a store (which tells the server how to interpret the ontology data). Then we pass the store into the query, and now the Henley does appear in the results.

Next we tell the server that the store we created should be used by default, so we can run the query without specifying a store.

  1. Set-up: graph and data
  2. Example 1 (SPARQL Update):

    ## reset:
    ## drop the graph used in this exercise
    ## use "SILENT" so it doesn't give an error if the graph doesn't exist
    DROP SILENT GRAPH <http://marklogic.com/semantics/sb/products/inf-1> ;

    Example 2 (SPARQL Update):

    ## create <http://marklogic.com/semantics/sb/products/inf-1>
    CREATE GRAPH <http://marklogic.com/semantics/sb/products/inf-1> ;

    Example 3 (SPARQL Update):

    ## insert some triples into < http://marklogic.com/semantics/sb/products/inf-1>
    ## prod:1001 is a blue Henley
    ## prod:1002 is a blue shirt
    INSERT DATA
    {
      GRAPH <graph-1>
      {
        prod:1001 rdf:type ex:Henley ;
                  ex:color "blue" .
        prod:1002 rdf:type ex:Shirt ;
                  ex:color "blue" .
      }
    }
  3. Find all blue shirts – without inference
  4. Example 1 (SPARQL Query):

    SELECT ?product
    FROM <http://marklogic.com/semantics/sb/products/inf-1>
    WHERE
      {
        ?product rdf:type ex:Shirt ;
        ex:color "blue"
      }
    =>
    [
      {
        "product": "<http://example.com/products/1002>"
      }
    ]
  5. Setup RDFS inferencing – insert some ontology data, create a store, run a query using the store
  6. Example 1 (SPARQL Update):

    ## insert some ontology data into <http://marklogic.com/semantics/sb/products/inf-
    1>
    INSERT DATA
    {
      GRAPH <http://marklogic.com/semantics/sb/products/inf-1>
      {
        ex:Henley rdfs:subClassOf ex:Shirt .
      }
    }
    =>
    Empty

    Example 2 (XQuery):

    (: create a store that uses the RDFS ruleset for inferencing :)
    let $rdfs-store := sem:ruleset-store("rdfs.rules",sem:store() )
    return
      (: use the store you just created - pass it in to sem:sparql() :)
      sem:sparql('
        PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
        PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
        PREFIX prod: <http://example.com/products/>
        PREFIX ex: <http://example.com/>
        SELECT ?product
        FROM <http://marklogic.com/semantics/sb/products/inf-1>
        WHERE
        {
          ?product rdf:type ex:Shirt ;
          ex:color "blue"
        }',
        (),
        (),
        $rdfs-store
      )
    =>
    [
      {
       "product": "<http://example.com/products/1001>"
      },
      {
        "product": "<http://example.com/products/1002>"
      }
    ]
  7. Set some ruleset as default
  8. Example 1 (XQuery):

    import module namespace admin = "http://marklogic.com/xdmp/admin"
      at "/MarkLogic/admin.xqy";
    (:
      Set the default ruleset for the database "Documents" to "rdfs.rules"
      Note: other ways to do this:
      * in the Admin UI, click on database "Documents”, scroll down to "default 
        rulesets" on the left-hand side
      * use the REST management API - see
        [http://localhost:8002]/manage/v2/databases/Documents/properties
    :)
    let $config := admin:get-configuration()
    let $dbid := admin:database-get-id($config, "Documents")
    let $rules := admin:database-ruleset("rdfs.rules")
    let $new-config := admin:database-add-default-ruleset($config, $dbid, $rules)
    return admin:save-configuration($new-config)

    Example 2 (XQuery):

    import module namespace admin = "http://marklogic.com/xdmp/admin"
      at "/MarkLogic/admin.xqy";
    
    (:
      Get the default ruleset(s) for the database "Documents" to verify you’ve set
      the default ruleset correctly.
      Note: other ways to do this:
      * in the Admin UI, click on database "Documents", scroll down to "default 
        rulesets" on the left-hand side
      * use the REST management API - see
        [http://localhost:8002]/manage/v2/databases/Documents/properties
    :)
    let $config := admin:get-configuration()
    let $dbid := admin:database-get-id($config, "Documents")
    let $rules := admin:database-ruleset("rdfs.rules")
    let $db-rulesets := admin:database-get-default-rulesets($config, $dbid)
    return $db-rulesets
    =>
    <ruleset xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
     xmlns="http://marklogic.com/xdmp/database">
      <location>rdfs.rules</location>
    </ruleset>

    Example 3 (SPARQL query):

    ## re-run "find all blue shirts" – uses default ruleset
    SELECT ?product
    FROM <http://marklogic.com/semantics/sb/products/inf-1>
    WHERE
    {
      ?product rdf:type ex:Shirt ;
      ex:color "blue"
    }
    =>
    [
      {
        "product": "<http://example.com/products/1001>"
      },
      {
        "product": "<http://example.com/products/1002>"
      }
    ]
  9. Use more than one ruleset
  10. Example 1 (XQuery):

    import module namespace admin = "http://marklogic.com/xdmp/admin"
      at "/MarkLogic/admin.xqy";
    (:
     Delete all the default rulesets for the database "Documents" before you start
     Note: other ways to do this:
     * in the Admin UI, click on database "Documents", scroll down to "default 
       rulesets" on the left-hand side
     * use the REST management API - see
       [http://localhost:8002]/manage/v2/databases/Documents/properties
    :)
    let $config := admin:get-configuration()
    let $dbid := admin:database-get-id($config, "Documents")
    let $rules := admin:database-ruleset("rdfs.rules")
    let $db-rulesets := admin:database-get-default-rulesets($config, $dbid)
    let $new-config := admin:database-delete-default-ruleset($config, $dbid, $dbrulesets)
    return admin:save-configuration($new-config)

    Example 2 (SPARQL Update):

    ## insert another triple into http://marklogic.com/semantics/sb/products/inf-1
    ## prod:1003 is a Henley that has hue "blue"
    INSERT DATA
    {
      GRAPH <http://marklogic.com/semantics/sb/products/inf-1>
      {
        prod:1003 rdf:type ex:Henley ;
        ex:hue "blue" .
      }
    }

    Example 3 (SPARQL Update):

    ## insert some more ontology data into
    http://marklogic.com/semantics/sb/products/inf-1
    ## the predicate ex:color is equivalent to the predicate ex:hue
    INSERT DATA
    {
      GRAPH <http://marklogic.com/semantics/sb/products/inf-1>
      {
        ex:color owl:equivalentProperty ex:hue .
      }
    }

    Example 4 (XQuery):

    (:
      SPARQL query using 2 rulesets, RDFS and owl:equivalentProperty
      You could also do it this way:
      * set the default rulesets for the database to RDFS and owl:equivalentProperty;
      * query using SPARQL Query from query console or REST endpoint
    :)
    (: create a store that uses the RDFS and owl:equivalentProperty rulesets for
    inferencing :)
    let $rdfs-store :=
      sem:ruleset-store(
        ("rdfs.rules", "equivalentProperty.rules"),
        sem:store()
      )
    return
      (: use the store you just created - pass it into sem:sparql() :)
      sem:sparql('
        PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
        PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
        PREFIX prod: <http://example.com/products/>
        PREFIX ex: <http://example.com/>
        SELECT ?product
        FROM <http://marklogic.com/semantics/sb/products/inf-1>
        WHERE
        {
          ?product rdf:type ex:Shirt ;
          ex:color "blue"
        }',
        (),
        (),
        $rdfs-store
      )
     =>
    [
      {
        "product": "<http://example.com/products/1001>"
      },
      {
        "product": "<http://example.com/products/1002>"
      },
      {
        "product": "<http://example.com/products/1003>"
      }
    ]
  11. Define your own ruleset
  12. This example draws from the geonames ontology and data sets – see http://www.geonames.org/ontology/documentation.html.

    Example 1 (SPARQL Update):

    ## drop the customers graph
    DROP SILENT GRAPH <http://marklogic.com/semantics/sb/customers/inf-1> ;

    Example 2 (SPARQL Update):

    ## create the customers graph
    CREATE GRAPH <http://marklogic.com/semantics/sb/customers/inf-1> ;

    Example 3 (SPARQL Update):

    ## insert some triples from geonames
    ## * "Greater London" has parentFeature "England"
    PREFIX gn: <http://www.geonames.org/ontology#>
    PREFIX owl: <http://www.w3.org/2002/07/owl#>
    PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
    INSERT DATA
    {
      GRAPH <http://marklogic.com/semantics/sb/customers/inf-1> {
        <http://sws.geonames.org/2648110/> rdfs:isA gn:Feature ;
          rdfs:isDefinedBy <http://sws.geonames.org/2648110/about.rdf> ;
          gn:name "Greater London" ;
          gn:parentFeature <http://sws.geonames.org/6269131/> .
      
        <http://sws.geonames.org/6269131/> rdfs:isA gn:Feature ;
          rdfs:isDefinedBy <http://sws.geonames.org/2648110/about.rdf> ;
          gn:name "England" ;
          gn:parentFeature <http://sws.geonames.org/6269131/> .
      }
    }

    Example 4 (SPARQL Query):

    ## check that the inserts into the customer graph worked
    SELECT * FROM <http://marklogic.com/semantics/sb/customers/inf-1>
    WHERE { ?s ?p ?o }
    ORDER BY ?s

    Example 5 (XQuery):

    (: create a rules file and insert it into the Schemas database :)
    (: Note: run this from Query Console with "Content Source" set to "Schemas" :)
    xdmp:document-insert(
     '/rules/livesin.rules',
     text {
      '# my rules for inference
        prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
        prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
        prefix ex: <http://example.com/>
        prefix gn: <http://www.geonames.org/ontology#>
        rule "lives in" construct {
          ?person ex:livesIn ?place2
        } {
          ?person ex:livesIn ?place1 .
          ?place1 gn:parentFeature ?place2
        }'
      }
    )

    Example 6 (SPARQL Query):

    ## find places that John Smith lives in – without inferencing
    PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
    PREFIX gn: <http://www.geonames.org/ontology#>
    PREFIX ex: <http://example.com/>
    SELECT ?person ?placeName
    FROM <http://marklogic.com/semantics/sb/customers/inf-1>
    WHERE
    {
      ?person ex:livesIn ?place .
      ?place gn:name ?placeName
    }
    =>
    <http://marklogic.com/semantics/sb/customers/inf-1#JohnSmith> "Greater London"

    Example 7 (XQuery):

    (: find places that John Smith lives in – with inferencing, using my ruleset :)
    (: MarkLogic will look in the Config directory AND Schemas database for the named
    ruleset :)
    let $my-store := sem:ruleset-store("/rules/livesin.rules",sem:store() )
    return
      (: use the store you just created - pass it in to sem:sparql() :)
      sem:sparql('
        PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
        PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
        PREFIX gn: <http://www.geonames.org/ontology#>
        PREFIX ex: <http://example.com/>
        SELECT ?person ?placeName
        FROM <http://marklogic.com/semantics/sb/customers/inf-1>
        WHERE
        {
          ?person ex:livesIn ?place .
          ?place gn:name ?placeName
        }
        ORDER BY ?person',
        (),
        (),
        $my-store
      )
    =>
    <http://marklogic.com/semantics/sb/customers/inf-1#JohnSmith> "Greater London"
    <http://marklogic.com/semantics/sb/customers/inf-1#JohnSmith> "England"

    Note: In MarkLogic 8 you can set the default ruleset for inferencing, so in Query Console you can run a SPARQL Query (not an XQuery) that makes use of inferencing. You can also run SPARQL over REST – using the SPARQL endpoint – and you’ll get automatic inferencing by way of the database’s default ruleset.

    Example 8 (JavaScript):

    // call sem.sparql from Server-side JavaScript
    var myStore = sem.rulesetStore("/rules/livesin.rules",sem.store() )
    var query = " \
    PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> \
    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \
    PREFIX gn: <http://www.geonames.org/ontology#> \
    PREFIX ex: <http://example.com/> \
     \
    SELECT ?person ?placeName \
    FROM <http://marklogic.com/semantics/sb/customers/inf-1> \
    WHERE \
    { \
      ?person ex:livesIn ?place . \
      ?place gn:name ?placeName \
    }"
    
    sem.sparql(
      query,
      [],
      [],
      myStore
    )
    =>
    <http://marklogic.com/semantics/sb/customers/inf-1#JohnSmith> "Greater London"
    <http://marklogic.com/semantics/sb/customers/inf-1#JohnSmith> "England"

Stack Overflow iconStack Overflow: Get the most useful answers to questions from the MarkLogic community, or ask your own question.