我如何 "nest" 对象与 OpenRDF Alibaba 分配资源 IRI?
How can I "nest" objects with OpenRDF Alibaba with assigned resource IRIs?
我正在尝试 OpenRDF Alibaba (associated with Sesame) 作为将 Java 对象映射到 RDF 三元组并返回的工具。目前,我正在研究它如何处理对象图。
我有两个对象,内部和外部。 Outer 引用了 Inner。当我持久化一个外部实例时,似乎内部实例被表示为 b 节点,即使我之前已经使用分配的 IRI 持久化了内部实例。
我必须做什么才能成功地自己分配内部实例的 IRI,而不是创建 b 节点?
加分问题:如何使资源 IRI 成为 Java 对象上的 属性,而不是使其与其标识的对象平行但断开连接?
代码:
内部:
package alibabaeval.domain;
import org.openrdf.annotations.Iri;
@Iri("http://example.com/innerType")
public class Inner {
@Iri("http://example.com/innerType/data")
private String data;
public Inner(String data) {
this.data = data;
}
// if this is missing, an unhelpful ClassCastException will be thrown on retrieval
public Inner() {
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
外部:
package alibabaeval.domain;
import org.openrdf.annotations.Iri;
@Iri("http://example.com/outerType")
public class Outer {
@Iri("http://example.com/outerType/data")
private String outerData;
@Iri("http://example.com/outerType/innerObject")
private Inner innerObject;
public Outer(String outerData) {
this.outerData = outerData;
}
// if this is missing, an unhelpful ClassCastException will be thrown on retrieval
public Outer() {
}
public String getOuterData() {
return outerData;
}
public void setOuterData(String outerData) {
this.outerData = outerData;
}
public Inner getInnerObject() {
return innerObject;
}
public void setInnerObject(Inner innerObject) {
this.innerObject = innerObject;
}
}
测试程序:
package alibabaeval;
import org.junit.Test;
import org.openrdf.model.URI;
import org.openrdf.model.ValueFactory;
import org.openrdf.query.QueryLanguage;
import org.openrdf.repository.Repository;
import org.openrdf.repository.object.ObjectConnection;
import org.openrdf.repository.object.ObjectRepository;
import org.openrdf.repository.object.config.ObjectRepositoryFactory;
import org.openrdf.repository.sail.SailRepository;
import org.openrdf.rio.RDFFormat;
import org.openrdf.rio.RDFWriter;
import org.openrdf.rio.Rio;
import org.openrdf.sail.memory.MemoryStore;
import alibabaeval.domain.Inner;
import alibabaeval.domain.Outer;
public class AlibabaEval {
public static void main(String[] args) throws Exception {
Repository store = new SailRepository(new MemoryStore());
store.initialize();
// wrap in an object repository
ObjectRepositoryFactory factory = new ObjectRepositoryFactory();
ObjectRepository repository = factory.createRepository(store);
// add a stuff to the repository
ObjectConnection con = repository.getConnection();
ValueFactory vf = con.getValueFactory();
Inner inner = new Inner("some inner data");
URI innerId = vf.createURI("http://example.com/inners/inner1");
con.addObject(innerId, inner);
URI outerId = vf.createURI("http://example.com/outers/outer1");
Outer outer = new Outer("some outer data");
outer.setInnerObject(inner);
con.addObject(outerId, outer);
// look at the triples that were created
System.out.println("\n\n\nGenerated triples:");
RDFWriter writer = Rio.createWriter(RDFFormat.NTRIPLES, System.out);
con.prepareGraphQuery(QueryLanguage.SPARQL, "CONSTRUCT { ?s ?p ?o } WHERE {?s ?p ?o }").evaluate(writer);
// close everything down
con.close();
repository.shutDown();
}
}
输出:
我只创建了两个对象实例,并将它们分别持久化。阿里巴巴似乎忽略了这一点,并创建了内部实例的第二个副本作为外部实例引用的b节点。
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/Users/me/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-jdk14/1.7.7/25d160723ea37a6cb84e87cd70773ff02997e857/slf4j-jdk14-1.7.7.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/me/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-log4j12/1.7.12/485f77901840cf4e8bf852f2abb9b723eb8ec29/slf4j-log4j12-1.7.12.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.JDK14LoggerFactory]
Jan 08, 2016 6:00:21 PM org.openrdf.repository.object.managers.helpers.Scanner scan
INFO: Scanning C:\workspace\AlibabaTest\bin for concepts
Jan 08, 2016 6:00:22 PM org.openrdf.repository.object.ObjectRepository compileSchema
INFO: Compiling schema
Jan 08, 2016 6:00:22 PM org.openrdf.repository.object.composition.ClassResolver setBaseClassRoles
WARNING: Concept will only be mergable: class alibabaeval.domain.Inner
Jan 08, 2016 6:00:22 PM org.openrdf.repository.object.composition.ClassResolver setBaseClassRoles
WARNING: Concept will only be mergable: class alibabaeval.domain.Outer
Generated triples:
<http://example.com/inners/inner1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.com/innerType> .
<http://example.com/inners/inner1> <http://example.com/innerType/data> "some inner data" .
<http://example.com/outers/outer1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.com/outerType> .
_:node1a8hqu4aqx1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.com/innerType> .
_:node1a8hqu4aqx1 <http://example.com/innerType/data> "some inner data" .
<http://example.com/outers/outer1> <http://example.com/outerType/innerObject> _:node1a8hqu4aqx1 .
<http://example.com/outers/outer1> <http://example.com/outerType/data> "some outer data" .
问题是 Inner
的 ID 被添加到商店中,但您的实际 Inner
POJO 没有得到更新。要解决此问题,只需在调用 addObject
.
之后添加一行 inner = con.getObject(Inner.class, innerId);
FWIW 额外的往返惩罚并不像阿里巴巴那样特别严重 recent-access 对象缓存 - 因此它不需要一直到持久层进行此查找。
至于如何从对象本身取回标识资源:如果您确定您的 POJO 实现了 RDFObject
接口,您可以调用 getResource
来检索关联的 id。 getResource
方法的实现可以简单地 return null
,顺便说一下,因为阿里巴巴会在其生成的对象中覆盖实现。
现在对阿里巴巴稍微熟悉了一些,又看了一遍文档,我看到了一个更好的答案。
阿里巴巴将在分离对象上使用RDFObject.getResource()返回的值。这是执行此操作的 inner 的实现:
package alibabaeval.domain;
import org.openrdf.annotations.Iri;
import org.openrdf.model.Resource;
import org.openrdf.model.impl.URIImpl;
import org.openrdf.repository.object.ObjectConnection;
import org.openrdf.repository.object.RDFObject;
@Iri("http://example.com/#innerType")
public class Inner implements RDFObject {
@Iri("http://example.com/innerType/data")
private String data;
private Resource detachedId;
public Inner() {
}
@Override
public ObjectConnection getObjectConnection() {
// don't really care about this one right now
return null;
}
@Override
public Resource getResource() {
// only run on detached object, is hidden by a proxy on managed objects
return detachedId;
}
public Resource getDetachedId() {
return detachedId;
}
public void setDetachedId(Resource detachedId) {
this.detachedId = detachedId;
}
public void setDetachedId(String detachedId) {
this.detachedId = new URIImpl(detachedId);
}
public void setResource(Resource resource) {
detachedId = resource;
}
public Inner(String data) {
this.data = data;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
这允许您这样做:
Inner inner = new Inner("some inner data");
inner.setDetachedId("http://example.com/inners/inner1");
URI outerId = vf.createURI("http://example.com/outers/outer1");
Outer outer = new Outer("some outer data");
outer.setInnerObject(inner);
con.addObject(outerId, outer);
并得到这些三元组:
<http://example.com/inners/inner1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.com/#innerType> .
<http://example.com/inners/inner1> <http://example.com/innerType/data> "some inner data" .
<http://example.com/outers/outer1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.com/#outerType> .
<http://example.com/outers/outer1> <http://example.com/outerType/data> "some outer data" .
<http://example.com/outers/outer1> <http://example.com/outerType/innerObject> <http://example.com/inners/inner1> .
此技术也适用于 single-parameter ObjectConnection.addObject(Object instance)
方法。
这也只适用于分离的对象。阿里巴巴管理的实例将代理 RDFObject.getResource() 方法,因此您不再控制它 returns.
我正在尝试 OpenRDF Alibaba (associated with Sesame) 作为将 Java 对象映射到 RDF 三元组并返回的工具。目前,我正在研究它如何处理对象图。
我有两个对象,内部和外部。 Outer 引用了 Inner。当我持久化一个外部实例时,似乎内部实例被表示为 b 节点,即使我之前已经使用分配的 IRI 持久化了内部实例。
我必须做什么才能成功地自己分配内部实例的 IRI,而不是创建 b 节点?
加分问题:如何使资源 IRI 成为 Java 对象上的 属性,而不是使其与其标识的对象平行但断开连接?
代码:
内部:
package alibabaeval.domain;
import org.openrdf.annotations.Iri;
@Iri("http://example.com/innerType")
public class Inner {
@Iri("http://example.com/innerType/data")
private String data;
public Inner(String data) {
this.data = data;
}
// if this is missing, an unhelpful ClassCastException will be thrown on retrieval
public Inner() {
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
外部:
package alibabaeval.domain;
import org.openrdf.annotations.Iri;
@Iri("http://example.com/outerType")
public class Outer {
@Iri("http://example.com/outerType/data")
private String outerData;
@Iri("http://example.com/outerType/innerObject")
private Inner innerObject;
public Outer(String outerData) {
this.outerData = outerData;
}
// if this is missing, an unhelpful ClassCastException will be thrown on retrieval
public Outer() {
}
public String getOuterData() {
return outerData;
}
public void setOuterData(String outerData) {
this.outerData = outerData;
}
public Inner getInnerObject() {
return innerObject;
}
public void setInnerObject(Inner innerObject) {
this.innerObject = innerObject;
}
}
测试程序:
package alibabaeval;
import org.junit.Test;
import org.openrdf.model.URI;
import org.openrdf.model.ValueFactory;
import org.openrdf.query.QueryLanguage;
import org.openrdf.repository.Repository;
import org.openrdf.repository.object.ObjectConnection;
import org.openrdf.repository.object.ObjectRepository;
import org.openrdf.repository.object.config.ObjectRepositoryFactory;
import org.openrdf.repository.sail.SailRepository;
import org.openrdf.rio.RDFFormat;
import org.openrdf.rio.RDFWriter;
import org.openrdf.rio.Rio;
import org.openrdf.sail.memory.MemoryStore;
import alibabaeval.domain.Inner;
import alibabaeval.domain.Outer;
public class AlibabaEval {
public static void main(String[] args) throws Exception {
Repository store = new SailRepository(new MemoryStore());
store.initialize();
// wrap in an object repository
ObjectRepositoryFactory factory = new ObjectRepositoryFactory();
ObjectRepository repository = factory.createRepository(store);
// add a stuff to the repository
ObjectConnection con = repository.getConnection();
ValueFactory vf = con.getValueFactory();
Inner inner = new Inner("some inner data");
URI innerId = vf.createURI("http://example.com/inners/inner1");
con.addObject(innerId, inner);
URI outerId = vf.createURI("http://example.com/outers/outer1");
Outer outer = new Outer("some outer data");
outer.setInnerObject(inner);
con.addObject(outerId, outer);
// look at the triples that were created
System.out.println("\n\n\nGenerated triples:");
RDFWriter writer = Rio.createWriter(RDFFormat.NTRIPLES, System.out);
con.prepareGraphQuery(QueryLanguage.SPARQL, "CONSTRUCT { ?s ?p ?o } WHERE {?s ?p ?o }").evaluate(writer);
// close everything down
con.close();
repository.shutDown();
}
}
输出:
我只创建了两个对象实例,并将它们分别持久化。阿里巴巴似乎忽略了这一点,并创建了内部实例的第二个副本作为外部实例引用的b节点。
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/Users/me/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-jdk14/1.7.7/25d160723ea37a6cb84e87cd70773ff02997e857/slf4j-jdk14-1.7.7.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/me/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-log4j12/1.7.12/485f77901840cf4e8bf852f2abb9b723eb8ec29/slf4j-log4j12-1.7.12.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.JDK14LoggerFactory]
Jan 08, 2016 6:00:21 PM org.openrdf.repository.object.managers.helpers.Scanner scan
INFO: Scanning C:\workspace\AlibabaTest\bin for concepts
Jan 08, 2016 6:00:22 PM org.openrdf.repository.object.ObjectRepository compileSchema
INFO: Compiling schema
Jan 08, 2016 6:00:22 PM org.openrdf.repository.object.composition.ClassResolver setBaseClassRoles
WARNING: Concept will only be mergable: class alibabaeval.domain.Inner
Jan 08, 2016 6:00:22 PM org.openrdf.repository.object.composition.ClassResolver setBaseClassRoles
WARNING: Concept will only be mergable: class alibabaeval.domain.Outer
Generated triples:
<http://example.com/inners/inner1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.com/innerType> .
<http://example.com/inners/inner1> <http://example.com/innerType/data> "some inner data" .
<http://example.com/outers/outer1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.com/outerType> .
_:node1a8hqu4aqx1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.com/innerType> .
_:node1a8hqu4aqx1 <http://example.com/innerType/data> "some inner data" .
<http://example.com/outers/outer1> <http://example.com/outerType/innerObject> _:node1a8hqu4aqx1 .
<http://example.com/outers/outer1> <http://example.com/outerType/data> "some outer data" .
问题是 Inner
的 ID 被添加到商店中,但您的实际 Inner
POJO 没有得到更新。要解决此问题,只需在调用 addObject
.
inner = con.getObject(Inner.class, innerId);
FWIW 额外的往返惩罚并不像阿里巴巴那样特别严重 recent-access 对象缓存 - 因此它不需要一直到持久层进行此查找。
至于如何从对象本身取回标识资源:如果您确定您的 POJO 实现了 RDFObject
接口,您可以调用 getResource
来检索关联的 id。 getResource
方法的实现可以简单地 return null
,顺便说一下,因为阿里巴巴会在其生成的对象中覆盖实现。
现在对阿里巴巴稍微熟悉了一些,又看了一遍文档,我看到了一个更好的答案。
阿里巴巴将在分离对象上使用RDFObject.getResource()返回的值。这是执行此操作的 inner 的实现:
package alibabaeval.domain;
import org.openrdf.annotations.Iri;
import org.openrdf.model.Resource;
import org.openrdf.model.impl.URIImpl;
import org.openrdf.repository.object.ObjectConnection;
import org.openrdf.repository.object.RDFObject;
@Iri("http://example.com/#innerType")
public class Inner implements RDFObject {
@Iri("http://example.com/innerType/data")
private String data;
private Resource detachedId;
public Inner() {
}
@Override
public ObjectConnection getObjectConnection() {
// don't really care about this one right now
return null;
}
@Override
public Resource getResource() {
// only run on detached object, is hidden by a proxy on managed objects
return detachedId;
}
public Resource getDetachedId() {
return detachedId;
}
public void setDetachedId(Resource detachedId) {
this.detachedId = detachedId;
}
public void setDetachedId(String detachedId) {
this.detachedId = new URIImpl(detachedId);
}
public void setResource(Resource resource) {
detachedId = resource;
}
public Inner(String data) {
this.data = data;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
这允许您这样做:
Inner inner = new Inner("some inner data");
inner.setDetachedId("http://example.com/inners/inner1");
URI outerId = vf.createURI("http://example.com/outers/outer1");
Outer outer = new Outer("some outer data");
outer.setInnerObject(inner);
con.addObject(outerId, outer);
并得到这些三元组:
<http://example.com/inners/inner1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.com/#innerType> .
<http://example.com/inners/inner1> <http://example.com/innerType/data> "some inner data" .
<http://example.com/outers/outer1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.com/#outerType> .
<http://example.com/outers/outer1> <http://example.com/outerType/data> "some outer data" .
<http://example.com/outers/outer1> <http://example.com/outerType/innerObject> <http://example.com/inners/inner1> .
此技术也适用于 single-parameter ObjectConnection.addObject(Object instance)
方法。
这也只适用于分离的对象。阿里巴巴管理的实例将代理 RDFObject.getResource() 方法,因此您不再控制它 returns.