7
2

Inspired by a few related questions (in particular this one), I wanted to ask a more general form of the question: how can I specify preferences for basic graph pattern matching in SPARQL (1.1) such that potentially many lower preferences are only matched if a higher preference cannot be found?

It seems there are a few potential solutions and I hope to gather some alternative patterns, some of which may work best in different concrete scenarios.

To make the general question concrete, but in a way that can easily be generalised, say I want to get the labels of each resource of type foaf:Person where, in order, I prefer the values from the following predicates:

  1. foaf:name
  2. skos:prefLabel
  3. skos:altLabel
  4. rdfs:label
  5. (potentially more)

The basic query in SPARQL would be:

PREFIX ...
SELECT ?person ?name
WHERE {
  ?person a foaf:Person ; foaf:name ?name .
}

How can this query be adapted to return names from predicates in the above preference order such that values for a given predicate are only returned if no value is returned for a higher-preference predicate? (I.e., if we find a foaf:name that suffices, else if we find a skos:prefLabel that suffices, else ...).

asked 30 Jan '13, 15:27

Signified's gravatar image

Signified ♦
23.7k1623
accept rate: 37%

edited 31 Jan '13, 13:39

I'm particularly (but not solely) interested in a pattern that uses something like VALUES (?p ?pref) { (foaf:name 1) (skos:prefLabel 2) (skos:altLabel 3) (rdfs:label 4) ... } to specify the ordering. I thought this would be relatively straightforward, but it's difficult to make VALUES play nice with sub-queries/group by/limit, etc.

(30 Jan '13, 15:31) Signified ♦ Signified's gravatar image
1

What if it finds multiple foaf:names?

(30 Jan '13, 21:48) utapyngo utapyngo's gravatar image

I would leave that open ... i.e., I'd take answers for patterns that either (i) only return one value or (ii) return all values for the preferred predicate.

(It shouldn't be so difficult to get the (i) from the (ii) using GROUP BY/SAMPLE with a nested sub-query.)

(30 Jan '13, 22:39) Signified ♦ Signified's gravatar image

We find the subjects and properties, with preference numbering. We then check to see there isn't a better match.

Data:

@prefix : <http://example/> .

:s1 :name1 "s11" . :s1 :name2 "s12" .
:s2 :name2 "s22" .
:s3 :name1 "s31" .

Query:

PREFIX :        <http://example/>
SELECT ?x ?p ?o ?pref
{
   VALUES (?p ?pref) { (:name1 10) (:name2 20) }
   ?x ?p ?o
   FILTER NOT EXISTS {
     VALUES (?p2 ?pref2) { (:name1 10) (:name2 20 ) }
     ?x ?p2 ?o2
     FILTER( ?pref2 > ?pref)
   }
} ORDER BY str(?x)

Results:

-------------------------------
| x   | p      | o     | pref |
===============================
| :s1 | :name2 | "s12" | 20   |
| :s2 | :name2 | "s22" | 20   |
| :s3 | :name1 | "s31" | 10   |
-------------------------------
link

answered 31 Jan '13, 13:28

AndyS's gravatar image

AndyS ♦
13.2k37
accept rate: 32%

A sequence of OPTIONALs gets a sort of conditional testing but it does not allow the input from VALUES or the rest of the query.

SELECT *
{
  ?person a foaf:Person .
  OPTIONAL { ?person foaf:name      ?X  }
  OPTIONAL { ?person skos:prefLabel ?X  }
  OPTIONAL { ?person skos:altLabel  ?X  }
  OPTIONAL { ?person rdfs:label     ?X  }
}

To allow the input to be defined not by the syntax order (returns one value at the top pref level):

SELECT *
{
  VALUES (?p ?pref) { 
       (foaf:name 1) (skos:prefLabel 2) 
       (skos:altLabel 3) (rdfs:label 4) 
   }

  ?person a foaf:Person .
  ?person ?p ?o 
} ORDER BY ?pref LIMIT 1

Given that used as a subquery, you can use it to get the ?p and all all ?person ?p is you want all values.

link

answered 31 Jan '13, 05:05

AndyS's gravatar image

AndyS ♦
13.2k37
accept rate: 32%

+1 That second solution is really rather neat

(31 Jan '13, 08:02) Rob Vesse ♦ Rob%20Vesse's gravatar image

+1 for the first solution.

Regarding the second solution, I was thinking along similar lines, but even as a sub-query, doesn't it mean that you only get one name for one person and not one name for each person?

For testing:

PREFIX dc:      <http://purl.org/dc/elements/1.1/>
SELECT *
WHERE
{    SELECT *
     {
       VALUES (?p ?pref) { 
          (dc:title 1) (dc:creator 2) 
       }
       ?book ?p ?label .
     } ORDER BY ?pref LIMIT 1 
}

Against: http://sparql.org/query.html

Returns one result for one book.

(31 Jan '13, 12:34) Signified ♦ Signified's gravatar image

Ok, you want more than a single item -- the data in /books isn't rich enough for testing. We need the old maximum trick ... updated to SPARQL 1.1. And a new answer.

(31 Jan '13, 13:19) AndyS ♦ AndyS's gravatar image

A variation on the OPTIONAL pattern is as follows:

SELECT *
{
  ?person a foaf:Person .
  OPTIONAL { ?person foaf:name      ?x1  }
  OPTIONAL { ?person skos:prefLabel ?x2  }
  OPTIONAL { ?person skos:altLabel  ?x3  }
  OPTIONAL { ?person rdfs:label     ?x4  }
  BIND(COALESCE(?x1, ?x2, ?x3, ?x4) AS ?x)
}

This may be useful if you want to provide a fallback default in the absence of any of the preferred matches being found e.g.

SELECT *
{
  ?person a foaf:Person .
  OPTIONAL { ?person foaf:name      ?x1  }
  OPTIONAL { ?person skos:prefLabel ?x2  }
  OPTIONAL { ?person skos:altLabel  ?x3  }
  OPTIONAL { ?person rdfs:label     ?x4  }
  BIND(COALESCE(?x1, ?x2, ?x3, ?x4, "Unknown") AS ?x)
}
link

answered 31 Jan '13, 08:04

Rob%20Vesse's gravatar image

Rob Vesse ♦
13.7k1715
accept rate: 29%

2

Good point about COALESCE to add a default.

Use different variables does mean that the cardinality of each match shows through. The idea of using the same variable is that once found, the later OPTIONALs either match once (single triple, all slots fixed) or don't, so don't change the row count.

(31 Jan '13, 08:50) AndyS ♦ AndyS's gravatar image

Yes I did realize that, I suspect your VALUES within a subquery is almost certainly the nicest solution regardless

(31 Jan '13, 09:34) Rob Vesse ♦ Rob%20Vesse's gravatar image

+1 since I think the cardinality issue (i.e., returning multiple values for the preferred predicate) could be a feature not a bug in certain scenarios.

(31 Jan '13, 12:29) Signified ♦ Signified's gravatar image
Your answer
toggle preview

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Markdown Basics

  • *italic* or _italic_
  • **bold** or __bold__
  • link:[text](http://url.com/ "Title")
  • image?![alt text](/path/img.jpg "Title")
  • numbered list: 1. Foo 2. Bar
  • to add a line break simply add two spaces to where you would like the new line to be.
  • basic HTML tags are also supported

Tags:

×1,264
×104

Asked: 30 Jan '13, 15:27

Seen: 954 times

Last updated: 07 Mar, 09:46