如何使用 TDB 和 reasoner 配置 Apache Jena Fuseki?删除数据集时出错

How to configure Apache Jena Fuseki with TDB and reasoner ? Error on DELETE dataset

上下文

尽管关于该主题的 questions/answers 数量,我仍然无法配置 Apache Jena Fuseki...

我正在尝试配置 Apache Jena Fuseki 实例并激活 TDB 和 OWL 推理器,以测试我的应用程序。我需要创建数据集、执行测试并以编程方式删除数据集。

设置

我使用 stain/jena-fuseki docker 图像到 运行 Apache Jena Fuseki。

I 运行 Jena Fuseki 版本 3.10.0.

bash-4.3# ./fuseki-server -version
Jena:       VERSION: 3.10.0
Jena:       BUILD_DATE: 2018-12-30T15:45:57+0000
TDB:        VERSION: 3.10.0
TDB:        BUILD_DATE: 2018-12-30T15:45:57+0000
Fuseki:     VERSION: 3.10.0
Fuseki:     BUILD_DATE: 2018-12-30T15:45:57+0000

基本配置

我使用以下 shiro.ini 文件。 我允许所有人完全访问这只是一个测试实例。

bash-4.3# cat /fuseki/shiro.ini 

[main]
# Development
ssl.enabled = false
plainMatcher=org.apache.shiro.authc.credential.SimpleCredentialsMatcher
iniRealm.credentialsMatcher = $plainMatcher

[users]
admin=mysupersecurepassword

[roles]

[urls]
## Control functions open to anyone
/$/status = anon
/$/ping   = anon

# Everything else
/**=anon

我使用默认的config.ttl文件:

bash-4.3# cat /fuseki/config.ttl 
# Licensed under the terms of http://www.apache.org/licenses/LICENSE-2.0
## Fuseki Server configuration 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 ja:      <http://jena.hpl.hp.com/2005/11/Assembler#> .

[] rdf:type fuseki:Server ;
   .

我要做什么?

为了测试我的应用程序,我尝试创建数据集、执行测试并以编程方式删除数据集。为此,我使用 Fuseki HTTP Administration Protocol.

我遵循以下步骤:


第 1 步:

使用卷曲:

curl -F 'files[]=@dataset.ttl' http://localhost:3030/$/datasets

我使用以下 dataset.ttl 文件:

@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 : <#> .


# Custom code
tdb:GraphTDB rdfs:subClassOf ja:Model .

# Setup service
:service rdf:type fuseki:Service ;
    rdfs:label                          "TDB dataset_name" ;
    fuseki:name                         "dataset_name" ;
    fuseki:dataset                      :dataset ;
    fuseki:serviceQuery                 "query", "sparql" ;
    fuseki:serviceUpdate                "update" ;
    fuseki:serviceUpload                "upload" ;
    fuseki:serviceReadWriteGraphStore   "data" ;
    fuseki:serviceReadGraphStore        "get" ;
.

# Setup Assembler model with reasoner
:dataset rdf:type ja:RDFDataset;
    ja:defaultGraph :modelInf ;
.
:modelInf rdf:type ja:InfModel;
    ja:baseModel :tdbGraph ;
    ja:reasoner [ 
        ja:reasonerURL <http://jena.hpl.hp.com/2003/OWLFBRuleReasoner> 
    ] ;
.

# TDB dataset used for RDF storage
:tdbGraph rdf:type tdb:GraphTDB;
    tdb:location "/fuseki/databases/dataset_name" ;
.

Jena Fuseki 日志

[2019-10-23 14:41:00] Admin      INFO  [6] POST http://localhost:3030/$/datasets
[2019-10-23 14:41:00] Admin      INFO  [6] Filename: dataset.ttl, Content-Type=application/octet-stream, Charset=null => Turtle : Count=19 Triples=19 Quads=0
[2019-10-23 14:41:00] Admin      INFO  [6] Create database : name = /dataset_name
[2019-10-23 14:41:02] Admin      INFO  [6] 200 OK (1.894 s)

一切正常:P


第 2 步:

使用卷曲:

curl -F 'files[]=@data.rdf' http://localhost:3030/dataset_name/data
{ 
  "count" : 1524 ,
  "tripleCount" : 1524 ,
  "quadCount" : 0
}

Jena Fuseki 日志

[2019-10-23 14:44:52] Fuseki     INFO  [7] POST http://localhost:3030/dataset_name/data
[2019-10-23 14:44:53] Fuseki     INFO  [7] Filename: data.rdf, Content-Type=application/octet-stream, Charset=null => RDF/XML : Count=1524 Triples=1524 Quads=0
[2019-10-23 14:44:54] Fuseki     INFO  [7] 200 OK (1.858 s)

一切正常:P


第 3 步:

正在测试我的应用程序(此处无用)


第 4 步:

使用卷曲:

curl -d "update=DROP+ALL" -X POST http://localhost:3030/dataset_name/update
...
Update succeeded
...

Jena Fuseki 日志

[2019-10-23 15:04:13] Fuseki     INFO  [67] POST http://localhost:3030/dataset_name/update
[2019-10-23 15:04:14] Fuseki     INFO  [67] 200 OK (268 ms)

一切正常:P


第 5 步:

使用卷曲:

curl -X DELETE http://localhost:3030/$/datasets/dataset_name

Jena Fuseki 日志

[2019-10-23 15:10:17] Admin      INFO  [92] DELETE http://localhost:3030/$/datasets/dataset_name
[2019-10-23 15:10:17] Admin      INFO  [92] DELETE ds=/dataset_name
[2019-10-23 15:10:17] Server     INFO  Shutting down data service for [, data, upload, query, get, update, sparql]
[2019-10-23 15:10:17] Admin      WARN  [92] RC = 500 : Not in a transaction
org.apache.jena.tdb.transaction.TDBTransactionException: Not in a transaction
        at org.apache.jena.tdb.transaction.DatasetGraphTransaction.get(DatasetGraphTransaction.java:140)
        at org.apache.jena.tdb.transaction.DatasetGraphTransaction.getDatasetGraphToQuery(DatasetGraphTransaction.java:86)
        at org.apache.jena.tdb.store.GraphTxnTDB.getDatasetGraphTDB(GraphTxnTDB.java:51)
        at org.apache.jena.tdb.store.GraphTDB.sync(GraphTDB.java:128)
        at org.apache.jena.tdb.store.GraphTDB.close(GraphTDB.java:133)
        at org.apache.jena.reasoner.BaseInfGraph.close(BaseInfGraph.java:445)
        at org.apache.jena.reasoner.rulesys.BasicForwardRuleInfGraph.close(BasicForwardRuleInfGraph.java:360)
        at org.apache.jena.reasoner.rulesys.FBRuleInfGraph.close(FBRuleInfGraph.java:710)
        at org.apache.jena.sparql.core.DatasetGraphMapLink.close(DatasetGraphMapLink.java:199)
        at org.apache.jena.fuseki.server.DataService.expel(DataService.java:223)
        at org.apache.jena.fuseki.server.DataService.shutdown(DataService.java:199)
        at org.apache.jena.fuseki.mgt.ActionDatasets.execDeleteItem(ActionDatasets.java:360)
        at org.apache.jena.fuseki.ctl.ActionContainerItem.execDelete(ActionContainerItem.java:105)
        at org.apache.jena.fuseki.ctl.ActionContainerItem.perform(ActionContainerItem.java:64)
        at org.apache.jena.fuseki.ctl.ActionCtl.executeLifecycle(ActionCtl.java:68)
        at org.apache.jena.fuseki.ctl.ActionCtl.executeAction(ActionCtl.java:62)
        at org.apache.jena.fuseki.ctl.ActionCtl.execCommonWorker(ActionCtl.java:53)
        at org.apache.jena.fuseki.servlets.ActionBase.doCommon(ActionBase.java:74)
        at org.apache.jena.fuseki.ctl.ActionContainerItem.doDelete(ActionContainerItem.java:52)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:713)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
        at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:865)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1655)
        at org.apache.jena.fuseki.servlets.FusekiFilter.doFilter(FusekiFilter.java:101)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
        at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61)
        at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
        at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
        at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
        at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
        at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
        at org.apache.shiro.web.servlet.AbstractShiroFilter.call(AbstractShiroFilter.java:365)
        at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
        at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
        at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
        at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
        at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
        at org.apache.jena.fuseki.servlets.CrossOriginFilter.handle(CrossOriginFilter.java:285)
        at org.apache.jena.fuseki.servlets.CrossOriginFilter.doFilter(CrossOriginFilter.java:248)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1634)
        at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146)
        at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257)
        at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255)
        at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1340)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203)
        at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)
        at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201)
        at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1242)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144)
        at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:690)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
        at org.eclipse.jetty.server.Server.handle(Server.java:503)
        at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:364)
        at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260)
        at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
        at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
        at org.eclipse.jetty.io.ChannelEndPoint.run(ChannelEndPoint.java:118)
        at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765)
        at org.eclipse.jetty.util.thread.QueuedThreadPool.run(QueuedThreadPool.java:683)
        at java.lang.Thread.run(Thread.java:745)
[2019-10-23 15:10:17] Admin      INFO  [92] 500 Not in a transaction (65 ms)

问题来了。任何人都可以帮助解决这个问题?

想法/尝试

我对默认数据集配置文件尝试了相同的过程,没有出现错误。所以我认为这来自数据集配置文件。

这里是我调用的默认数据集配置文件:

@prefix :      <http://base/#> .
@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix tdb2:  <http://jena.apache.org/2016/tdb#> .
@prefix ja:    <http://jena.hpl.hp.com/2005/11/Assembler#> .
@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .
@prefix fuseki: <http://jena.apache.org/fuseki#> .

:service_tdb_all        a                   fuseki:Service ;
        rdfs:label                          "TDB2 dataset_name" ;
        fuseki:dataset                      :tdb_dataset_readwrite ;
        fuseki:name                         "dataset_name" ;
        fuseki:serviceQuery                 "query" , "sparql" ;
        fuseki:serviceReadGraphStore        "get" ;
        fuseki:serviceReadWriteGraphStore   "data" ;
        fuseki:serviceUpdate                "update" ;
        fuseki:serviceUpload                "upload" .

:tdb_dataset_readwrite  a                   tdb2:DatasetTDB2 ;
        tdb2:location                       "/fuseki/databases/dataset_name" .

我没有找到任何关于如何正确配置 Jena Fuseki 的足够清晰的文档。可以找到很多示例,但可以追溯到几年前,不知道它们是否仍然是最新的。并且没有解释它们是如何工作的,所以很难适应特定的情况。

如果有任何文档/教程来解释什么是 "ja:RDFDataset"、"ja:InfModel" 和其他 "ja:things" 以及它们是如何工作的,我们将不胜感激。

我仍然从 ontology/triplestores/linked 数据开始,这些文档不是最容易阅读的:


我尝试了不同的配置示例,但在第 1 步或第 5 步总是出错。

例子

配置:

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

[] rdf:type fuseki:Server ;
    fuseki:services (
        <#service>
    ) .

## ---------------------------------------------------------------
## Service with only SPARQL query on an inference model.
## Inference model base data in TDB.

<#service> rdf:type fuseki:Service ;
    fuseki:name "dataset_name" ;
    fuseki:serviceQuery "query" , "sparql" ;
    fuseki:serviceUpdate "update" ;
    fuseki:serviceUpload "upload" ;
    fuseki:serviceReadWriteGraphStore "data" ;
    fuseki:serviceReadGraphStore "get" ;
    fuseki:dataset <#dataset>  ;
    .

<#dataset> rdf:type ja:RDFDataset ;
    ja:defaultGraph <#model> ;
    . 

<#model> rdf:type ja:InfModel ;
    ja:baseModel <#tdbGraph> ;
    ja:reasoner [
        ja:reasonerURL <http://jena.hpl.hp.com/2003/OWLFBRuleReasoner> ;
    ] ;
    .

<#tdbGraph> rdf:type tdb:GraphTDB ;
    tdb:dataset <#tdbDataset> ;
    .

<#tdbDataset> rdf:type tdb:DatasetTDB ;
    tdb:location "/fuseki/databases/dataset_name" ;
    .

第 1 步出错。

Fuseki 日志:

[2019-10-23 15:20:51] Admin      INFO  [93] POST http://localhost:3030/$/datasets
[2019-10-23 15:20:51] Admin      INFO  [93] Filename: dataset.ttl, Content-Type=text/turtle, Charset=null => Turtle : Count=23 Triples=23 Quads=0
[2019-10-23 15:20:51] Admin      INFO  [93] Create database : name = /dataset_name
[2019-10-23 15:20:51] Admin      WARN  [93] RC = 500 : cannot find a most specific type for :tdbGraph, which has as possibilities: ja:Model tdb:GraphTDB.
org.apache.jena.assembler.exceptions.AmbiguousSpecificTypeException: cannot find a most specific type for :tdbGraph, which has as possibilities: ja:Model tdb:GraphTDB.

完整服务器为通过 UI 或协议使用模板之一创建的数据库提供删除。推送到服务器的任意配置文件无法通过这种方式删除;即使它们可以与服务器断开链接,也可能会留下一些不利于测试的东西(它们是任意的汇编文件)。

对于测试,有一个更简单的方法。为每个测试启动一个服务器,无论是脚本还是来自 Java(JUnit 等)。服务器的 "Fuseki main" 版本启动和停止非常快。因此,启动具有所需配置的服务器 - 如果数据相当小,您可以使用内存中的 TDB 数据库(位置为“--mem--”)存储数据。

这将在服务器退出时完成清理,使测试完全隔离。