Skip to content

Instantly share code, notes, and snippets.

@jindrichmynarz
Created February 24, 2018 18:20
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jindrichmynarz/c2e332d5ab35b47d95f17bb78dfccc07 to your computer and use it in GitHub Desktop.
Save jindrichmynarz/c2e332d5ab35b47d95f17bb78dfccc07 to your computer and use it in GitHub Desktop.
Recursive concise bounded description
# SPARQL 1.1 implementation of concise bounded description (<https://www.w3.org/Submission/CBD>).
PREFIX : <http://example.com/>
PREFIX non: <http://non/>
CONSTRUCT {
:resource ?p1 ?r1 .
?r2 ?p2 ?r3 .
}
WHERE {
# :resource is the IRI of the resource we want to describe.
:resource ?p1 ?r1 .
OPTIONAL {
# Since variables cannot be used in SPARQL 1.1 property paths
# we can ask for any but a (presumably) non-existent property.
# We use zero or more quantifier (i.e. "*") to recursively
# expand to blank node neighbourhood.
?r1 (!non:existent)* ?r2 .
FILTER (isBlank(?r1) && isBlank(?r2))
?r2 ?p2 ?r3 .
}
}
@prefix : <http://example.com/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
:resource a :C ;
:p1 [
a :D ;
:p2 [
a :E
]
] .
:C a rdfs:Class .
:D a rdfs:Class .
:E a rdfs:Class .
@klinovp
Copy link

klinovp commented Feb 24, 2018

No, not really. The problem is that ?r1 (!non:existent)* ?r2 would also match pairs of bnodes which are connected via IRI nodes, while you want bnode-only paths. Counter example:

insert data { <urn:X> <urn:p> _:b1 . _:b1 <urn:p> <urn:Y> . <urn:Y> <urn:p> _:b2 . _:b2 <urn:p> <urn:Z> . }

Results for <urn:X>:

<urn:X> <urn:p> _:b1 .
_:b1 <urn:p> <urn:Y> .
_:b2 <urn:p> <urn:Z> .

@VladimirAlexiev
Copy link

Furthermore this is completely be impractical on any but the tiniest stores

@jindrichmynarz
Copy link
Author

jindrichmynarz commented Feb 24, 2018

How about restricting the paths between ?r1 and ?r2 to blank nodes only?

PREFIX :    <http://example.com/>
PREFIX non: <http://non/>

CONSTRUCT {
  <urn:X> ?p1 ?r1 .
  ?r2 ?p2 ?r3 .
}
WHERE {
  <urn:X> ?p1 ?r1 
  OPTIONAL {
    ?r1 (!non:existent)* ?r2 .
    FILTER (isBlank(?r1) && isBlank(?r2))
    FILTER NOT EXISTS {
      ?r1 (!non:existent)+ ?mid .
      ?mid (!non:existent)* ?r2 .
      FILTER (!isBlank(?mid))
    }
    ?r2 ?p2 ?r3 .
  }
}

Returns the following for the example data (using Jena ARQ version 3.3.0):

<urn:X>  <urn:p>  [ <urn:p>  <urn:Y> ] .

Regarding the impracticality for real data, this is only an exploration of an idea. I haven't tried it with non-toy data.

@klinovp
Copy link

klinovp commented Feb 24, 2018

OK, start with crazy and then double down -- I like it! =)
I can't check at the moment but you may try ARQ on this:

<urn:X> <urn:p> _:b1 .
 _:b1 <urn:p> <urn:Y>, _:b2 . 
<urn:Y> <urn:p> _:b2 . 
_:b2 <urn:p> <urn:Z> .

I think your mid-point filter might now break the _:b1 -> _:b2 path because there's an alternative path via :Y. But it's late and I could easily be wrong.

@jindrichmynarz
Copy link
Author

You're right. Again, there are corner cases that break the query. There's no free lunch.

@klinovp
Copy link

klinovp commented Feb 25, 2018

Yeah. This is the main reason we implemented SPARQL-style path queries in Stardog. Traversals are hard in pure SPARQL.

@jindrichmynarz
Copy link
Author

I don't see the correspondence between recursive CBD and Stardog path queries. Is it possible to implement the recursive CBD in Stardog-flavoured SPARQL?

@ktk
Copy link

ktk commented Feb 26, 2018

We plan to use PATH for that but from what I know we cannot use it in sub-selects right now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment