Blank node skolemization in SPARQL without iteration - sparql

Is it possible to implement blank node skolemization in SPARQL without iteration? It seems to me that iteration is required to skolemize chains of blank nodes, such as:
#prefix : <http://example.com/> .
[ a :A ;
:p1 [
a :B
]
] .
A SPARQL Update operation for skolemization can start from the blank nodes that appear as subjects only in triples without blank node objects:
DELETE {
?b1 ?outP ?outO .
?inS ?inP ?b1 .
}
INSERT {
?iri ?outP ?outO .
?inS ?inP ?iri .
}
WHERE {
{
SELECT ?b1 (uuid() AS ?iri)
WHERE {
{
SELECT DISTINCT ?b1
WHERE {
?b1 ?p1 [] .
FILTER isBlank(?b1)
FILTER NOT EXISTS {
?b1 ?p2 ?b2 .
FILTER isBlank(?b2)
}
}
}
}
}
?b1 ?outP ?outO .
OPTIONAL {
?inS ?inP ?b1 .
}
}
This operation can be repeated until no blank nodes are found in the data:
ASK {
?bnode ?p [] .
FILTER isBlank(?bnode)
}
Is it possible to avoid the iteration and implement the blank node skolemization in a single SPARQL Update operation?
(Also, this approach assumes there are no "orphan" blank nodes (i.e. blank nodes that appear only as objects).)

I found a two-step solution skolemising subjects and objects separately and storing the blank node aliases (links between blank nodes and IRIs via owl:sameAs) as intermediate data:
PREFIX : <http://example.com/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
####################
# Rewrite subjects #
####################
DELETE {
?bnode ?p ?o .
}
INSERT {
?iri ?p ?o .
GRAPH :aliases {
?bnode owl:sameAs ?iri .
}
}
WHERE {
{
SELECT ?bnode (uuid() AS ?iri)
WHERE {
{
SELECT DISTINCT ?bnode
WHERE {
?bnode ?p [] .
FILTER isBlank(?bnode)
}
}
}
}
?bnode ?p ?o .
}
;
###################
# Rewrite objects #
###################
DELETE {
?s ?p ?bnode .
}
INSERT {
?s ?p ?iri .
}
WHERE {
{
SELECT ?bnode ?iri
WHERE {
{
SELECT DISTINCT ?bnode
WHERE {
[] ?p ?bnode .
FILTER isBlank(?bnode)
}
}
OPTIONAL {
GRAPH :aliases {
?bnode owl:sameAs ?_iri .
}
}
BIND (coalesce(?_iri, uuid()) AS ?iri)
}
}
?s ?p ?bnode .
}
;
############################
# Clear blank node aliases #
############################
CLEAR GRAPH :aliases

Related

SPARQL Blank node skolemization with incremental Variable

I am trying to execute Blank node skolemization on a graph using an incremental variable for the identifier, however, the urn:count object is not being updated.
I have the following code so far.
PREFIX : <http://example.com/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
####################
# Create Counter Graph #
####################
INSERT DATA {
graph <urn:counters> {<urn:Example> <urn:count> 1 }
}
;
####################
# Rewrite objects #
####################
DELETE {
#remove the old value of the counter
graph <urn:counters> {<urn:Example> <urn:count> ?old}
?s ?p ?bnode .
}
INSERT {
#update the new value of the counter
graph <urn:counters> {<urn:Example> <urn:count> ?new}
?s ?p ?iri .
GRAPH :aliases {
?bnode owl:sameAs ?iri .
}
}
WHERE {
{
SELECT ?bnode ?iri ?new ?old
WHERE {
{
SELECT DISTINCT ?bnode
WHERE {
[] ?p ?bnode .
FILTER isBlank(?bnode)
}
}
# retrieve the counter
graph <urn:counters> {<urn:Example> <urn:count> ?old}
# compute the new value
bind(?old+1 as ?new)
#construct the IRI
bind(IRI(concat("http://example.org/item/", str(?old))) as ?iri)
}
}
?s ?p ?bnode .
}
;
Which produces the following output.
<#TripleMap1>
rr:logicalTable <http://example.org/item/1> ;
rr:predicateObjectMap <http://example.org/item/1> ;
rr:subjectMap <http://example.org/item/1> .
However I would like the output as follows.
<#TripleMap1>
rr:logicalTable <http://example.org/item/1> ;
rr:predicateObjectMap <http://example.org/item/2> ;
rr:subjectMap <http://example.org/item/3> .
And the input graph is as follows.
#prefix rr: <http://www.w3.org/ns/r2rml#> .
<#TripleMap1>
rr:logicalTable [] ;
rr:predicateObjectMap [];
rr:subjectMap [];
Any help would be appreciated.

