How to rank values in SPARQL?

2020-06-23 08:53发布

问题:

I would like to create a ranking of observations using SPARQL. Suppose I have:

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

:A :value 60 .
:B :value 23 .
:C :value 89 .
:D :value 34 .

The ranking should be: :C = 1 (the highest), :A = 2, :D = 3, :B = 4. Up until now, I was able solve it using the following query:

prefix : <http://example.org#> 
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

SELECT ?x ?v ?ranking { 
 ?x :value ?v .
 { SELECT (GROUP_CONCAT(?x;separator="") as ?ordered) {
    { SELECT ?x {
       ?x :value ?v .
      } ORDER BY DESC(?v)
    }
   }
 }
 BIND (str(?x) as ?xName)
 BIND (strbefore(?ordered,?xName) as ?before) 
 BIND ((strlen(?before) / strlen(?xName)) + 1 as ?ranking)
} ORDER BY ?ranking

But that query only works if the URIs for ?x have the same length. A better solution would be to have a function similar to strpos in PHP or isIndexOf in Java, but as far as I know, they are not available in SPARQL 1.1. Are there simpler solutions?

回答1:

One way of doing this is to take as the ranking for a value the number of values which are less than or equal to it. This might be inefficient for larger data sets, since for each value it has to check all the other values. It doesn't require string manipulation though.

PREFIX : <http://example.org#>

SELECT ?x ?v (COUNT(*) as ?ranking) WHERE {
  ?x :value ?v .
  [] :value ?u .
  FILTER( ?v <= ?u )
}
GROUP BY ?x ?v
ORDER BY ?ranking

---------------------
| x  | v  | ranking |
=====================
| :C | 89 | 1       |
| :A | 60 | 2       |
| :D | 34 | 3       |
| :B | 23 | 4       |
---------------------


标签: sparql