1

I'm trying to return subjects based on the relative position of their subjects in an ordered list.

A subject can be associated with multiple objects (via a single predicate) and all objects are in an ordered list. Given a reference object in this list I'd like to return the subjects in order of relative distance of their objects from the reference object.

:a : :x     
:b : :v
:b : :z
:c : :v
:c : :y

:ls :list (:v :w :x :y :z)

Taking x as our starting object in the list, the code below returns

:a :x :0
:c :y :1
:b :v :2
:b :z :2
:c :v :2

Instead of returning all positions I would like only the objects relating to the subject's minimum object 'distance' to be returned (which may mean up to two objects per subject - both up and down the list). So I'd like to return

:a :x :0
:c :y :1
:b :v :2
:b :z :2

The code so far... (with a lot of help from Find lists containing ALL values in a set? and Is it possible to get the position of an element in an RDF Collection in SPARQL?)

SELECT ?s ?p (abs(?refPos-?pos) as ?dif) 
WHERE {
      :ls :list/rdf:rest*/rdf:first ?o .
      ?s : ?o .
      {
      SELECT ?o (count(?mid) as ?pos) ?refPos 
      WHERE {
            [] :list/rdf:rest* ?mid . ?mid rdf:rest* ?node .
            ?node rdf:first ?o .
            {
            SELECT ?o (count(?mid2) as ?refPos)
            WHERE {
                  [] :list/rdf:rest* ?mid2 . ?mid2 rdf:rest* ?node2 .
                  ?node2 rdf:first :x .
                  }
            }
            }
            GROUP BY ?o
      }
      }
      GROUP BY ?s ?o
      ORDER BY ?dif

I've been trying to get a minimum ?dif (difference/distance) by grouping by ?s but because I then have to apply this (something like ?dif = ?minDif) to the ?s ?o grouping from earlier I don't know how to go back and forward between these two groupings.

Thanks for any assistance you can provide

Stanislav Kralin
  • 10,115
  • 4
  • 30
  • 52
  • 2
    Are you sure that this is a proper use case for SPARQL? Sounds more like graph traversal engines like Cypher or Gremlin would work better here. – UninformedUser Apr 25 '18 at 08:33
  • Thanks for those recommendations @AKSW. I wanted to incorporate the hierarchy a list provides into my SPARQL queries, but I'll look into graph traversal engines if I continue with this approach. – user9175828 Apr 27 '18 at 04:12

1 Answers1

1

All you needed to compound a solution is yet another one Joshua Taylor's answer: this or this.

Here below I'm using Jena functions, but I hope the idea is clear.

Query 1

PREFIX list: <http://jena.hpl.hp.com/ARQ/list#>
SELECT ?s ?el ?dif {
    ?s : ?el .
    :ls :list/list:index (?pos ?el) .
    :ls :list/list:index (?ref :x) .
    BIND (ABS(?pos -?ref) AS ?dif) 
    {
    SELECT ?s (MIN (?dif_) AS ?dif) WHERE {
        ?s : ?el_ .
        :ls :list/list:index (?pos_ ?el_) .
        :ls :list/list:index (?ref_ :x) .
        BIND (ABS(?pos_ - ?ref_) AS ?dif_)
        } GROUP by ?s
    }
}

Query 2

PREFIX list: <http://jena.apache.org/ARQ/list#>    
SELECT ?s ?el ?dif {
    ?s : ?el .
    :ls :list/list:index (?pos ?el) .
    :ls :list/list:index (?ref :x) .
    BIND (ABS(?pos -?ref) AS ?dif) 
    FILTER NOT EXISTS {
        ?s : ?el_ .
        :ls :list/list:index (?pos_ ?el_) .
        BIND (ABS(?pos_ - ?ref) AS ?dif_) .
        FILTER(?dif_ < ?dif)                                           
    }
}

Update

Query 1 can be rewritten in this way:

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

SELECT ?s ?el ?dif {
  ?s : ?el 
  { select (count(*) as ?pos) ?el {[] :list/rdf:rest*/rdf:rest*/rdf:first ?el} group by ?el }
  { select (count(*) as ?ref)     {[] :list/rdf:rest*/rdf:rest*/rdf:first :x} } 
  BIND (ABS(?pos - ?ref) AS ?dif) 
  {
  SELECT ?s (MIN(?dif_) AS ?diff) {
    ?s : ?el_ 
    { select (count(*) as ?pos_) ?el_ {[] :list/rdf:rest*/rdf:rest*/rdf:first ?el_} group by ?el_ }
    { select (count(*) as ?ref_)      {[] :list/rdf:rest*/rdf:rest*/rdf:first :x} } 
    BIND (ABS(?pos_ - ?ref_) AS ?dif_)
    } GROUP by ?s
  }
  FILTER (?dif = ?diff)
}

Notes

  • As you can see, this is not what SPARQL was designed for. For example, Blazegraph supports Gremlin...
  • Possibly this is not what RDF was designed for. Or try other modeling approach: do you really need RDF lists?
  • I haven't tested the above query in Virtuoso.
Stanislav Kralin
  • 10,115
  • 4
  • 30
  • 52
  • Thanks @Stanislav Kralin, I've just been playing with straight SPARQL (hence the verbose position queries). – user9175828 Apr 26 '18 at 08:07
  • Thanks again @Stanislav Kralin. I just wanted to explore some data using the hierarchy the list provides (while becoming more familiar with SPARQL). If it looks promising and I continue with this approach I'll check out Gremlin. Also, I was just running these queries in RDFLib and they all work fine. – user9175828 Apr 27 '18 at 04:09