Reputation: 97
I have a hierarchy of skos concepts and some individuals indexed by those concepts (for example ex:Regina dct:subject ex:Pizza
).
I want to find every individuals indexed by some concepts (or more specific ones). The query below retrieves every meal that is a pizza or homemade. (I'm using the concat
and group_concat
to easily get the concepts of the meals in one row)
select ?ind ?name (group_concat(concat(str(?concept),':',?conceptName)) as ?concepts){
?ind a ex:Individual.
?ind skos:prefLabel ?name.
?ind dct:subject ?concept.
?concept skos:prefLabel ?conceptName.
optional{?ind dct:subject [skos:broaderTransitive* ex:Pizza].}
optional{?ind dct:subject [skos:broaderTransitive* ex:Homemade].}
}
group by ?ind ?name
This is great, but now I would like to rank those results according to the numbers of concepts they have in common with what I want. So in my example I would like the homemade pizzas first, then only pizzas or homemade meals.
I would also like to get rid of results having none of the concepts I'm interested in.
Ideally, I would also like that meals directly indexed by the desired concept have a higher score than the one being indexed by more specific concepts.
I could postprocess the results of course, but I'm pretty sure there is a clever and efficient way to do it in sparql. Any idea ?
EDIT : Sample data as per request
@prefix : <http://www.semanticweb.org/owl/owlapi/turtle#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix xml: <http://www.w3.org/XML/1998/namespace> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
@prefix dct: <http://purl.org/dc/terms/> .
@prefix ex: <http://example.com#> .
ex:FoodScheme a skos:ConceptScheme ;
skos:prefLabel "The food schema"@en ;
skos:hasTopConcept ex:Food .
ex:Food a skos:Concept ;
skos:prefLabel "Food"@en ;
skos:inScheme ex:FoodScheme .
ex:Italian a skos:Concept ;
skos:prefLabel "Italian food"@en ;
skos:broaderTransitive ex:Food ;
skos:inScheme ex:FoodScheme .
ex:Pizza a skos:Concept ;
skos:prefLabel "Pizza"@en ;
skos:broaderTransitive ex:Italian ;
skos:inScheme ex:FoodScheme .
ex:Pasta a skos:Concept ;
skos:prefLabel "Pasta"@en ;
skos:broaderTransitive ex:italian ;
skos:inScheme ex:FoodScheme .
ex:Homemade a skos:Concept ;
skos:prefLabel "Homemade food"@en ;
skos:broaderTransitive ex:Food ;
skos:inScheme ex:FoodScheme .
ex:Regina a ex:Meal ;
skos:prefLabel "Regina"@en ;
dct:subject ex:Homemade ;
dct:subject ex:Pizza.
ex:PeppyPaneer a ex:Meal ;
skos:prefLabel "From Domino's"@en ;
dct:subject ex:Pizza.
ex:Carbonara a ex:Meal ;
skos:prefLabel "Pasta a la carbonara"@en ;
dct:subject ex:Homemade ;
dct:subject ex:Pasta.
ex:Lasagna a ex:Meal ;
skos:prefLabel "Lasagna"@en ;
dct:subject ex:Italian.
Expected results for homemade pizza (Regina first, because it's homemade and a pizza, carbonara not included beacause it's neither homemade nor a pizza. The order of PeppyPaneer and Carbonara does not matter, they should have the same "score"):
ex:Regina
ex:PeppyPaneer
ex:Carbonara
Expected results for Italian (Lasagna first because it is directly indexed as Italian while the others are not):
ex:Lasagna
ex:Carbonara
ex:PeppyPaneer
ex:Regina
Upvotes: 1
Views: 363
Reputation: 8465
Given a set of relevant subjects { ex:Pizza ex:Homemade }
, we can do:
PREFIX ex: <http://example.com#>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
SELECT ?ind ?name (GROUP_CONCAT(DISTINCT ?conceptStr) AS ?concepts) (COUNT(DISTINCT ?cls) AS ?score)
WHERE
{ ?ind skos:prefLabel ?name ;
dct:subject ?concept .
?concept skos:prefLabel ?conceptName
BIND(concat(str(?concept), ":", ?conceptName) AS ?conceptStr)
OPTIONAL
{ VALUES ?cls { ex:Pizza ex:Homemade }
?ind dct:subject/(skos:broaderTransitive)* ?cls
}
}
GROUP BY ?ind ?name
HAVING ( ?score > 0 )
ORDER BY DESC(?score)
+-----------------+-------------------------+--------------------------------------------------------------------------+-------+
| ind | name | concepts | score |
+-----------------+-------------------------+--------------------------------------------------------------------------+-------+
| ex:Regina | Regina en | http://example.com#Pizza:Pizza http://example.com#Homemade:Homemade food | 2 |
| ex:Carbonara | Pasta a la carbonara en | http://example.com#Pasta:Pasta http://example.com#Homemade:Homemade food | 1 |
| ex:PeppyPaneer | From Domino's en | http://example.com#Pizza:Pizza | 1 |
+-----------------+-------------------------+--------------------------------------------------------------------------+-------+
Upvotes: 3