Jena TDB/Fuseki Performance - java

I have a simple SPARQL query which executes reasonably fast on my Jena TDB store using a local Fuseki SPARQL endpoint:
SELECT DISTINCT ?p
WHERE
{
?s rdf:type dbpedia-owl:Organisation .
?s ?p dbpedia:California .
}
LIMIT 10
It takes maybe 10 seconds to complete and contains a few owl:ObjectProperty's and other properties. When I want to show only an object property using the following query (note the additional triple and the limit of 1 at the end):
SELECT DISTINCT ?p
WHERE
{
?s rdf:type dbpedia-owl:Organisation .
?s ?p dbpedia:California .
?p a owl:ObjectProperty .
}
LIMIT 1
then I would expect the answer to appear just as quickly, and to show only one of the object properties previously shown. After all, it's only a further refinement of the previous query. However, the query takes many times longer, and finishes after several minutes instead of several seconds.
I am puzzled here. Why does the second query take so much longer?
I am using Fuseki version 1.1.0. Here's my fuseki configuration file:
#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 fuseki: <http://jena.apache.org/fuseki#> .
#prefix foaf: <http://xmlns.com/foaf/0.1/> .
#prefix : <http://localhost/dbpedia37#> .
[] rdf:type fuseki:Server ;
fuseki:services (
:service_text_tdb
) .
## Example of a TDB dataset and text index
## Initialize TDB
[] ja:loadClass "com.hp.hpl.jena.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 .
## ---------------------------------------------------------------
## This URI must be fixed - it's used to assemble the text dataset.
:text_dataset rdf:type text:TextDataset ;
text:dataset :dataset ;
text:index :indexLucene ;
.
# A TDB datset used for RDF storage
:dataset rdf:type tdb:DatasetTDB ;
tdb:location "/Users/jsimon/No-Backup/dbpedia37/tdb" ;
# tdb:unionDefaultGraph true ; # Optional
.
# 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 rdfs:label ]
[ text:field "text" ; text:predicate foaf:name ]
) .
:service_text_tdb rdf:type fuseki:Service ;
rdfs:label "TDB/text service" ;
fuseki:name "ds" ;
fuseki:serviceQuery "query" ;
fuseki:serviceQuery "sparql" ;
fuseki:serviceUpdate "update" ;
fuseki:serviceUpload "upload" ;
fuseki:serviceReadGraphStore "get" ;
fuseki:serviceReadWriteGraphStore "data" ;
fuseki:dataset :text_dataset ;
.

Related

The function "org.apache.jena.rdf.model.hasProperty" didn't work

I'm learning jena recently.
I try to understand their TUTORIALS. (https://jena.apache.org/tutorials/rdf_api.html#ch-Navigating-a-Model).
When I compile Tutorial06, (https://github.com/apache/jena/blob/main/jena-core/src-examples/jena/examples/rdf/Tutorial06.java)
I put a "/" in the end of the URI by accident in line 32:
static final String johnSmithURI = "http://somewhere/JohnSmith/";
(it should be: static final String johnSmithURI = "http://somewhere/JohnSmith";)
so I got the exception.
I want to use "org.apache.jena.rdf.model.hasProperty" to set a condition,
but it didn't work.
There might be two situation:
if I directly copy and paste "vcard.hasProperty​(VCARD.Family)"
the console will show "The method hasProperty​(Property) is undefined for the type Resource"
it's strange
this method is defined in their doc
https://jena.apache.org/documentation/javadoc/jena/org/apache/jena/rdf/model/Resource.html#hasProperty(org.apache.jena.rdf.model.Property)
However, if I just choose the function after I keyed in "." like the picture
enter image description here
It won't show the error
but the value of Boolean seems strange
I add those code since line 51 in Tutorial06:
System.out.println("vcard.hasProperty(VCARD.FN) : " + vcard.hasProperty(VCARD.FN)) ; System.out.println("vcard.hasProperty(VCARD.N) : " + vcard.hasProperty(VCARD.N)) ; System.out.println("vcard.hasProperty(VCARD.Family) : " + vcard.hasProperty(VCARD.Family)) ; System.out.println("vcard.hasProperty(VCARD.Given) : " + vcard.hasProperty(VCARD.Given)) ; System.out.println("vcard.hasProperty(VCARD.EMAIL) : " + vcard.hasProperty(VCARD.EMAIL)) ;
Result:
vcard.hasProperty(VCARD.FN) : true
vcard.hasProperty(VCARD.N) : true
vcard.hasProperty(VCARD.Family) : false
vcard.hasProperty(VCARD.Given) : false
vcard.hasProperty(VCARD.EMAIL) : false
the rdf file look like this:
<rdf:Description rdf:about="http://somewhere/JohnSmith">
<vCard:FN>John Smith</vCard:FN>
<vCard:N rdf:parseType="Resource">
<vCard:Family>Smith</vCard:Family>
<vCard:Given>John</vCard:Given>
</vCard:N>
</rdf:Description>
I'll appreciate if anyone can give me some idea about those situation.
I use Eclipse with jdk-11 and the jena-core -3.2.0.jar as my library
The "vCard:Family" has a different subject because of the <vCard:N rdf:parseType="Resource">.
The RDF structure is clearer in Turtle or N-Triples:
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix vCard: <http://www.w3.org/2001/vcard-rdf/3.0#> .
<http://somewhere/JohnSmith>
vCard:FN "John Smith" ;
vCard:N [ vCard:Family "Smith" ;
vCard:Given "John"
] .
or equivalently:
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix vCard: <http://www.w3.org/2001/vcard-rdf/3.0#> .
<http://somewhere/JohnSmith>
vCard:FN "John Smith" ;
vCard:N _:b0 .
_:b0 vCard:Family "Smith" ;
vCard:Given "John" .
or in N-Triples:
<http://somewhere/JohnSmith> <http://www.w3.org/2001/vcard-rdf/3.0#FN> "John Smith" .
<http://somewhere/JohnSmith> <http://www.w3.org/2001/vcard-rdf/3.0#N> _:B99dd1c9aX2D9045X2D4719X2D8d7eX2D9f4043b9b757 .
_:B99dd1c9aX2D9045X2D4719X2D8d7eX2D9f4043b9b757 <http://www.w3.org/2001/vcard-rdf/3.0#Family> "Smith" .
_:B99dd1c9aX2D9045X2D4719X2D8d7eX2D9f4043b9b757 <http://www.w3.org/2001/vcard-rdf/3.0#Given> "John" .

Convertering between textual SPARQL syntax and the SPIN RDF Vocabulary: How to add rdfs:comment and sp:text

Using the SPIN API (http://topbraid.org/spin/api/) and working from the example code at https://github.com/spinrdf/spinrdf/blob/master/src-examples/org/topbraid/spin/examples/SPINParsingExample.java I'm trying to add handling of rdfs:comment and spin:text to the example. Topbraid Composer Free Edition (TBC FE) does allow one comment per SPIN rule which is included in the RDF. TBC FE also optionally includes the SPIN SPARQL source code as an xsd:string value via the sp:text property. I'd like to do the same in an extended verion of the example and then transfer that over to my working code where I'd like to embed SPIN rule editing.
Here's my current extended version of the example code. Please ignore the logging warnings. Note that the comment I've inserted at the top of the example query (line 54) is silently dropped in the output (output also included below).
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*/
package mil.disa.dso.spo.a2i.nsc.sharing2025.raaDemo;
import org.topbraid.spin.arq.ARQ2SPIN;
import org.topbraid.spin.arq.ARQFactory;
import org.topbraid.spin.model.Select;
import org.topbraid.spin.system.SPINModuleRegistry;
import org.apache.jena.query.Query;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.rdf.model.Property;
import org.apache.jena.util.FileUtils;
import org.apache.jena.vocabulary.RDF;
/**
* Converts between textual SPARQL representation and SPIN RDF model.
*
* #author Holger Knublauch
*/
public class SPINParsingExample {
/**
* #param args
*/
public static void main(String[] args) {
// Register system functions (such as sp:gt (>))
SPINModuleRegistry.get().init();
// Create an empty OntModel importing SP
Model model = ModelFactory.createDefaultModel();
model.setNsPrefix("rdf", RDF.getURI());
model.setNsPrefix("ex", "http://example.org/demo#");
String query =
"# This is an example SPARQL comment\n" +
"SELECT ?person\n" +
"WHERE {\n" +
" ?person a ex:Person .\n" +
" ?person ex:age ?age .\n" +
" FILTER (?age > 18) .\n" +
"}";
System.out.println("Original SPARQL query string:\n\n" + query);
Query arqQuery = ARQFactory.get().createQuery(model, query);
ARQ2SPIN arq2SPIN = new ARQ2SPIN(model);
Select spinQuery = (Select) arq2SPIN.createQuery(arqQuery, null);
// TODO what about the sp:text? It's not in the artifacts printed below...
// TODO figure out how to add a comment to the tokenized query... does not propagate from source string above
// perhaps this is through and addProperty call to add an rdfs:comment?? many calls, not clear how to use...
// get javadoc?
System.out.println("\n-----");
System.out.println("SPIN query in Turtle:\n");
model.write(System.out, FileUtils.langTurtle);
System.out.println("\n-----");
System.out.println("SPIN query in XML:\n");
model.write(System.out, FileUtils.langXML);
System.out.println("\n-----");
String str = spinQuery.toString();
System.out.println("SPIN query:\n\n" + str);
// Now turn it back into a Jena Query
Query parsedBack = ARQFactory.get().createQuery(spinQuery);
System.out.println("Jena query:\n" + parsedBack);
}
}
Output from the above...
log4j:WARN No appenders could be found for logger (Jena).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Original SPARQL query string:
# This is an example SPARQL comment
SELECT ?person
WHERE {
?person a ex:Person .
?person ex:age ?age .
FILTER (?age > 18) .
}
-----
SPIN query in Turtle:
#prefix ex: <http://example.org/demo#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix sp: <http://spinrdf.org/sp#> .
[ a sp:Select ;
sp:resultVariables ( [ sp:varName "person" ]
) ;
sp:where ( [ sp:object ex:Person ;
sp:predicate rdf:type ;
sp:subject [ sp:varName "person" ]
]
[ sp:object [ sp:varName "age" ] ;
sp:predicate ex:age ;
sp:subject [ sp:varName "person" ]
]
[ a sp:Filter ;
sp:expression [ a sp:gt ;
sp:arg1 [ sp:varName "age" ] ;
sp:arg2 18
]
]
)
] .
-----
SPIN query in XML:
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:ex="http://example.org/demo#"
xmlns:sp="http://spinrdf.org/sp#">
<sp:Select>
<sp:resultVariables rdf:parseType="Collection">
<rdf:Description>
<sp:varName>person</sp:varName>
</rdf:Description>
</sp:resultVariables>
<sp:where rdf:parseType="Collection">
<rdf:Description>
<sp:object rdf:resource="http://example.org/demo#Person"/>
<sp:predicate rdf:resource="http://www.w3.org/1999/02/22-rdf-syntax-ns#type"/>
<sp:subject rdf:parseType="Resource">
<sp:varName>person</sp:varName>
</sp:subject>
</rdf:Description>
<rdf:Description>
<sp:object rdf:parseType="Resource">
<sp:varName>age</sp:varName>
</sp:object>
<sp:predicate rdf:resource="http://example.org/demo#age"/>
<sp:subject rdf:parseType="Resource">
<sp:varName>person</sp:varName>
</sp:subject>
</rdf:Description>
<sp:Filter>
<sp:expression>
<sp:gt>
<sp:arg2 rdf:datatype="http://www.w3.org/2001/XMLSchema#integer"
>18</sp:arg2>
<sp:arg1 rdf:parseType="Resource">
<sp:varName>age</sp:varName>
</sp:arg1>
</sp:gt>
</sp:expression>
</sp:Filter>
</sp:where>
</sp:Select>
</rdf:RDF>
-----
SPIN query:
SELECT ?person
WHERE {
?person a ex:Person .
?person ex:age ?age .
FILTER (?age > 18) .
}
Jena query:
SELECT ?person
WHERE
{ ?person a <http://example.org/demo#Person> ;
<http://example.org/demo#age> ?age
FILTER ( ?age > 18 )
}
I'm sure that there's a way to add an rdfs:comment and the source code (via sp:text) to the RDF, but I have not found it yet. I suspect that one can do both via calls to methods of the Select class via its spinQuery instantiation in the example (line 66), but I'm not sure how. Any pointers would be appreciated.
This question relates to my prior answered question How to turn a SPARQL/SPIN query/rule into an RDF structure from Java? but specializes on comments and source code in the RDF.
It seems you can add rdfs:comment only to the verbose rdf-form of query.
It is not possible to pass rdfs:comment to sp:text because the last one is a predicate for string literal, you can do it only as part of string. It seems Topbraid allows commenting only through RDF-graph, and text-query exists only in GUI (as separated model). An advice: keep your queries in RDF-form, in this case you will have no possible problems with prefixes also.
Example how to add rdfs:comment and sp:text:
public static void main(String ... args) {
Model model = ModelFactory.createDefaultModel();
model.setNsPrefix("rdf", RDF.getURI());
model.setNsPrefix("ex", "http://example.org/demo#");
model.setNsPrefix("sp", SP.getURI());
model.setNsPrefix("rdfs", RDFS.getURI());
String query = "SELECT ?person\n" +
"WHERE {\n" +
" ?person a ex:Person .\n" +
" ?person ex:age ?age .\n" +
" FILTER (?age > 18) .\n" +
"}";
Query arqQuery = ARQFactory.get().createQuery(model, query);
ARQ2SPIN arq2SPIN = new ARQ2SPIN(model);
Select select1 = (Select) arq2SPIN.createQuery(arqQuery, null);
select1.addProperty(RDFS.comment, "Comment1"); // <-- as part of rdf
Resource anon = model.createResource();
anon.addProperty(RDF.type, SP.Select);
anon.addProperty(SP.text, model.createTypedLiteral(
"# Comment2\n" + // <-- as part of string
"SELECT ?person\n" +
"WHERE {\n" +
" ?person a ex:Person .\n" +
" ?person ex:age ?age .\n" +
" FILTER (?age < 22) .\n" +
"}"));
Select select2 = anon.as(Select.class);
System.out.println("========================");
model.write(System.out, "ttl");
System.out.println("========================");
System.out.println("Select1:\n" + select1);
System.out.println("Select2:\n" + select2);
}
And output:
========================
#prefix ex: <http://example.org/demo#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix sp: <http://spinrdf.org/sp#> .
_:b0 a sp:Filter ;
sp:expression [ a sp:gt ;
sp:arg1 [ sp:varName "age" ] ;
sp:arg2 18
] .
_:b1 sp:object [ sp:varName "age" ] ;
sp:predicate ex:age ;
sp:subject [ sp:varName "person" ] .
[ a sp:Select ;
rdfs:comment "Comment1" ;
sp:resultVariables ( _:b2 ) ;
sp:where ( _:b3 _:b1 _:b0 )
] .
_:b3 sp:object ex:Person ;
sp:predicate rdf:type ;
sp:subject [ sp:varName "person" ] .
_:b2 sp:varName "person" .
[ a sp:Select ;
sp:text "# Comment2\nSELECT ?person\nWHERE {\n ?person a ex:Person .\n ?person ex:age ?age .\n FILTER (?age < 22) .\n}"
] .
========================
Select1:
# Comment1
SELECT ?person
WHERE {
?person a ex:Person .
?person ex:age ?age .
FILTER sp:gt(?age, 18) .
}
Select2:
# Comment2
SELECT ?person
WHERE {
?person a ex:Person .
?person ex:age ?age .
FILTER (?age < 22) .
}

how to return a detail information of URL/author from cidoc crm rdf file using sparql

Thank you for the answer but unfortunately i am not getting any result in the console, here i am attaching my code, please guide that where i am making a mistake.
FileManager.get().addLocatorClassLoader(test.class.getClassLoader());
Model model=FileManager.get().loadModel("H:/EclipseWorkplace/MuseumDatabaseRecommendation/src/data3.rdf");
String spr="prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n"+
"prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>\n"+
"prefix crm: <urn:x-stackoverflow:example#>\n"+
"\n"+
"SELECT * WHERE{\n"+
" [ crm:E21_Person/rdfs:label ?creator\n"+
" ; crm:P108i_was_produced_by [ crm:P126_employed [ rdfs:label ?material ]\n"+
" ; crm:P4_has_time-span [ crm:P82_at_some_time_within ?timespan ]\n"+
" ]\n"+
" ; crm:P3_has_note [ a crm:P102_has_title\n"+
" ; rdfs:label ?title\n"+
" ]\n"+
" ]\n"+
" FILTER( ?creator = \"Brett WHITELEY\" ).\n"+
"}";
Query query = QueryFactory.create(spr); //s2 = the query above
QueryExecution qExe = QueryExecutionFactory.create( query,model );
//QueryExecution qExe = QueryExecutionFactory.sparqlService( "http://dbpedia.org/sparql", query );
ResultSet results = qExe.execSelect();
ResultSetFormatter.out(System.out, results, query);
My current output is
-----------------------------------------
| creator | material | timespan | title |
=========================================
-----------------------------------------
Thanks for your time.
Input Data
In order to facilitate readability, I restructured your model into TURTLE syntax for others to read.
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix crm: <http://www.cidoc-crm.org/cidoc-crm/> .
<http://phdprototype.tk/collectionimage /4D0BFF17-5810-4644-A550-D35EE090D4A8.png>
a "Painting" ;
rdfs:label "Brett WHITELEY" ;
crm:E21_Person [ a <E39_Actor> ;
rdfs:label "Brett WHITELEY"
] ;
crm:E62_String "Painting\n" ;
crm:P108i_was_produced_by [ a crm:E12_Production ;
crm:P126_employed [ a crm:E57_Material ;
rdfs:label "Oil"
] ;
crm:P4_has_time-span [ a crm:E52_Time-Span ;
crm:P82_at_some_time_within "\n 1976\n "
]
] ;
crm:P3_has_note [ a crm:P102_has_title ;
rdfs:label "Interior with Time Past"
] ;
crm:P7_took_place_at [ a crm:E53_Place ;
crm:E44_Place_Appellation " \n 5D\n "
] ;
crm:P91_has_unit [ a crm:E58_Measurement_Unit ;
rdfs:label "182.0 h * 200.0 w cm"
] .
There are some issues with this data. For example, your painting has rdf:type the plain literal "painting", which is extremely bad. This is denoted by the a "painting" property-object pair. We can execute a query over this data, but you may wish to restructure your ontology so that it uses terms like rdf:type properly.
Query
For the sample data provided, the following query will extract what you are looking for:
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix crm: <http://www.cidoc-crm.org/cidoc-crm/>
SELECT * WHERE{
[ crm:E21_Person/rdfs:label ?creator
; crm:P108i_was_produced_by [ crm:P126_employed [ rdfs:label ?material ]
; crm:P4_has_time-span [ crm:P82_at_some_time_within ?timespan ]
]
; crm:P3_has_note [ a crm:P102_has_title
; rdfs:label ?title
]
]
FILTER( ?creator = "Brett WHITELEY" ).
}
will result in:
----------------------------------------------------------------------------------
| creator | material | timespan | title |
==================================================================================
| "Brett WHITELEY" | "Oil" | "\n 1976\n " | "Interior with Time Past" |
----------------------------------------------------------------------------------
Note that this is highly tailored to your particular sample data. You will need to adjust this query to match what structures are actually allowed. For (hypothetical) example, the TimeSpan instance may sometimes have a crm:P82_at_some_time_span property, or it may have some crm:exampleProperty that relates it to another values. In that case, you'd need to modify the query to use a property path to match this.
Example Code
public static final String queryString = "prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n"+
"prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>\n"+
"prefix crm: <http://www.cidoc-crm.org/cidoc-crm/>\n"+
"\n"+
"SELECT * WHERE{\n"+
" [ crm:E21_Person/rdfs:label ?creator\n"+
" ; crm:P108i_was_produced_by [ crm:P126_employed [ rdfs:label ?material ]\n"+
" ; crm:P4_has_time-span [ crm:P82_at_some_time_within ?timespan ]\n"+
" ]\n"+
" ; crm:P3_has_note [ a crm:P102_has_title\n"+
" ; rdfs:label ?title\n"+
" ]\n"+
" ]\n"+
" FILTER( ?creator = \"Brett WHITELEY\" ).\n"+
"}";
public static final Query query = QueryFactory.create(queryString);
#Test
public void test() throws Exception {
final Model model = ModelFactory.createDefaultModel();
try( final InputStream in = this.getClass().getResourceAsStream("/so.rdf") ) {
model.read(in, null, "RDF/XML");
}
model.write(System.out, "TTL");
System.out.println("=================================================================");
System.out.println(queryString);
System.out.println("=================================================================");
try( final QueryExecution exec = QueryExecutionFactory.create(query, model) ) {
ResultSetFormatter.out(System.out, exec.execSelect(), query);
}
}

How to automatically generate new instance identifier in INSERT query on Sesame 2.7.7

I'm facing the problem of identification when doing automatic instanciation of triplets
using SPARQL queries. Let see the problem through this example.
suppose that we have the following triplets set representing person and their weeding relation.
ns:Person rdf:type owl:Class
ns:Man rdfs:subClassOf ns:Person
ns:Woman rdfs:subClassOf ns:Person
ns:Family rdf:type owl:Class
ns:jean rdf:type ns:Man
ns:roger rdf:type ns:Man
ns:chris rdf:type ns:Woman
ns:sofy rdf:type ns:Woman
ns:chloe rdf:type ns:Woman
ns:jean ns:isMarriedWith ns:chris
ns:roger ns:isMarriedWith ns:chloe
Ok now we want to automatically build families using the rule that a family is when two person are married.
IF (ns:A ns:isMarriedWith ns:B)
THEN (ns:f rdf:type Family)
AND (ns:f ns:contains A)
AND (ns:f ns:contains B)
here is the Java code that I propose to do that upon an http sesame repository.
Repository myRepository = new HTTPRepository(serverURL, repositoryId);
myRepository.initialize();
RepositoryConnection con = myRepository.getConnection();
query = "INSERT {"
+ " ns:f0 rdf:type ns:Family ."
+ " ns:f0 ns:contains ?p ."
+ " ns:f0 ns:contains ?q ."
+ "}"
+ "WHERE { "
+ " ?p ns:isMarriedWith ?q ."
+ "}";
Update update = con.prepareUpdate(QueryLanguage.SPARQL, query);
update.execute();
Here are triplets which were inserted
ns:f0 rdf:type ns:Family
ns:f0 ns:contains ns:jean
ns:f0 ns:contains ns:chris
ns:f0 ns:contains ns:roger
ns:f0 ns:contains ns:chloe
This result is not correct, because only one family is created. The problem is that the identify of the familly instance doesn't change any time that the WHERE clause match.
How could I tune the above code in order the have the following correct response.
ns:f0 rdf:type ns:Family
ns:f0 ns:contains ns:jean
ns:f0 ns:contains ns:chris
ns:f1 rdf:type ns:Family
ns:f1 ns:contains ns:roger
ns:f1 ns:contains ns:chloe
Thank !
It's much easier to answer this type of question if you provide data and code that we can work with without having to add a whole bunch of stuff to make it complete. E.g., provide complete working RDF documents. Your data is something like this (in Turtle):
#prefix ns: <http://stackoverflow.com/q/20287293/1281433/> .
#prefix owl: <http://www.w3.org/2002/07/owl#> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
ns:Person a owl:Class .
ns:Man rdfs:subClassOf ns:Person .
ns:Woman rdfs:subClassOf ns:Person .
ns:Family a owl:Class .
ns:jean a ns:Man .
ns:roger a ns:Man .
ns:chris a ns:Woman .
ns:sofy a ns:Woman .
ns:chloe a ns:Woman .
ns:jean ns:isMarriedWith ns:chris .
ns:roger ns:isMarriedWith ns:chloe .
In your SPARQL query, it's not clear what f0 is, since it's not legal SPARQL syntax, but based on your description of the problem, you've got something like the following. I've changed to a construct query so that we can look at the results of the query and see the triples that are constructed, which would be the same as the triples that get inserted. This just makes it easier to see what's happening.
prefix ns: <http://stackoverflow.com/q/20287293/1281433/>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix xsd: <http://www.w3.org/2001/XMLSchema#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix : <urn:ex:>
construct {
:f0 a ns:Family . # This can be written as
:f0 ns:contains ?p . # :f0 a ns:Family ; ns:contains ?p, ?q .
:f0 ns:contains ?q . #
}
where {
?p ns:isMarriedWith ?q .
}
Now, your problem is that when you run this query on that data, you get results like:
:f0 a ns:Family ;
ns:contains ns:chris , ns:jean , ns:chloe , ns:roger .
where there's one family that contains all four people, but you want a different family for each pair. The trick is to replace the constant :f0 with a blank node, which will be unique for each match in the query. You could do this just by changing :f0 to _:f0:
_:f0 a ns:Family .
_:f0 ns:contains ?p .
_:f0 ns:contains ?q .
but I'd prefer to use a bit more of the syntactic sugar that we have available to us and just write:
[ a ns:Family ; ns:contains ?p, ?q ]
so that we have:
prefix ns: <http://stackoverflow.com/q/20287293/1281433/>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix xsd: <http://www.w3.org/2001/XMLSchema#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix : <urn:ex:>
construct {
_:f0 a ns:Family ; ns:contains ?p, ?q .
}
where {
?p ns:isMarriedWith ?q .
}
The results of this query contain two different families:
#prefix : <urn:ex:> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix ns: <http://stackoverflow.com/q/20287293/1281433/> .
#prefix owl: <http://www.w3.org/2002/07/owl#> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
[ a ns:Family ;
ns:contains ns:chris , ns:jean
] .
[ a ns:Family ;
ns:contains ns:chloe , ns:roger
] .
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:ns="http://stackoverflow.com/q/20287293/1281433/"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns="urn:ex:"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
<ns:Family>
<ns:contains rdf:resource="http://stackoverflow.com/q/20287293/1281433/chris"/>
<ns:contains rdf:resource="http://stackoverflow.com/q/20287293/1281433/jean"/>
</ns:Family>
<ns:Family>
<ns:contains rdf:resource="http://stackoverflow.com/q/20287293/1281433/chloe"/>
<ns:contains rdf:resource="http://stackoverflow.com/q/20287293/1281433/roger"/>
</ns:Family>
</rdf:RDF>

Retrieving superclasses implied by OWL intersection classes

An OWL ontology may have classes A, B, and C, and axiom (in DL notation):
A &sqsubseteq; (B &sqcap; C)
or in approximate Manchester OWL Syntax:
A subClassOf (B and C)
It is logically true that A is a subclass of B, and that A is a subclass of C, but the triples
A rdfs:subClassOf B
A rdfs:subClassOf C
are not necessarily present in the RDF serialization of the OWL ontology. For instance, consider this very simple ontology in Protégé and its RDF serialization in RDF/XML and Turtle:
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://stackoverflow.com/q/19924861/1281433/sample.owl#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
<owl:Ontology rdf:about="http://stackoverflow.com/q/19924861/1281433/sample.owl"/>
<owl:Class rdf:about="http://stackoverflow.com/q/19924861/1281433/sample.owl#C"/>
<owl:Class rdf:about="http://stackoverflow.com/q/19924861/1281433/sample.owl#B"/>
<owl:Class rdf:about="http://stackoverflow.com/q/19924861/1281433/sample.owl#A">
<rdfs:subClassOf>
<owl:Class>
<owl:intersectionOf rdf:parseType="Collection">
<owl:Class rdf:about="http://stackoverflow.com/q/19924861/1281433/sample.owl#B"/>
<owl:Class rdf:about="http://stackoverflow.com/q/19924861/1281433/sample.owl#C"/>
</owl:intersectionOf>
</owl:Class>
</rdfs:subClassOf>
</owl:Class>
</rdf:RDF>
#prefix : <http://stackoverflow.com/q/19924861/1281433/sample.owl#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix owl: <http://www.w3.org/2002/07/owl#> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
<http://stackoverflow.com/q/19924861/1281433/sample.owl>
a owl:Ontology .
:B a owl:Class .
:C a owl:Class .
:A a owl:Class ;
rdfs:subClassOf [ a owl:Class ;
owl:intersectionOf ( :B :C )
] .
The serialization has a triple with rdfs:subClassOf, but the object isn't :B or :C, so a query like
:A rdfs:subClassOf ?superclass
won't return the superclasses of :A. How can I write a SPARQL query that will return those superclasses of :A?
It sounds like you've got a class that is a subclass of some intersection class. E.g., you might have
Student &sqsubseteq; Person &sqcap; enrolledIn some Course
In the Protégé OWL ontology editor, this would look like:
If you write a SPARQL query for subclasses, e.g.,
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
select ?subclass ?superclass where {
?subclass rdfs:subClassOf ?superclass
}
and you don't have a reasoner inferring additional data, you won't see Student as a subclass in your results, but you might see an blank (anonymous) node:
---------------------------------------------------------
| subclass | superclass |
=========================================================
| <http://www.examples.org/school#Student> | _:b0 |
---------------------------------------------------------
To understand why this is the case, you need to take a look at the RDF serialization of the ontology. In this case, it's (in RDF/XML):
<rdf:RDF
xmlns="http://www.examples.org/school#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
<owl:Ontology rdf:about="http://www.examples.org/school"/>
<owl:Class rdf:about="http://www.examples.org/school#Course"/>
<owl:Class rdf:about="http://www.examples.org/school#Person"/>
<owl:Class rdf:about="http://www.examples.org/school#Student">
<rdfs:subClassOf>
<owl:Class>
<owl:intersectionOf rdf:parseType="Collection">
<owl:Class rdf:about="http://www.examples.org/school#Person"/>
<owl:Restriction>
<owl:onProperty>
<owl:ObjectProperty rdf:about="http://www.examples.org/school#enrolledIn"/>
</owl:onProperty>
<owl:someValuesFrom rdf:resource="http://www.examples.org/school#Course"/>
</owl:Restriction>
</owl:intersectionOf>
</owl:Class>
</rdfs:subClassOf>
</owl:Class>
</rdf:RDF>
Or in the more human-readable Turtle (which is also more like the SPARQL query syntax):
#prefix : <http://www.examples.org/school#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix owl: <http://www.w3.org/2002/07/owl#> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
:Student a owl:Class ;
rdfs:subClassOf [ a owl:Class ;
owl:intersectionOf ( :Person [ a owl:Restriction ;
owl:onProperty :enrolledIn ;
owl:someValuesFrom :Course
] )
] .
:Person a owl:Class .
:enrolledIn a owl:ObjectProperty .
:Course a owl:Class .
<http://www.examples.org/school>
a owl:Ontology .
There is, in fact, a Student rdfs:subClassOf [ ... ] triple in the data, but the [ ... ] is a blank node; it's an anonymous owl:Class that is the intersection of some other classes. A reasoner would be able to tell you that if X &sqsubseteq; (Y and Z) then X &sqsubseteq; Y and X &sqsubseteq; Z, but a SPARQL query on its own won't do that. You could make a more complex SPARQL query like this that would, though:
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select ?subclass ?superclass where {
{ ?subclass rdfs:subClassOf ?superclass }
union
{ ?subclass rdfs:subClassOf [ owl:intersectionOf [ rdf:rest* [ rdf:first ?superclass ] ] ] }
}
--------------------------------------------------------------------------------------
| subclass | superclass |
======================================================================================
| <http://www.examples.org/school#Student> | _:b0 |
| <http://www.examples.org/school#Student> | <http://www.examples.org/school#Person> |
| <http://www.examples.org/school#Student> | _:b1 |
--------------------------------------------------------------------------------------
The two blank nodes are the anonymous intersection class, and the anonymous restriction class (enrolledIn some Course). If you only want IRI results, you can use a filter:
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select ?subclass ?superclass where {
{ ?subclass rdfs:subClassOf ?superclass }
union
{ ?subclass rdfs:subClassOf [ owl:intersectionOf [ rdf:rest* [ rdf:first ?superclass ] ] ] }
filter( isIRI( ?superclass ) )
}
--------------------------------------------------------------------------------------
| subclass | superclass |
======================================================================================
| <http://www.examples.org/school#Student> | <http://www.examples.org/school#Person> |
--------------------------------------------------------------------------------------
Now, as final touch, if you want to make your query a bit smaller, since the only difference in those two unioned patterns is the path that connects ?subclass and ?superclass, you can actually write this with just one property path. (Although, as noted in Sparql query Subclass or EquivalentTo, you might run into some issues with Protégé if you do this.) The idea is that you can rewrite this:
{ ?subclass rdfs:subClassOf ?superclass }
union
{ ?subclass rdfs:subClassOf [ owl:intersectionOf [ rdf:rest* [ rdf:first ?superclass ] ] ] }
as this, by using property paths, which also removes the need for the blank nodes:
?subclass ( rdfs:subClassOf |
( rdfs:subClassOf / owl:intersectionOf / rdf:rest* / rdf:first ) ) ?superclass
and you can simplify that a bit more to
?subclass rdfs:subClassOf/((owl:intersectionOf/rdf:rest*/rdf:first)+) ?superclass
and you can even remove one level of parentheses from that, to make it
?subclass rdfs:subClassOf/(owl:intersectionOf/rdf:rest*/rdf:first)+ ?superclass
but then you'd have to start remembering the precedence rules, and that's not much fun. The query works though:
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select ?subclass ?superclass where {
?subclass rdfs:subClassOf/(owl:intersectionOf/rdf:rest*/rdf:first)+ ?superclass
filter( isIRI( ?superclass ) )
}
--------------------------------------------------------------------------------------
| subclass | superclass |
======================================================================================
| <http://www.examples.org/school#Student> | <http://www.examples.org/school#Person> |
--------------------------------------------------------------------------------------

Categories