Create new triplets based on a query result - sparql

[![enter image description here][1]][1][1]: https://i.stack.imgur.com/AG7MM.png
Given the following triple
I would like to get a result
:crr1 :hasPart :part1
:crr2 :hasPart :part3
I have tried currently a query below but I don't get the expected results I am trying to put a filter FILTER (?part = ?part2) over the UNION of two queries but failed to get the response I need, what am I doing wrong here?
My sole purpose with the query is to find the missing connections like in this case if CRR1 and CRR2 are connected via Part2 I would then like to create a new CRR that connects Part1 and Part3 depending upon who is the DOB in this example it is CRR1
:crr1 a :XObject .
:crr2 a :XObject .
:crr3 a :XObject .
:crr4 a :XObject .
:part1 a :Part
:part2 a :Part
:part3 a :Part
:part4 a :Part
:part5 a :Part
:crr1 :hasPart :part1 .
:crr1 :hasPart :part2 .
:crr2 :hasPart :part2 .
:crr2 :hasPart :part3 .
:crr3 :hasPart :part3 .
:crr3 :hasPart :part4 .
:crr4 :hasPart :part4 .
:crr4 :hasPart :part5 .
:crr1 :hasType :DOB .
PREFIX : <http://example.com/test#>
construct {
?o :hasPart ?part .
:crr2 :hasPart ?part2 .
}
where
{
{
?o :hasPart ?part
{
select DISTINCT ?o
where {
:crr2 (:hasPart/^:hasPart)+ ?o
FILTER (:crr2 != ?o)
}
}
FILTER EXISTS {?o :hasType :DOB .}
}
UNION
{
:crr2 :hasPart ?part2 .
}
FILTER (?part = ?part2)
}

I am not sure I understand your question properly, but let me try to answer it.
If you are looking to construct a triple between :crr1 and :part3, as the
3rd paragraph of your questions suggests, then you need something like this:
PREFIX : <http://example.com/test#>
CONSTRUCT {?dob :hasPart ?part}
WHERE {
?dob :hasType :DOB .
?dob :hasPart ?p .
?otherCRR :hasPart ?p.
FILTER(?dob != ?otherCRR)
#The above establishes whether the DOB CRR and another one are connected via any part
?otherCRR :hasPart ?part .
FILTER NOT EXISTS {?dob :hasPart ?part}
#This instead makes sure that there isn't already a connection between the DOB and the part in question.
}
If instead you are looking for the parts of :crr2 that are not shared with any other CRR where some connection exists and the other CRR is a DOB, as the 1st paragraph of your question seems to suggest, then you need something like this:
PREFIX : <http://example.com/test#>
CONSTRUCT {
?o :hasPart ?part .
:crr2 :hasPart ?part2 .
}
WHERE{
?o :hasPart ?sharedPart, ?part .
?o :hasType :DOB .
FILTER(?sharedPart != ?part)
:crr2 :hasPart ?sharedPart, ?part2 .
FILTER NOT EXISTS {?o :hasPart ?part2}
FILTER NOT EXISTS {:crr2 :hasPart ?part}
}
This returns the triples you are after.
Notice that in your filter, you say that ?part and ?part2 must be the same, so you can't have them as :part1 and :part3, respectively, in your returned triples.
It may also interest you that you can insert your triples directly into the graph with an insert query. Just replace CONSTRUCT with INSERT.

Related

How to query the path between two IRI within the same sparql endpoint

