How do I convert a rdflib.term.URIRef back into a string that includes a namespace prefix? - semantic-web

I am working with rdflib. I am parsing Turtle files that include namespace prefixes. When I get my triples back from the SPARQL query, they contain rdflib.term.URIRef elements, which print as things like this:
http://resources.data.gov/resources/dcat-us/#public
My rdflib graph knows that usg: is a namespace prefix for http://resources.data.gov/resources/dcat-us/# . I would like to convert http://resources.data.gov/resources/dcat-us/#public back to usg:public on printing.
MWE
Here is a file mwe_schema.ttl:
#prefix usg: <http://resources.data.gov/resources/dcat-us/#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix dcat: <http://www.w3.org/ns/dcat#> .
#prefix dct: <http://purl.org/dc/terms/#> .
usg:public
a rdfs:Property ;
rdfs:label "public"#en ;
rdfs:comment "Data asset is or could be made publicly available to all without restrictions." ;
.
Here is a program mwe_demo.py:
#!/usr/bin/env demonstrate python namespaces
import rdflib
from rdflib import Dataset, Graph, URIRef, Literal, Namespace, BNode
if __name__=="__main__":
g = Graph()
g.parse("mwe_schema.ttl")
for r in g.query(
"""
SELECT DISTINCT ?aSubject ?aPredicate ?anObject
WHERE {
?aSubject ?aPredicate ?anObject
}
"""):
d = r.asdict()
print(d['aSubject'],d['aPredicate'],d['anObject'])
Here is the actual output:
http://resources.data.gov/resources/dcat-us/#public http://www.w3.org/2000/01/rdf-schema#comment Data asset is or could be made publicly available to all without restrictions.
http://resources.data.gov/resources/dcat-us/#public http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://www.w3.org/2000/01/rdf-schema#Property
http://resources.data.gov/resources/dcat-us/#public http://www.w3.org/2000/01/rdf-schema#label public
Here is my desired output:
usg:public rdfs:comment rdfs:Property
usg:public http://www.w3.org/1999/02/22-rdf-syntax-ns#type rdfs:Property
usg:public rdfs:label public
(I will separately handle turning the last public into `"public"#en).

Results from SPARQL queries are not themselves RDF but SPARQL Results formats (see https://www.w3.org/TR/2013/REC-sparql11-results-json-20130321/).
This means results like http://resources.data.gov/resources/dcat-us/#public are strings in JSON or XML and not RDFlib's URIRef objects which can easily be prefixed.
To compress those URIs down with the given prefixes, don't SPARQL query but loop through the graph and use the Namespace Manager's qname() function like this:
for s, p, o in g:
for x in [s, p, o]:
print(g.qname(x) if isinstance(x, URIRef) else x, end=" ")
print()
If you really want to compress SPARQL results, you will have to use a CONSTRUCT query that returns an RDF graph, not a SPARQL Results output.

Related

Converting a bnode to a string in graphdb

I have an RDF file where the resources are identified with nodeID's instead of URIs. I have imported them into Ontotext graphdb, and would like to generate URIs based on the nodeID (which I preserved during import). For example, I am trying to map this triple
_:C00456 rdf:type skos:Concept
to this:
<https://example.com/data/C00456> rdf:type skos:Concept
Unfortunately, if ?s is a BNODE, STR(?s) is an empty string in graphdb. xsd:string(?s), ditto. IRI(?s), you guessed it. Is there any function that will expose the form of the bnode as a string, so that I can build a URI from it? I went through the list of functions in the sparql 1.1 specification and could not see any.
PS It would have been nice if graphdb would just convert the nodeIDs to URIs during import (I specified a prefix for relative names), but it went by the book and turned them into bnodes. If I overlooked something, I'll be glad to be set right.
You can use the spif:buildString function to convert a BNode to String and then to IRI.
Here is a sample query:
PREFIX spif: <http://spinrdf.org/spif#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
CONSTRUCT {?sIRI ?p ?o} WHERE {
?s ?p ?o .
FILTER (isBlank(?s))
BIND (IRI(spif:buildString("http://my/namespace/{?1}", ?s)) as ?sIRI)
} LIMIT 10
The function is documented here:
https://graphdb.ontotext.com/documentation/10.0/sparql-functions-reference.html?highlight=buildstring#sparql-spin-functions-and-magic-predicates

DBPedia-France (fr.dpbedia.org/sparql) query giving different result from a call to another

I'm calling on http://fr.dbpedia.org/sparql
the following SPARQL query:
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#>
select distinct ?lcs where {
{
?lcs ^(rdf:type/rdfs:subClassOf*) <http://fr.dbpedia.org/resource/Honoré_Daumier> ,
<http://fr.dbpedia.org/resource/Auguste_Rodin>;
a owl:Class .
filter not exists {
?llcs ^(rdf:type/rdfs:subClassOf*) <http://fr.dbpedia.org/resource/Honoré_Daumier> ,
<http://fr.dbpedia.org/resource/Auguste_Rodin>;
a owl:Class ;
rdfs:subClassOf+ ?lcs .
}
}
}
On some call I've http://dbpedia.org/ontology/Person as result, on others call I'm getting http://dbpedia.org/ontology/Person and http://dbpedia.org/ontology/Agent and with others the previous answers plus http://www.w3.org/2002/07/owl#Thing
without nothing to know that a response isn't complete. How can I use the result, if it is a little randomized
The main reason for your query not working as expected is that the data the data is i) split into separate graphs and ii) not all graphs were added to the default graph.
To keep it short, the instance data is contained inside the graph http://fr.dbpedia.org whereas the schema triples will be accessible via http://dbpedia.org graph only. Sometimes, if no graph is given, then the union of some graphs is used as the default graph which will be the dataset at query time. Unfortunately, this doesn't hold for the French DBpedia endpoint, only the instance data graph will be used.
You can check this with
DESCRIBE <http://dbpedia.org/ontology/Person>
which is empty when using either no graph explicitly or the graph http://fr.dbpedia.org, but non-empty for graph http://dbpedia.org.
The way to define the default graph is using the keyword FROM. For your query, it should therefore be
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#>
select distinct ?lcs
from <http://fr.dbpedia.org>
from <http://dbpedia.org>
where {
?lcs ^(rdf:type/rdfs:subClassOf*) <http://fr.dbpedia.org/resource/Honoré_Daumier> ,
<http://fr.dbpedia.org/resource/Auguste_Rodin>;
a owl:Class .
filter not exists {
?llcs ^(rdf:type/rdfs:subClassOf*) <http://fr.dbpedia.org/resource/Honoré_Daumier> ,
<http://fr.dbpedia.org/resource/Auguste_Rodin>;
a owl:Class ;
rdfs:subClassOf+ ?lcs .
}
}
Note, while this seems to return the correct result, you should also consider the comment from #TallTed regarding possible differences among language chapters (e.g. English vs French Wikipedia as source), release dumps (2016 vs 2018 or even the DBpedia Live) as well as Virtuoso versions used as backend.

RDF + OWL reasoning

Let's suppose I have an RDF data about Socrates. The data is shown below
subject, predicate, object
man, being, mortal
Socrates, being, man
To check whether Socrates is mortal I have a request
SELECT *
FROM RDFData t1
JOIN RDFData t2
ON t1.subject = t2.object
Then I have a filter on "Socrates" and "mortal" and if result is not empty, then Socrates is mortal.
It works fine, but my teacher asks to add OWL information.
For example, if we have the next data
subject, predicate, object
man, being, mortal
Socrates, being, Greek
Greek, being, man
My approach does not work, because we have additional step in the chain.
I need to add an OWL static data here and implement a request for arbitrary number of steps in the chain.
What are my next steps?
If we turn your example data into actual RDF (using Turtle syntax), you'd get something like this:
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix : <http://example.org/> .
:socrates rdf:type :Greek .
:Man rdfs:subClassOf :Mortal .
:Greek rdfs:subClassOf :Man .
If you upload this data into an RDF database (such as RDF4J, Jena, GraphDB, Stardog, Blazegraph, or a host of other options), you can use the following SPARQL query:
ASK WHERE { :socrates rdf:type/rdfs:subClassOf* :Mortal }
This checks if :socrates is of a type that is either :Mortal, or a (direct or indirect) subclass of :Mortal. It returns true if Socrates is a mortal, false otherwise. You don't even need a reasoner for this, you can just use the expressivity of the query language.
If your RDF database supports basic RDFS reasoning, you can simplify your query even further:
ASK WHERE { :socrates rdf:type :Mortal }

SPARQL 1.1 entailment regimes and query with FROM clause (follow-up)

This is a follow-up question from SPARQL 1.1 entailment regimes and query with FROM clause
I'm currently documenting/testing about SPARQL 1.1 entailment regimes and the recommendation repeatedly states that
The scoping graph is graph-equivalent to the active graph...
So it would seems that the inference scoping graph depends on the query.
The question is: does the scoping graph stems from the query's dataset (FROM/FROM NAMED clauses) or does it refer to the real current active graph context for the triple pattern being evaluated ?
With the following graphs
# Named graph: <urn:rdfs-schema-graph>
#prefix ex:<http://www.example.org/> .
ex:Article rdfs:subClassOf ex:Publication .
ex:publishes rdfs:range ex:Publication .
# Named graph: <urn:data-graph>
#prefix ex:<http://www.example.org/> .
ex:book1 a ex:Publication .
ex:book2 a ex:Article .
ex:MITPress ex:publishes ex:book3 .
What should the following query return (here under RDFS-entailment regime, for instance) and according to the recommendation ?
PREFIX ex: <http://www.example.org/>
SELECT ?s
FROM <urn:rdfs-schema-graph>
FROM NAMED <urn:data-graph>
WHERE {
GRAPH <urn:data-graph> {
?s a ex:Publication .
}
}
should I get back all three resources:
<http://www.example.org/book1>
<http://www.example.org/book2>
<http://www.example.org/book3>
or just
<http://www.example.org/book1>
since the active graph on the triple pattern is scoped to the NAMED graph while inferencing axioms are "located" in the default graph ?
Thanks for your insight,
Max.

in turtle or RDF can I add a predicate/object on all subjects that match a criteria?

I am doing some experiments with importing triples formulated in the turtle language
within the openrdf-workbench webapp in Tomcat, which has incorporated a SPARQL endpoint.
I wonder if with turtle, or, generally, in RDF / RDFS is it possible to add a certain predicate/object declaration on all (implicit) subjects conditionally to the existence of another predicate/object.
For example, if I have the following triples defined:
foo:a foo:b foo:c
foo:d foo:b foo:c
foo:e foo:b foo:c
foo:f foo:b foo:c
I would like to automatically add the following predicate/subject to all subjects that match predicate=foo:b and object=foo:c:
(implicit subject) foo:g foo:h
in order to automatically produce the following triples:
foo:a foo:g foo:h
foo:d foo:g foo:h
foo:e foo:g foo:h
foo:f foo:g foo:h
Is this possible?
Alternatively: is there any way to define some triples in order to enable SPARQL to find foo:a/d/e/f when queried for subjects that have foo:g foo:h as predicate/object?
Part 1 - Creating additional information
The first part of your question can be solved in one of two ways:
Using Inference
Using SPARQL Update
Inferencing
Inference is a technique whereby you define rules that infer additional triple based on your existing triples. You typically either use a pre-defined set of rules or use your own custom rules. I think Sesame only supports pre-defined rule sets out of the box so you may want to take a look at OWLIM which is an alternative back end that can be used with Sesame and has much more customisable rules AFAIK.
Inferencing can typically be applied in two ways, one where you only store the rules and you compute the additional information every time a rule fires and another where you pre-compute all the additional information and add it to your database. Which you will want to use depends on how you intend to use your system and there are performance trade offs involved. I'm not going into detail because that's really a whole other question - see Forward vs Backward Chaining for some discussion
SPARQL Update
Alternatively if your rules are relatively simple and you are OK with pre-computing the extra information and adding it to your database you can write SPARQL Updates to do this e.g.
PREFIX foo: <http://example.org/foo#>
INSERT
{
?x foo:g foo:h .
}
WHERE
{
?x foo:b foo:c .
}
Part 2 - Querying the Data
I am guessing you are fairly new to SPARQL because from what you've described this sounds trivial to me.
If I wanted to find all subjects which had the predicate foo:g and the object foo:h I would simply write the following:
PREFIX foo: <http://example.org/foo#>
SELECT ?x
WHERE
{
?x foo:g foo:h .
}
You can do this type of inference using OWL with an axiom of the form
p value a &sqsubseteq; q value b
which says that if something has a as a value for property p, then it also has b as a value for property q. As an example, here's an ontology with four individuals (a, b, c, d), two object properties (p, q), and the axiom (p value c &sqsubseteq; q value d).
#prefix : <http://example.org/add-predicate-object#> .
#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://example.org/add-predicate-object> a owl:Ontology .
:p a owl:ObjectProperty .
:q a owl:ObjectProperty .
[ a owl:Restriction ;
owl:onProperty :p ;
owl:hasValue :c ;
rdfs:subClassOf [ a owl:Restriction ;
owl:onProperty :q ;
owl:hasValue :d ] . ] .
:a a owl:Thing, owl:NamedIndividual ; :p :c .
:b a owl:Thing, owl:NamedIndividual ; :p :c .
:c a owl:Thing, owl:NamedIndividual .
:d a owl:Thing, owl:NamedIndividual .
In Protégé, the axiom looks like this:
You can enable a reasoner and query for instances of q value d and see:
or you can browse to individuals and see the results: