2

Let us consider we two classes: Person and its subclass BlondePerson. Let us consider a relationship: isParent where a Person is parent of another person. Let us define the relationship: isAncestor where there is a sequence of isParent relationships.

There might be many BlondPersons ancestor of me.

My question: how to write a SPARQL query so I learn the closest ancestor who is blond. The closest means my parent if possible, if not the grandparents, otherwise grandgrandparents and so on.

How to compose a SPARQL query for that? How to assure that I will get the ancestor who it the closest one?

Thank you.

Karel Macek
  • 878
  • 1
  • 9
  • 21

1 Answers1

3

This isn't too hard; you can use the same technique demonstrated in Is it possible to get the position of an element in an RDF Collection in SPARQL?. The idea is essentially to treat the ancestry as a sequence, from which you can get the "closeness" of each ancestor, and select the closest ancestor from a given class. If we create some sample data, we end up with something like this:

@prefix : <urn:ex:>

:a a :Person ; :hasParent :b .
:b a :Person ; :hasParent :c .
:c a :Person, :Blond ; :hasParent :d .
:d a :Person, :Blond ; :hasParent :e .
:e a :Person .
prefix : <urn:ex:>

select distinct
  ?person
  ?ancestor
  (count(distinct ?mid) as ?closeness)
  ?isBlond
where {
  values ?person { :a }
  ?a :hasParent+ ?mid .
  ?mid a :Person .
  ?mid :hasParent* ?ancestor .
  ?ancestor a :Person .
  bind( if( exists { ?ancestor a :Blond }, true, false ) as ?isBlond )
}
group by ?person ?ancestor ?isBlond
order by ?person ?closeness
-------------------------------------------
| person | ancestor | closeness | isBlond |
===========================================
| :a     | :b       | 1         | false   |
| :a     | :c       | 2         | true    |
| :a     | :d       | 3         | true    |
| :a     | :e       | 4         | false   |
-------------------------------------------

That's actually more information than we needed, I just included it to show how this works. Now we can actually just require that ?ancestor is blond, order by closeness, and limit the results to the first (and thus the closest):

prefix : <urn:ex:>

select distinct
  ?person
  ?ancestor
  (count(distinct ?mid) as ?closeness)
where {
  values ?person { :a }
  ?a :hasParent+ ?mid .
  ?mid a :Person .
  ?mid :hasParent* ?ancestor .
  ?ancestor a :Person, :Blond .
}
group by ?person ?ancestor
order by ?person ?closeness
limit 1
---------------------------------
| person | ancestor | closeness |
=================================
| :a     | :c       | 2         |
---------------------------------
Community
  • 1
  • 1
Joshua Taylor
  • 80,876
  • 9
  • 135
  • 306