An OWL ontology may have classes A, B, and C, and axiom (in DL notation):
A ⊑ (B ⊓ 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 ⊑ Person ⊓ 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 ⊑ (Y and Z) then X ⊑ Y and X ⊑ 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> |
--------------------------------------------------------------------------------------
Related
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" .
I want to run the following simple testing query:
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX vcard: <http://www.w3.org/2001/vcard-rdf/3.0#>
SELECT ?givenName ?name_count ?temp
WHERE
{ BIND(if(( ?name_count = 2 ), "just two", "definitely not 2") AS ?temp)
{ SELECT DISTINCT ?givenName (COUNT(?givenName) AS ?name_count)
WHERE
{ ?y vcard:Family ?givenName }
GROUP BY ?givenName
}
}
The graph I am querying is this from the tutorial https://jena.apache.org/tutorials/sparql_data.html:
#prefix vCard: <http://www.w3.org/2001/vcard-rdf/3.0#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
<http://somewhere/MattJones/> vCard:FN "Matt Jones" .
<http://somewhere/MattJones/> vCard:N _:b0 .
_:b0 vCard:Family "Jones" .
_:b0 vCard:Given "Matthew" .
<http://somewhere/RebeccaSmith/> vCard:FN "Becky Smith" .
<http://somewhere/RebeccaSmith/> vCard:N _:b1 .
_:b1 vCard:Family "Smith" .
_:b1 vCard:Given "Rebecca" .
<http://somewhere/JohnSmith/> vCard:FN "John Smith" .
<http://somewhere/JohnSmith/> vCard:N _:b2 .
_:b2 vCard:Family "Smith" .
_:b2 vCard:Given "John" .
<http://somewhere/SarahJones/> vCard:FN "Sarah Jones" .
<http://somewhere/SarahJones/> vCard:N _:b3 .
_:b3 vCard:Family "Jones" .
_:b3 vCard:Given "Sarah" .
Now the problem is that running it with Jena:
Query query = QueryFactory.create(theAboveQueryAsString);
QueryExecution qexec = QueryExecutionFactory.create(query, theAboveGraphmodel);
ResultSet execSel = qexec.execSelect();
ResultSetRewindable results = ResultSetFactory.copyResults(execSel);;
ResultSetFormatter.out(System.out, results, query);
gives off this result in console:
----------------------------------
| givenName | name_count | temp |
==================================
| "Smith" | 2 | |
| "Jones" | 2 | |
----------------------------------
having the temp values as null.
On the other hand running the same query on the the same graph in Ontotext GraphDb enviroment i get the correct result (saved as CSV):
givenName | name_count | temp
------------------------------------
Jones | 2 | just two
Smith | 2 | just two
Could there be a bug in the ARQ engine or am I missing something?
Thanks in advance.
I am using jena-arq 3.12.0
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Eclipse Version Version: 2019-06 (4.12.0)
There is a join between BIND and sub-select. The arguments to the join step are calculated before the join is done. So the BIND is evaluated, the sub-select is evaluated separately and the results joined. ?name_count isn't set in the BIND assignment. If you move it after the sub-select, it will apply to the results of the sub-select.
BIND adds a binding to the result of the pattern before it.
(base <http://example/base/>
(prefix ((rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>)
(vcard: <http://www.w3.org/2001/vcard-rdf/3.0#>))
(project (?givenName ?name_count ?temp)
(join
(extend ((?temp (if (= ?name_count 2) "just two" "definitely not 2")))
(table unit))
(distinct
(project (?givenName ?name_count)
(extend ((?name_count ?.0))
(group (?givenName) ((?.0 (count ?givenName)))
(bgp (triple ?y vcard:Family ?givenName))))))))))
Here, the (extend...) is one of two argument to the (join...). (table unit) is the "nothing" before the BIND.
If put afterwards, the algebra is:
(base <http://example/base/>
(prefix ((rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>)
(vcard: <http://www.w3.org/2001/vcard-rdf/3.0#>))
(project (?givenName ?name_count ?temp)
(extend ((?temp (if (= ?name_count 2) "just two" "definitely not 2")))
(distinct
(project (?givenName ?name_count)
(extend ((?name_count ?.0))
(group (?givenName) ((?.0 (count ?givenName)))
(bgp (triple ?y vcard:Family ?givenName))))))))))
and the extend (which is from the syntax BIND) is working on the (distinct ... of the sub-query.
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 ;
.
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);
}
}
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>