How to query the path between two IRI within the same sparql endpoint,Can I control the length and direction of the path.For example, I have some triples,input IRI_A and IRI_B,Can all the paths between IRI_A and IRI_B be detected? now i know that sparql can use this statement,However, the length and direction of the path cannot be controlled
SELECT ?s ?p ?o
WHERE {
GRAPH ?g {
BIND ( <http://localhost/XXX/IRI_A> AS ?start ) .
BIND ( <http://localhost/XXX/IRI_B> AS ?end ) .
?start (<>|!<>)* ?s .
?s ?p ?o .
?o (<>|!<>)* ?end .
}
}
I want to find all the paths between two IRIs

how to find classes from dbpedia?

I need a sparql query that given a free text (user input),
it finds me from dbpedia all the classes related to it.
How do it?
Also asked here. Accepted answer said --
When you say classes, are you mean about types? If yes, try something like
SELECT ?uri ?label ?type
WHERE {
?uri rdfs:label ?label .
?uri <http://dbpedia.org/ontology/type> ?type .
FILTER regex(str(?label), "Leipzig") .
}
limit 10
I couldn't let this go...
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX virtdrf: <http://www.openlinksw.com/schemas/virtrdf#>
SELECT ?s1c AS ?c1
COUNT (*) AS ?c2
?c3
WHERE
{
QUAD MAP virtrdf:DefaultQuadMap
{
GRAPH ?g
{
?s1 ?s1textp ?o1 .
?o1 bif:contains '"dbpedia"' .
}
}
?s1 a ?s1c .
OPTIONAL { ?s1c rdfs:label ?c3
FILTER(langMatches(LANG(?c3),"EN"))}
}
GROUP BY ?s1c ?c3
ORDER BY DESC (2) ASC (3)
The earlier answer gets you partial results.

Delete all triples about event time except earliest event time

I have several triples like this
:event1 :hasTimeStamp "2017-06-30T00:01:00Z" .
:event1 :hasTimeStamp "2017-06-30T00:02:00Z" .
:event1 :hasTimeStamp "2017-06-30T00:03:00Z" .
I would like to delete all of the assertions about :event1's timestamp except the earliest.
I know how to select the earliest, insert it into a scratch named graph, delete all :event1 timestamps, and then copy back from the scratch graph.
Is there a way to do the deletion in place, with no utilization of a temporary/scratch graph?
Here's a nested select, where the inner subselect gets the minimum time, which is then be compared with the individual times form the outer select.
Now I just have to wrap that in the delete.
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT *
WHERE
{ ?s rdf:type <http://turbo.org/procStartTimeMeas> ;
<http://purl.obolibrary.org/obo/IAO_0000136> ?something .
?something <http://purl.obolibrary.org/obo/RO_0002223> ?another .
?another rdf:type <http://turbo.org/R2RInstantiation> .
?s <http://purl.obolibrary.org/obo/IAO_0000004> ?o
{ SELECT ?s (MIN(?o) AS ?earliest)
WHERE
{ ?s rdf:type <http://turbo.org/procStartTimeMeas> ;
<http://purl.obolibrary.org/obo/IAO_0000136> ?something .
?something <http://purl.obolibrary.org/obo/RO_0002223> ?another .
?another rdf:type <http://turbo.org/R2RInstantiation> .
?s <http://purl.obolibrary.org/obo/IAO_0000004> ?o
}
GROUP BY ?s
}
FILTER ( ?o != ?earliest )
}
Try this (not in the production environment):
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
DELETE {
?s <http://purl.obolibrary.org/obo/IAO_0000004> ?o2 .
}
WHERE {
?s <http://purl.obolibrary.org/obo/IAO_0000004> ?o2 .
?s rdf:type <http://turbo.org/procStartTimeMeas> .
FILTER EXISTS {
?s <http://purl.obolibrary.org/obo/IAO_0000004> ?o1 .
?s rdf:type <http://turbo.org/procStartTimeMeas> .
FILTER (?o2 > ?o1)
}
}
I'm not sure I understand correctly what these predicates mean.
I suppose <http://purl.obolibrary.org/obo/IAO_0000004> is :hasTimeStamp of the initial example.
In my answer, ?s rdf:type <http://turbo.org/procStartTimeMeas> is the only selection criterion. Please add other criteria.
(An alternative to the nice solution of #StansilavKralin)
I just did it based on the sample data
#prefix : <http://example.org/> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
:event1 :hasTimeStamp "2017-06-30T00:01:00Z"^^xsd:dateTime .
:event1 :hasTimeStamp "2017-06-30T00:02:00Z"^^xsd:dateTime .
:event1 :hasTimeStamp "2017-06-30T00:03:00Z"^^xsd:dateTime .
Not sure whether this is what you want, but at least it's pretty compact and I'm a big fan of MINUS which is at least more human readable (but maybe less performant):
PREFIX : <http://example.org/>
DELETE {
?event :hasTimeStamp ?ts .
}
WHERE
{ ?event :hasTimeStamp ?ts
MINUS
{ { SELECT ?event (MIN(?_ts) AS ?ts)
WHERE
{ ?event :hasTimeStamp ?_ts }
GROUP BY ?event
}
}
}
I think this does what I want, but I'd like to see suggestions from others. I don't want to be reckless with a deletion.
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
DELETE {
?s <http://purl.obolibrary.org/obo/IAO_0000004> ?o .
}
WHERE
{ SELECT *
WHERE
{ ?s rdf:type <http://turbo.org/procStartTimeMeas> ;
<http://purl.obolibrary.org/obo/IAO_0000136> ?something .
?something <http://purl.obolibrary.org/obo/RO_0002223> ?another .
?another rdf:type <http://turbo.org/R2RInstantiation> .
?s <http://purl.obolibrary.org/obo/IAO_0000004> ?o
{ SELECT ?s (MIN(?o) AS ?earliest)
WHERE
{ ?s rdf:type <http://turbo.org/procStartTimeMeas> ;
<http://purl.obolibrary.org/obo/IAO_0000136> ?something .
?something <http://purl.obolibrary.org/obo/RO_0002223> ?another .
?another rdf:type <http://turbo.org/R2RInstantiation> .
?s <http://purl.obolibrary.org/obo/IAO_0000004> ?o
}
GROUP BY ?s
}
FILTER ( ?o != ?earliest )
}
}

SPARQL BIND inside UNION is too slow

Given an IMDb ID, i want to get a list of directors and actors for that movie from Wikidata.
The problem is, I want to UNION both the director and actor query into a single column while also providing a new column with the role of director or actor.
Pretty easy query overall: first I get the movie entity from the IMDb ID, then I get all the directors from that movie followed by getting all the actors from that movie and UNION them together while filling a new column (?role) with the role.
This is what I have:
PREFIX p: <http://www.wikidata.org/prop/>
PREFIX ps: <http://www.wikidata.org/prop/statement/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
SELECT ?person ?personLabel ?role ?imdb WHERE
{
?movie wdt:P345 "tt0110912" .
{ ?movie p:P57 ?cast .
?cast ps:P57 ?person .
BIND("director" as ?role) .
} UNION {
?movie p:P161 ?cast .
?cast ps:P161 ?person .
BIND("actor" as ?role) . }
?person wdt:P345 ?imdb .
OPTIONAL { ?cast prov:wasDerivedFrom ?ref . }
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?person ?personLabel ?role ?imdb
ORDER BY DESC(?role)
LIMIT 100
This works and gives the result I want, problem is it takes about 10secs. If I remove the BINDs its instant speed, but I don't get a column with the roles.
I'd write this using values instead of bind and union. The idea is that you're saying when the properties are one thing, then ?role is one thing, and when the properties are another, ?role is another. The easy way to do that with values is something like:
select ?owner ?pet ?petType {
values (?hasPet ?petType) {
(:hasCat "cat")
(:hasDog "dog")
}
?owner ?hasPet ?pet
}
In your case, this would be:
PREFIX p: <http://www.wikidata.org/prop/>
PREFIX ps: <http://www.wikidata.org/prop/statement/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
SELECT ?person ?personLabel ?role ?imdb WHERE
{
?movie wdt:P345 "tt0110912" .
values (?p ?ps ?role) {
(p:P161 ps:P161 "actor")
(p:P57 ps:P57 "director")
}
?movie ?p ?cast .
?cast ?ps ?person .
?person wdt:P345 ?imdb .
OPTIONAL { ?cast prov:wasDerivedFrom ?ref . }
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?person ?personLabel ?role ?imdb
ORDER BY DESC(?role)
LIMIT 100
When I run this at query.wikidata.org, it produces 35 results almost instantly.
I guess that BIND leads to some problems with the query optimizer. You can try as an alternative to bind the role outside of the UNION clause, i.e.
PREFIX p: <http://www.wikidata.org/prop/>
PREFIX ps: <http://www.wikidata.org/prop/statement/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
SELECT ?person ?personLabel ?role ?imdb WHERE
{
?movie wdt:P345 "tt0110912" .
?person wdt:P345 ?imdb .
{
?movie p:P57 ?c1 . ?c1 ps:P57 ?person .
?movie p:P57 ?cast .
} UNION {
?movie p:P161 ?c2 . ?c2 ps:P161 ?person .
?movie p:P161 ?cast .
}
BIND(IF(bound(?c1), "director", "actor") as ?role)
OPTIONAL { ?cast prov:wasDerivedFrom ?ref . }
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?person ?personLabel ?role ?imdb
ORDER BY DESC(?role)
LIMIT 100
(If you do not the ?ref variable, you can omit the triple patterns to retrieve the ?cast in the UNION clauses.)

After (GROUP_CONCAT can't get single results

I am not very used to SPARQL, but I managed to write my own query for books and their genres, authors and their dates of birth and death at https://query.wikidata.org
SELECT
?title ?titleLabel
(GROUP_CONCAT(DISTINCT(?authorLabel); separator="//") as ?authors)
(GROUP_CONCAT(DISTINCT(?dateborn); separator="//") as ?date_born)
(GROUP_CONCAT(DISTINCT(?datedeath); separator="//") as ?date_death)
(GROUP_CONCAT(DISTINCT(?datepub); separator="//") as ?date_pub)
(GROUP_CONCAT(DISTINCT(?genre_titleLabel); separator="//") as ?genre_title)
WHERE
{
?title wdt:P31 wd:Q571 .
?title wdt:P50 ?author .
?title wdt:P577 ?date_pub .
?author wdt:P569 ?date_born .
?author wdt:P570 ?date_death .
?title wdt:P136 ?genre_title .
BIND(CONCAT(STR(DAY(?date_pub)),"-",STR(MONTH(?date_pub)),"-",STR(YEAR(?date_pub))) AS ?datepub )
BIND(CONCAT(STR(DAY(?date_born)),"-",STR(MONTH(?date_born)),"-",STR(YEAR(?date_born))) AS ?dateborn )
BIND(CONCAT(STR(DAY(?date_death)),"-",STR(MONTH(?date_death)),"-",STR(YEAR(?date_death))) AS ?datedeath )
FILTER (?date_born > "1900-01-01T00:00:00Z"^^xsd:dateTime) .
FILTER (?date_born < "1905-12-31T23:59:59Z"^^xsd:dateTime)
SERVICE wikibase:label {
bd:serviceParam wikibase:language "en" .
?title rdfs:label ?titleLabel .
?author rdfs:label ?authorLabel .
?date_pub rdfs:label ?date_pubLabel .
?date_born rdfs:label ?date_bornLabel .
?date_death rdfs:label ?date_deathLabel .
?genre_title rdfs:label ?genre_titleLabel .
}
}
GROUP BY ?title ?titleLabel
It works and I get all the genres in the same field. The only way I could get this was with
(GROUP_CONCAT(DISTINCT(
for genres and dates. But If you loook in the results there are records with more than one date. And I want to get only the first date, and not all the stored dates in the database for this record, but I can't.
For example, If I ask for
?dateborn
instead of
(GROUP_CONCAT(DISTINCT(?dateborn); separator="//") as ?date_born)
I get an error. Do you know where is my mistake?
Greets
N.