Is there a WITH clause in SPARQL?

Is there any analog of view creation or WITH clause from SQL in SPARQL?
I want to:
Select some data from table;
Select data which is not in the first selection (by subject) from the same table.
This seems to work without "WITH" but i do two similar SELECT query:
SELECT *
FROM NAMED <http://...>
{
{
SELECT DISTINCT ?s ?p ?o
WHERE {
BIND (<http://www.w3.org/2004/02/skos/core#prefLabel> AS ?p)
{ ?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2004/02/skos/core#Concept> . }
FILTER(LANGMATCHES(LANG(?o), "ru"))
}
ORDER BY ?o
}
UNION
{
SELECT DISTINCT ?s ?p ?o
WHERE {
BIND (<http://www.w3.org/2004/02/skos/core#prefLabel> AS ?p)
{ ?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2004/02/skos/core#Concept> . }
FILTER(LANGMATCHES(LANG(?o), "en"))
MINUS {
SELECT DISTINCT ?s
WHERE {
BIND (<http://www.w3.org/2004/02/skos/core#prefLabel> AS ?p)
{ ?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2004/02/skos/core#Concept> . }
FILTER(LANGMATCHES(LANG(?o), "ru"))
}
}
}
ORDER BY ?o
}
}

SPARQL DBpedia by taxonomic term

Have the following working SPARQL query that selects items from DBpedia that include the string "fish" in their name.
SELECT ?name, ?kingdom, ?phylum, ?class, ?order, ?family, ?genus, ?species, ?subspecies, ?img, ?abstract
WHERE {
?s dbpedia2:regnum ?hasValue;
rdfs:label ?name
FILTER regex( ?name, "fish", "i" )
FILTER ( langMatches( lang( ?name ), "EN" ))
?animal dbpedia2:name ?name;
foaf:depiction ?img;
dbpedia2:regnum ?kingdom
OPTIONAL { ?animal dbpedia2:ordo ?order . }
OPTIONAL { ?animal dbpedia2:phylum ?phylum . }
OPTIONAL { ?animal dbpedia2:classis ?class . }
OPTIONAL { ?animal dbpedia2:familia ?family . }
OPTIONAL { ?animal dbpedia2:genus ?genus . }
OPTIONAL { ?animal dbpedia2:species ?species . }
OPTIONAL { ?animal dbpedia2:subspecies ?subspecies . }
OPTIONAL {
FILTER ( langMatches( lang( ?abstract ), "EN" ))
}
}
GROUP BY ?name
LIMIT 500
Here is the result on SNORQL.
This approach finds animals with the word "fish" in their name (example: "starfish" which is not a fish but member of the phylum Echinoderm).
Would like a more precise query that selects DBpedia items by phylum, or by class, or by order, etc.
How to change the query to search only on dbpedia2:phylum (Chordata); on dbpedia2:classis (Actinopterygii); on dbpedia2:familia; etc. ?
Looking at Tuna, I see that there is a rdf:type assertion for the class
http://umbel.org/umbel/rc/Fish
that looks useful. E.g.,
select ?fish { ?fish a <http://umbel.org/umbel/rc/Fish> }
SPARQL results (10,000)
There's also the dbpedia-owl:Fish class, which gets more results:
select (count(*) as ?nFish) where {
?fish a dbpedia-owl:Fish .
}
SPARQL results (17,420)
While Wikipedia has lots of scientific classification information, I don't see much of it reflected in DBpedia. E.g,. while the Wikipedia article for Tuna has kingdom, phylum, class, order, etc., I don't see that data in the corresponding DBpedia resource.
Notes
Note that your query, as written, isn't actually legal SPARQL (even if Virtuoso, the SPARQL endpoint that DBpedia uses, accepts it). You can't have commas between the projection variables. Also, once you group by one variable, the non-group variables can't appear in the variable list. You could sample the other values though. E.g., you should end up with something like:
SELECT
?name
(sample(?kingdom) as ?kingdom_)
(sample(?phylum) as ?phylum_)
#-- ...
(sample(?img) as ?img_)
(sample(?abstract) as ?abstract_)
WHERE {
?s dbpedia2:regnum ?hasValue;
rdfs:label ?name
FILTER regex( ?name, "fish", "i" )
FILTER ( langMatches( lang( ?name ), "EN" ))
?animal dbpedia2:name ?name;
foaf:depiction ?img;
dbpedia2:regnum ?kingdom
OPTIONAL { ?animal dbpedia2:ordo ?order . }
OPTIONAL { ?animal dbpedia2:phylum ?phylum . }
OPTIONAL { ?animal dbpedia2:classis ?class . }
OPTIONAL { ?animal dbpedia2:familia ?family . }
OPTIONAL { ?animal dbpedia2:genus ?genus . }
OPTIONAL { ?animal dbpedia2:species ?species . }
OPTIONAL { ?animal dbpedia2:subspecies ?subspecies . }
OPTIONAL {
FILTER ( langMatches( lang( ?abstract ), "EN" ))
}
}
GROUP BY ?name
LIMIT 500

SPARQL distinct rowcount not returning correct number

I have the following SPARQL query , please pay attention to the rowcount in the selection predicate and the group by clause at the end of the query.
I want the query to return the correct row count in every record , I noticed that the row count that is being returned is not correct meaning if there is a single record I get 1 or sometimes 2 and if there are more than 2 records , I still get a 2, basically it seems to return random value.
I know its because of some issue with my query , can someone please let me know what I might be doing wrong ? I am using Apache Jena.
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX pf: <http://jena.hpl.hp.com/ARQ/property#>
PREFIX d: <http://data-vocabulary.org/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX s: <http://schema.org/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX gr: <http://purl.org/goodrelations/v1#>
SELECT DISTINCT (count(*) AS ?rowCount) ?productName ?offerImage ?offerName ?productCategory ?salePrice ?suggestedRetailPrice ?productImage ?productThumbNail ?productUrl (GROUP_CONCAT(DISTINCT ?productdescription) AS ?productdescriptions) ?productBrand ?productId ?productSku ?productModel ?productMPN ?productManufacturer ?productGtin13 ?productGtin14 ?productGtin8 ?productAvailable ?productUnAvailable ?productUsedCondition ?productNewCondition ?productColor ?productAggregateRatingValue ?productReviewCount
WHERE
{
?p2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> d:Product .
?p2 <http://data-vocabulary.org/Product/offerDetails> ?schOffer .
?schOffer <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> d:Offer .
?schOffer <http://data-vocabulary.org/Offer/price> ?salePrice
OPTIONAL
{ ?schOffer <http://data-vocabulary.org/Offer/name> ?offerName }
OPTIONAL
{ ?p2 <http://data-vocabulary.org/Product/name> ?productName }
OPTIONAL
{ ?schOffer <http://data-vocabulary.org/Offer/image> ?offerImage }
OPTIONAL
{ ?p2 <http://data-vocabulary.org/Product/url> ?productUrl }
OPTIONAL
{ ?p2 <http://data-vocabulary.org/Product/image> ?productImage }
OPTIONAL
{ ?schOffer <http://data-vocabulary.org/Offer/category> ?productCategory }
OPTIONAL
{ ?p2 <http://data-vocabulary.org/Product/description> ?productdescription }
OPTIONAL
{ ?p2 <http://data-vocabulary.org/Product/brand> ?pBrandNode
OPTIONAL
{ ?pBrandNode <http://data-vocabulary.org/Brand/name> ?brandNodeName }
OPTIONAL
{ ?pBrandNode <http://data-vocabulary.org/Organization/name> ?brandNodeName }
BIND(str(coalesce(?brandNodeName, ?pBrandNode)) AS ?productBrand)
}
OPTIONAL
{ ?p2 <http://data-vocabulary.org/Product/manufacturer> ?pManufacturerNode
OPTIONAL
{ ?pManufacturerNode <http://data-vocabulary.org/manufacturer/name> ?manufacturerNodeName }
BIND(str(coalesce(?manufacturerNodeName, ?pManufacturerNode)) AS ?productManufacturer)
}
OPTIONAL
{ ?p2 <http://schema.org/Product/aggregateRating> ?pAggregateRating
OPTIONAL
{ ?pAggregateRating <http://schema.org/AggregateRating/ratingValue> ?productAggregateRatingValue }
OPTIONAL
{ ?pAggregateRating <http://schema.org/AggregateRating/reviewCount> ?productReviewCount }
}
OPTIONAL
{ ?p2 <http://data-vocabulary.org/Product/productID> ?productId }
OPTIONAL
{ ?p2 <http://data-vocabulary.org/Product/sku> ?productSku }
OPTIONAL
{ ?p2 <http://data-vocabulary.org/Product/itemCondition> ?productNewCondition .
?productNewCondition <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> s:NewCondition
}
OPTIONAL
{ ?p2 <http://data-vocabulary.org/Product/itemCondition> ?productUsedCondition .
?productUsedCondition <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> s:UsedCondition
}
OPTIONAL
{ ?p2 <http://data-vocabulary.org/Product/gtin13> ?productGtin13 }
OPTIONAL
{ ?p2 <http://data-vocabulary.org/Product/gtin14> ?productGtin14 }
OPTIONAL
{ ?p2 <http://data-vocabulary.org/Product/gtin8> ?productGtin8 }
OPTIONAL
{ ?schOffer <http://data-vocabulary.org/Offer/availability> ?productAvailable
FILTER ( ?productAvailable = s:InStock )
}
OPTIONAL
{ ?schOffer <http://data-vocabulary.org/Offer/availability> ?productUnAvailable
FILTER ( ?productUnAvailable = s:OutOfStock )
}
OPTIONAL
{ ?p2 <http://data-vocabulary.org/Product/model> ?productModel }
OPTIONAL
{ ?p2 <http://data-vocabulary.org/Product/mpn> ?productMPN }
OPTIONAL
{ ?p2 <http://data-vocabulary.org/Product/color> ?productColor }
}
GROUP BY ?productName ?offerImage ?offerName ?productCategory ?salePrice ?suggestedRetailPrice ?productImage ?productThumbNail ?productUrl ?productBrand ?productId ?productSku ?productModel ?productMPN ?productManufacturer ?productGtin13 ?productGtin14 ?productGtin8 ?productAvailable ?productUnAvailable ?productUsedCondition ?productNewCondition ?productColor ?productAggregateRatingValue ?productReviewCount
It is saying that the pattern you have more than one item in a group. Try running without the count and group by and look at the results where you get 2.

UNION operator in SPARQL updates

I have two SPARQL updates.First one:
INSERT
{ GRAPH <[http://example/bookStore2]> { ?book ?p ?v } }
WHERE
{ GRAPH <[http://example/bookStore]>
{ ?book dc:date ?date .
FILTER ( ?date > "1970-01-01T00:00:00-02:00"^^xsd:dateTime )
?book ?p ?v
} }
Second:
INSERT
{ GRAPH <[http://example/bookStore2]> { ?book ?p ?v } }
WHERE
{ GRAPH <[http://example/bookStore3]>
{ ?book dc:date ?date .
FILTER ( ?date > "1980-01-01T00:00:00-02:00"^^xsd:dateTime )
?book ?p ?v
} }
Can i combine them with the UNION operator? And if yes, is it an equivalent result? Is it possible to use UNION in SPARQL updates such as in "Select"?
AndyS's answer is correct; you can combine them, and the description of UNION is found in section 7 Matching Alternatives of the SPARQL specification. The combined query would be:
INSERT {
GRAPH <[http://example/bookStore2]> { ?book ?p ?v }
}
WHERE{
{
GRAPH <[http://example/bookStore]> {
?book dc:date ?date .
FILTER ( ?date > "1970-01-01T00:00:00-02:00"^^xsd:dateTime )
?book ?p ?v
}
}
UNION
{
GRAPH <[http://example/bookStore3]> {
?book dc:date ?date .
FILTER ( ?date > "1980-01-01T00:00:00-02:00"^^xsd:dateTime )
?book ?p ?v
}
}
}
In this particular case where the patterns are so similar, you could also just abstract out the differing parts with VALUES:
INSERT {
GRAPH <[http://example/bookStore2]> { ?book ?p ?v }
}
WHERE{
values (?graph ?startDate) {
(<[http://example/bookStore]> "1970-01-01T00:00:00-02:00"^^xsd:dateTime)
(<[http://example/bookStore3]> "1980-01-01T00:00:00-02:00"^^xsd:dateTime)
}
GRAPH ?graph {
?book dc:date ?date .
FILTER ( ?date > ?startDate )
?book ?p ?v
}
}
The WHERE clause is the same as SPARQL Query - you can use UNION.