简体   繁体   中英

Recursive SPARQL query for a combination of triples

I have the following query that I run recursively in Python using ontospy:

SELECT ?c WHERE {
    ?c rdfs:subClassOf ?restriction .
    ?restriction owl:onProperty :has_part ; owl:someValuesFrom ?p .
    VALUES ?p { <some_uri> }
}

Basically, I take the values returned from that and re-run the query to follow a hierarchy of "has part some" relationships within an ontology. I am hoping to avoid making multiple SPARQL queries by adding the recursion to the query itself. I know how to do this for a single triple using rdfs:subClassOf* but cannot figure out the syntax for combining the two triples:

?c rdfs:subClassOf ?restriction .
?restriction owl:onProperty :has_part ; owl:someValuesFrom ?p .

Is this possible?

I can't give a formal proof, but this looks impossible. This is not what property paths were designed for, and why some extensions exist ( 1 , 2 ).

Under certain commitments (eg with tree-like structures), it is possible to figure out something using FILTER NOT EXISTS , however, this is not a general solution.

The idea is to do this in two queries. In essence, this is SELECT over CONSTRUCT . By the way, such SPARQL extension has already been proposed .


Let's use on which Ontospy is based, because

Ontospy does not offer any ontology-editing features, nor it can be used to interrogate a triplestore.

Input ( ontology.ttl )

@prefix : <http://www.example.org/ontology#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@base <http://www.example.org/ontology> .

<http://www.example.org/ontology> rdf:type owl:Ontology .

:hasPart rdf:type owl:ObjectProperty .

:Country rdf:type owl:Class ;
         rdfs:subClassOf [ rdf:type owl:Restriction ;
                           owl:onProperty :hasPart ;
                           owl:someValuesFrom :State
                         ] .

:State rdf:type owl:Class ;
       rdfs:subClassOf [ rdf:type owl:Restriction ;
                         owl:onProperty :hasPart ;
                         owl:someValuesFrom :City
                       ] .

:City rdf:type owl:Class .

Python code

import rdflib

g = rdflib.Graph()
g.parse("ontology.ttl", format="n3")

qres = g.update(
    """PREFIX : <http://www.example.org/ontology#> 
       INSERT { ?c :hasSome ?p } 
       WHERE  { ?c rdfs:subClassOf [ owl:onProperty :hasPart ; 
                                     owl:someValuesFrom ?p ] }""")

qres = g.query(
    """PREFIX : <http://www.example.org/ontology#> 
       SELECT ?a ?b WHERE {?a :hasSome+ ?b }""")

for row in qres:
    print("%s :hasSome+ %s" % row)

qres = g.update(
    """PREFIX : <http://www.example.org/ontology#> 
       DELETE { ?s :hasSome ?o } WHERE { ?s :hasSome ?o }""")

Output

:Country :hasSome+ :State
:State   :hasSome+ :City
:Country :hasSome+ :City

If you don't want to modify initial RDFLib graph, just create another one:

import rdflib

g1 = rdflib.Graph()
g1.parse("ontology.ttl", format="n3")

qres = g1.query(
    """PREFIX : <http://www.example.org/ontology#> 
       CONSTRUCT {?c :hasSome ?p } WHERE {
           ?c rdfs:subClassOf [ owl:onProperty :hasPart ;
                                owl:someValuesFrom ?p  ] }""")

g2 = rdflib.Graph();
for triple in qres: # quite a few triples
    g2.add(triple)

qres = g2.query(
    """PREFIX : <http://www.example.org/ontology#> 
       SELECT ?a ?b WHERE { ?a :hasSome+ ?b }""")

for row in qres:
    print("%s :hasSome+ %s" % row)

Probably you can use transitiveClosure() or transitive_objects() instead of the second query in both cases.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM