I am trying to persist multiple named graphs with inference in Fuseki.
I am referring to this excellent article, but facing some issues in Scenario 2: named graphs and no online updates.
My assembler configuration looks like this:
#prefix : <#> .
#prefix fuseki: <http://jena.apache.org/fuseki#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix tdb: <http://jena.hpl.hp.com/2008/tdb#> .
#prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
## ---------------------------------------------------------------
## Updatable TDB dataset with all services enabled.
:service_tdb_all rdf:type fuseki:Service ;
rdfs:label "TDB onekg-metadata-dev" ;
fuseki:name "onekg-metadata-dev" ;
fuseki:serviceQuery "" ;
fuseki:serviceQuery "sparql" ;
fuseki:serviceQuery "query" ;
fuseki:serviceUpdate "" ;
fuseki:serviceUpdate "update" ;
fuseki:serviceUpload "upload" ;
fuseki:serviceReadWriteGraphStore "data" ;
fuseki:serviceReadGraphStore "get" ;
fuseki:dataset :dataset ;
.
# Location of the TDB dataset
:tdb_dataset_readwrite
a tdb:DatasetTDB ;
tdb:location "reasoning-dir" ;
.
# Inference dataset
:dataset a ja:RDFDataset ;
ja:defaultGraph :model_inf .
# Inference Model
:model_inf a ja:InfModel ;
ja:baseModel :graph ;
ja:reasoner [
ja:reasonerURL
<http://jena.hpl.hp.com/2003/OWLFBRuleReasoner>
] .
# Intermediate graph referencing to the union graph
:graph rdf:type tdb:GraphTDB ;
tdb:dataset :tdb_dataset_readwrite ;
.
I am uploading some triples in a named graph and can query the triples(without inference) as is expected.
However, if I try to restart and try to query again, the named graph is missing and I can not query anything from there.
I would like to get some help here. Thank you in advance.
Related
I am creating a database which encodes directed acyclic graphs (DAGs), where nodes are RDF instances and edges are object properties. Ultimately, I would like to create SPARQL queries which match graph patterns in my set of DAGs. There are many (~200) subtree patterns that I am interested in and would like to somehow store these queries to execute later.
The SPARQL below is a toy example of selecting instances of DAGs having a set of nodes and connections:
SELECT ?dag
WHERE {
?dag :has_node ?n1 ;
:has_node ?n2 ;
:has_node ?n3 .
?n1 rdfs:type :Type1 ;
:parent_of ?n2 .
?n2 rdfs:type :Type2 ;
:parent_of ?n3 .
?n3 rdfs:type :Type3 .
}
Is it possible to store SPARQL queries like the one above as instances in RDF? If so, can I refer to the instance in a SPARQL query and have it translated into SPARQL? (See below)
SELECT ?dag
WHERE {
?dag :has_graph_pattern ?graphPattern .
}
The ?graphPattern variable would be an instance that would encode the same thing as the first SPARQL query.
Thanks for any feedback!
Another way to go would be using the SHACL Advanced Features vocabulary. You could store your ?dag variable as the ?this variable in a shape graph (see the section about SPARQL-Based Targets). You can then store the pattern after a sh:select predicate and use the select query as your pattern for finding your dag.
As suggested in #Roos' answer, I was able to encode my subgraphs in SHACL rules and use them to create triples relating DAGs and subgraphs.
In the example below, there are two DAGs—DAG1 and DAG2—whose nodes can have three possible node labels: A, B, or C. For this example, I want to find DAGs with the C<--B-->C pattern, and then create a new triple linking that DAG with an instance representing this subgraph:
ex:DAG ex:has_subgraph ex:subGraph1
This pattern I'm matching is highlighted in yellow in the image below:
The subgraph pattern can be encoded into a SHACL rule shown below in TTL. Be sure to have sh:declare statements preceding rules, as this may cause issues with the SHACL rule inferencer you use. This is stored in a file called dagShapes.ttl:
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix sh: <http://www.w3.org/ns/shacl#> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
#prefix ex: <http://example.com/ns#> .
ex:
sh:declare [
sh:prefix "ex" ;
sh:namespace "http://example.com/ns#"^^xsd:anyURI ;
] .
ex:DAGSubGraphRule1
a sh:NodeShape ;
sh:targetClass ex:DAG ;
sh:rule [
a sh:SPARQLRule ;
sh:prefixes ex: ;
sh:construct """
CONSTRUCT {
$this ex:has_subgraph ex:subGraph1 .
}
WHERE {
$this ex:has_node ?n1 ;
ex:has_node ?n2 ;
ex:has_node ?n3 .
?n1 a ex:nodeType_B ;
ex:parent_of ?n2 ;
ex:parent_of ?n3 .
?n2 a ex:nodeType_C .
?n3 a ex:nodeType_C .
}
""" ;
] ;
.
The DAGs in this example are encoded in their own file called dagData.ttl like this:
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix sh: <http://www.w3.org/ns/shacl#> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
#prefix ex: <http://example.com/ns#> .
ex:DAG1
a ex:DAG ;
ex:has_node ex:d1_n1 ;
ex:has_node ex:d1_n2 ;
ex:has_node ex:d1_n3 ;
ex:has_node ex:d1_n4 ;
ex:has_node ex:d1_n5 .
ex:d1_n1 a ex:nodeType_A ;
ex:parent_of ex:d1_n2 .
ex:d1_n2 a ex:nodeType_A ;
ex:parent_of ex:d1_n3 .
ex:d1_n3 a ex:nodeType_B ;
ex:parent_of ex:d1_n4 ;
ex:parent_of ex:d1_n5 .
ex:d1_n4 a ex:nodeType_C .
ex:d1_n5 a ex:nodeType_C .
ex:DAG2
a ex:DAG ;
ex:has_node ex:d2_n1 ;
ex:has_node ex:d2_n2 ;
ex:has_node ex:d2_n2 ;
ex:has_node ex:d2_n2 ;
ex:has_node ex:d2_n2 .
ex:d1_n1 a ex:nodeType_A ;
ex:parent_of ex:d1_n2 .
ex:d1_n2 a ex:nodeType_A ;
ex:parent_of ex:d1_n3 .
ex:d1_n3 a ex:nodeType_B ;
ex:parent_of ex:d1_n4 .
ex:d1_n4 a ex:nodeType_C ;
ex:parent_of ex:d1_n5 .
ex:d1_n5 a ex:nodeType_C .
The DAG file and the subgraph shapes file are then passed to a SHACL rule inference tool. The inferencer is run like this in the command line:
shaclinfer -datafile dagData.ttl -shapesfile dagShapes.ttl
The output from the inferencer shows that DAG1 was correctly associated with my subgraph pattern!
#prefix dash: <http://datashapes.org/dash#> .
#prefix ex: <http://example.com/ns#> .
#prefix graphql: <http://datashapes.org/graphql#> .
#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#> .
#prefix sh: <http://www.w3.org/ns/shacl#> .
#prefix swa: <http://topbraid.org/swa#> .
#prefix tosh: <http://topbraid.org/tosh#> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
ex:DAG1 ex:has_subgraph ex:subGraph1 .
It's certainly possible to encode a SPARQL query as OWL-but I'm not sure of anyone that's done it (it would be an involved process). As for pulling it out, definitely. It will be retrieved as a SPARQL Query Result, which you'd have to manually parse to get the full sparql query out.
In short, it's possible to embed a sparql query in an OWL document by first transforming the query to RDF. You can certainly pull the query out, _but processing to reconstruct the original query has to be done in another system (Java, Python, etc). Sounds like a cool topic for a paper, but lots of work around serializing and retrieving the query. Do I recommend it? Not if you're trying to do anything immediate.
I'm working with an OWL Ontology in Protégé 5.1.0 (plus HermiT 1.3.8.413 Reasoner) that I later want to use with OWLAPI 4.1.0 and maybe DL-Query or SPARQL. My task at hand is to get all Individuals of a class that have a certain Object Property unfulfilled. Because of the open-world assumption, an unfulfilled Object Property doesn't usually show up as a problem, but I need the information and would like to avoid writing my own code to check the whole ontology.
I prepared I small example, as readable text and Turtle-code:
Classes: Pizza, Topping
Object Property: has
Assertion: Pizza has some Topping
Individuals: Pizza1, Pizza2, Topping1, Topping2 (of respective Classes)
Assertion: Pizza1 has Topping1
Code:
#prefix : <http://www.semanticweb.org/user/ontologies/2017/0/untitled-ontology-23#> .
#prefix owl: <http://www.w3.org/2002/07/owl#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix xml: <http://www.w3.org/XML/1998/namespace> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#base <http://www.semanticweb.org/user/ontologies/2017/0/untitled-ontology-23> .
<http://www.semanticweb.org/user/ontologies/2017/0/untitled-ontology-23> rdf:type owl:Ontology .
#################################################################
# Object Properties
#################################################################
### http://www.semanticweb.org/user/ontologies/2017/0/untitled-ontology-23#has
:has rdf:type owl:ObjectProperty ;
owl:inverseOf :isOn .
### http://www.semanticweb.org/user/ontologies/2017/0/untitled-ontology-23#isOn
:isOn rdf:type owl:ObjectProperty ,
owl:FunctionalProperty .
#################################################################
# Classes
#################################################################
### http://www.semanticweb.org/user/ontologies/2017/0/untitled-ontology-23#Pizza
:Pizza rdf:type owl:Class ;
rdfs:subClassOf [ rdf:type owl:Restriction ;
owl:onProperty :has ;
owl:someValuesFrom :Topping
] .
### http://www.semanticweb.org/user/ontologies/2017/0/untitled-ontology-23#Topping
:Topping rdf:type owl:Class .
#################################################################
# Individuals
#################################################################
### http://www.semanticweb.org/user/ontologies/2017/0/untitled-ontology-23#Pizza1
:Pizza1 rdf:type owl:NamedIndividual ,
:Pizza ;
:has :Topping1 .
### http://www.semanticweb.org/user/ontologies/2017/0/untitled-ontology-23#Pizza2
:Pizza2 rdf:type owl:NamedIndividual ,
:Pizza .
### http://www.semanticweb.org/user/ontologies/2017/0/untitled-ontology-23#Topping1
:Topping1 rdf:type owl:NamedIndividual ,
:Topping ;
:isOn :Pizza1 .
### http://www.semanticweb.org/user/ontologies/2017/0/untitled-ontology-23#Topping2
:Topping2 rdf:type owl:NamedIndividual ,
:Topping .
#################################################################
# General axioms
#################################################################
[ rdf:type owl:AllDifferent ;
owl:distinctMembers ( :Pizza1
:Pizza2
)
] .
[ rdf:type owl:AllDifferent ;
owl:distinctMembers ( :Topping1
:Topping2
)
] .
### Generated by the OWL API (version 4.2.6.20160910-2108) https://github.com/owlcs/owlapi
In this case, I would like to query the ontology and get the information that Pizza2 currently doesn't have any Topping, i.e. its Object Property is not asserted or inferred. Also, if Topping1 is changed to be of a different class, I now want to see Pizza1 show up in the query as well because "Pizza has some Topping" is unsatisfied.
Is there an elegant way to do this either directly in OWLAPI or using DL-Query/SPARQL?
I am trying to setup a reasoner for Apache Jena.
But I cannot get it working.
When I have a skos concept with skos:broader, I cannot query that concept by searching in the result by skos:narrower
Currently my config.ttl looks like see below.
Do I need to load the schema for skos in the configuration to make this work?
## Licensed under the terms of http://www.apache.org/licenses/LICENSE-2.0
#prefix : <#> .
#prefix fuseki: <http://jena.apache.org/fuseki#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix tdb: <http://jena.hpl.hp.com/2008/tdb#> .
#prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
## ---------------------------------------------------------------
## Service with only SPARQL query on an inference model.
## Inference model base data is in TDB.
<#service2> rdf:type fuseki:Service ;
rdfs:label "skos" ;
fuseki:name "skos" ;
fuseki:serviceQuery "sparql" ; # SPARQL query service
fuseki:serviceUpdate "update" ;
fuseki:dataset <#dataset> ;
.
<#dataset> rdf:type ja:RDFDataset ;
ja:defaultGraph <#model_inf> ;
.
<#model_inf> a ja:InfModel ;
ja:baseModel <#tdbGraph> ;
ja:reasoner [
ja:reasonerURL <http://jena.hpl.hp.com/2003/RDFSExptRuleReasoner>
] .
## Base data in TDB.
<#tdbDataset> rdf:type tdb:DatasetTDB ;
tdb:location "run/databases/skos" ;
# If the unionDefaultGraph is used, then the "update" service should be removed.
# tdb:unionDefaultGraph true ;
.
<#tdbGraph> rdf:type tdb:GraphTDB ;
tdb:dataset <#tdbDataset> .
My data would look something like this.
I would expect the example.com/1 to have example.com/2 as narrower as it is the inverse of broader.
<http://example.com/2>
a skos:Concept ;
skos:broader <http://example.com/1> ;
skos:prefLabel "schaapskooi"#nl .
<http://example.com/1>
a skos:Concept ;
skos:prefLabel "restant landschapstermen"#nl ;
I've recently started playing with the full text search in the Fuseki 0.2.8 snapshot.
I have an InfModel backed by a TDB dataset, which I've added a Lucene text index to. I have tested it out with some search queries like this:
prefix text: <http://jena.apache.org/text#>
select distinct ?s where { ?s text:query ('stu' 16) }
This works great, until I have two or more simultaneous queries to Fuseki, then occasionally I get:
Error 500: Currently in a locked region Fuseki - version 0.2.8-SNAPSHOT (Build date: 20130820-0755).
I've tried testing out the endpoint with 10 concurrent users sending queries at random intervals, over a two minute period around 30% of the queries return the 500 error above.
I have also tried disabling inference by replacing this section (full assembler file below):
<#dataset_fulltext> rdf:type text:TextDataset ;
text:dataset <#dataset_inf> ;
##text:dataset <#tdbDataset> ;
text:index <#indexLucene> .
with this:
<#dataset_fulltext> rdf:type text:TextDataset ;
##text:dataset <#dataset_inf> ;
text:dataset <#tdbDataset> ;
text:index <#indexLucene> .
and there are no exceptions generated when the TextDataset is using #tdbDataset rather than #dataset_inf.
Are there any problems with my set up, or is this a bug in Fuseki?
Here is my current assembler file:
#prefix : <#> .
#prefix fuseki: <http://jena.apache.org/fuseki#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix tdb: <http://jena.hpl.hp.com/2008/tdb#> .
#prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
#prefix text: <http://jena.apache.org/text#> .
#prefix dc: <http://purl.org/dc/terms/> .
[] rdf:type fuseki:Server ;
# Timeout - server-wide default: milliseconds.
# Format 1: "1000" -- 1 second timeout
# Format 2: "10000,60000" -- 10s timeout to first result, then 60s timeout to for rest of query.
# See java doc for ARQ.queryTimeout
ja:context [ ja:cxtName "arq:queryTimeout" ; ja:cxtValue "12000,50000" ] ;
fuseki:services (
<#service1>
) .
# Custom code.
[] ja:loadClass "com.hp.hpl.jena.tdb.TDB" .
# TDB
tdb:DatasetTDB rdfs:subClassOf ja:RDFDataset .
tdb:GraphTDB rdfs:subClassOf ja:Model .
## Initialize text query
[] ja:loadClass "org.apache.jena.query.text.TextQuery" .
# A TextDataset is a regular dataset with a text index.
text:TextDataset rdfs:subClassOf ja:RDFDataset .
# Lucene index
text:TextIndexLucene rdfs:subClassOf text:TextIndex .
## ---------------------------------------------------------------
## Service with only SPARQL query on an inference model.
## Inference model bbase data in TDB.
<#service1> rdf:type fuseki:Service ;
rdfs:label "TDB/text service" ;
fuseki:name "dataset" ; # http://host/dataset
fuseki:serviceQuery "query" ;
fuseki:serviceUpdate "update" ;
fuseki:serviceUpload "upload" ;
fuseki:serviceReadWriteGraphStore "data" ;
fuseki:serviceReadGraphStore "get" ;
fuseki:dataset <#dataset_fulltext> ;
.
<#dataset_inf> rdf:type ja:RDFDataset ;
ja:defaultGraph <#model_inf> .
<#model_inf> rdf:type ja:Model ;
ja:baseModel <#tdbGraph> ;
ja:reasoner [ ja:reasonerURL <http://jena.hpl.hp.com/2003/OWLMicroFBRuleReasoner> ] .
<#tdbDataset> rdf:type tdb:DatasetTDB ;
tdb:location "Data" .
<#tdbGraph> rdf:type tdb:GraphTDB ;
tdb:dataset <#tdbDataset> .
# Dataset with full text index.
<#dataset_fulltext> rdf:type text:TextDataset ;
text:dataset <#dataset_inf> ;
##text:dataset <#tdbDataset> ;
text:index <#indexLucene> .
# Text index description
<#indexLucene> a text:TextIndexLucene ;
text:directory <file:Lucene> ;
##text:directory "mem" ;
text:entityMap <#entMap> ;
.
# Mapping in the index
# URI stored in field "uri"
# rdfs:label is mapped to field "text"
<#entMap> a text:EntityMap ;
text:entityField "uri" ;
text:defaultField "text" ;
text:map (
[ text:field "text" ; text:predicate dc:title ]
[ text:field "text" ; text:predicate dc:description ]
) .
And here is the full stack trace for one of the exceptions in Fuseki's log:
16:27:01 WARN Fuseki :: [2484] RC = 500 : Currently in a locked region
com.hp.hpl.jena.sparql.core.DatasetGraphWithLock$JenaLockException: Currently in a locked region
at com.hp.hpl.jena.sparql.core.DatasetGraphWithLock.checkNotActive(DatasetGraphWithLock.java:72)
at com.hp.hpl.jena.sparql.core.DatasetGraphTrackActive.begin(DatasetGraphTrackActive.java:44)
at org.apache.jena.query.text.DatasetGraphText.begin(DatasetGraphText.java:102)
at org.apache.jena.fuseki.servlets.HttpAction.beginRead(HttpAction.java:117)
at org.apache.jena.fuseki.servlets.SPARQL_Query.execute(SPARQL_Query.java:236)
at org.apache.jena.fuseki.servlets.SPARQL_Query.executeWithParameter(SPARQL_Query.java:195)
at org.apache.jena.fuseki.servlets.SPARQL_Query.perform(SPARQL_Query.java:80)
at org.apache.jena.fuseki.servlets.SPARQL_ServletBase.executeLifecycle(SPARQL_ServletBase.java:185)
at org.apache.jena.fuseki.servlets.SPARQL_ServletBase.executeAction(SPARQL_ServletBase.java:166)
at org.apache.jena.fuseki.servlets.SPARQL_ServletBase.execCommonWorker(SPARQL_ServletBase.java:154)
at org.apache.jena.fuseki.servlets.SPARQL_ServletBase.doCommon(SPARQL_ServletBase.java:73)
at org.apache.jena.fuseki.servlets.SPARQL_Query.doGet(SPARQL_Query.java:61)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:735)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:684)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1448)
at org.eclipse.jetty.servlets.UserAgentFilter.doFilter(UserAgentFilter.java:82)
at org.eclipse.jetty.servlets.GzipFilter.doFilter(GzipFilter.java:294)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1419)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:455)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:229)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1075)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:384)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1009)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
at org.eclipse.jetty.server.Server.handle(Server.java:370)
at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:489)
at org.eclipse.jetty.server.BlockingHttpConnection.handleRequest(BlockingHttpConnection.java:53)
at org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:949)
at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:1011)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:644)
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235)
at org.eclipse.jetty.server.BlockingHttpConnection.handle(BlockingHttpConnection.java:72)
at org.eclipse.jetty.server.nio.BlockingChannelConnector$BlockingChannelEndPoint.run(BlockingChannelConnector.java:298)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
at java.lang.Thread.run(Thread.java:722)
Any advice appreciated.
Thanks,
Stuart.
This looks like it is probably a bug which I have filed as JENA-522, if you have further details on the bug to add please add a comment there.
The issue is that the dataset with inference implicitly uses ARQ's standard in-memory Dataset implementation and this does not support transactions.
However text datasets which correspond to DatasetGraphText internally (and in your stack trace) requires the wrapped dataset to support transactions and where they do not wraps them with DatasetGraphWithLock. It is this that appears to be encountering the problem with the lock, the documentation states that this should support multiple readers but having followed the logic of the code I'm not sure that it actually allows this.
I want to configure Fuseki with an inference model supported by TDB.
I have been able to configure it with a Memory Model, but not with a TDB Model where I could update triples.
I am using the following assembler description:
#prefix tdb: <http://jena.hpl.hp.com/2008/tdb#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
#prefix tdb: <http://jena.hpl.hp.com/2008/tdb#> .
[] ja:loadClass "com.hp.hpl.jena.tdb.TDB" .
tdb:DatasetTDB rdfs:subClassOf ja:RDFDataset .
tdb:GraphTDB rdfs:subClassOf ja:Model .
<#dataset> rdf:type ja:RDFDataset ;
ja:defaultGraph <#infModel> .
<#infModel> a ja:InfModel ;
ja:baseModel <#tdbGraph>;
ja:reasoner
[ja:reasonerURL <http://jena.hpl.hp.com/2003/RDFSExptRuleReasoner>].
<#tdbGraph> rdf:type tdb:GraphTDB ;
tdb:location "DB" ;
.
It works fine and it is able to do RDFS inference and even to insert new triples.
However, once I stop and restart the server, it raises the following exception:
Error 500: Invalid id node for subject (null node): ([000000000000001D], [00000000000000AF], [000000000000003D])
<#tdbGraph> rdf:type tdb:GraphTDB ;
tdb:location "DB" ;
.
Get rid of the semi colon after the second statement and terminate with the full stop ie:
<#tdbGraph> rdf:type tdb:GraphTDB ;
tdb:location "DB".