You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@jena.apache.org by Joshua TAYLOR <jo...@gmail.com> on 2014/01/29 05:20:30 UTC

Do custom property functions get called in property paths?

I'm looking at implementing a property function that matches when its
subject and object are the same blank node.  This seemed like a
trivial case for subclassing the assign property function that's
included with Jena.  Here's a relatively minimal example that creates
such a property function and uses it in a SPARQL query (also available
as a Gist, https://gist.github.com/tayloj/349dd97014121a6c710c).  I
can see that the property function is getting called based on the
query output and on the logger output.  However, if I change the
property usage to be a property path, e.g., just by adding a * to it,
i.e., changing

"  ?s <java:CBDSPARQLExample$sameBlank> ?t .\n" +

to

"  ?s <java:CBDSPARQLExample$sameBlank>* ?t .\n" +

I get no log output whatsoever, which indicates that the property
function isn't getting called, and of course that means I get rather
different results, too.  Are property functions supposed to be invoked
in property paths?

Thanks in advance,
//JT

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hp.hpl.jena.graph.Node;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.sparql.engine.ExecutionContext;
import com.hp.hpl.jena.sparql.engine.QueryIterator;
import com.hp.hpl.jena.sparql.engine.binding.Binding;
import com.hp.hpl.jena.sparql.pfunction.library.assign;
import com.hp.hpl.jena.sparql.util.IterLib;

public class CBDSPARQLExample {

  private final static Logger LOGGER = LoggerFactory.getLogger(
CBDSPARQLExample.class );

  public static class sameBlank extends assign {
    @Override
    public QueryIterator execEvaluated( Binding binding, Node subject,
Node predicate, Node object, ExecutionContext execCxt) {
      LOGGER.info( "called with {} {} {}", new Object[] { subject,
predicate , object } );
      if ( subject.isBlank() || object.isBlank() ) {
        return super.execEvaluated(binding, subject, predicate,
object, execCxt);
      }
      else {
        return IterLib.noResults(execCxt);
      }
    }
  }

  private final static String MODEL_CONTENT = "" +
      "@prefix : <urn:ex:>\n" +
      "\n" +
      ":A :p :B ;\n" +
      "   :q [ :r :C, :D ; :s [ :t :U ] ] .\n" +
      ":C :p :E .\n" +
      ":D :q :F .\n";

  private final static String CBD_QUERY = "" +
      "prefix : <urn:ex:>\n" +
      "prefix fns: <http://example.org/fns#>" +
      "\n" +
      "construct { ?t ?p ?o }\n" +
      "where {\n" +
      "  ?s ?p ?o .\n" +
      "  ?s <java:CBDSPARQLExample$sameBlank> ?t .\n" +
      "}\n" +
      "";

  public static void main(String[] args) throws IOException {
    final Model model = ModelFactory.createDefaultModel();
    try ( final InputStream in = new ByteArrayInputStream(
MODEL_CONTENT.getBytes() )) {
      model.read( in, null, "TTL" );
    }

    QueryExecution exec = QueryExecutionFactory.create( CBD_QUERY, model );
    final Model cbd = exec.execConstruct();

    cbd.write( System.out, "TTL" );
  }
}


-- 
Joshua Taylor, http://www.cs.rpi.edu/~tayloj/

Re: Do custom property functions get called in property paths?

Posted by Andy Seaborne <an...@apache.org>.
On 29/01/14 14:53, Andy Seaborne wrote:
> [[ Rushed answer - more later ]]

Technically, every basic pattern involves a path in SPARQL 1.1

?s :p ?o .

is path.

ARQ compiles/optimizes paths down to triple patterns where ever possible 
by applying expansion rules for "/" "|" "^"

see com.hp.hpl.jena.sparql.algebra.optimize.TransformPathFlattern
and com.hp.hpl.jena.sparql.path.PathCompiler

and what can't be remains is evaluated as a path expression at run time. 
  The path expression engine can deal with any legal paths but, because 
of query exspansion, it's the unbounded paths that get left for run time.

?x foaf:knows/foaf:knows/foaf:name ?name .

==>

(bgp
   (triple ?x foaf:mbox <ma...@example>)
   (triple ?x foaf:knows ??P217)
   (triple ??P217 foaf:knows ??P216)
   (triple ??P216 foaf:name ?name) )

where ??P... are system generated variables and hidden from "SELECT *".

At run time, PathEngine executes remaining paths but it's not property 
path sensitive.  It should be.

Ideally, rewrite the path expression to have explicit (propfunc ...) so 
it shows in the algebra rather than juts do it implicitly by changing 
PathEngine.doOne.

Do raise a JIRA for it - maybe even turn it into a GSoC project. It's 
too small on it's own (?) but combine with property functions to runtime 
backwards inference and it's a nice project for someone.

	Andy

>
> The function that needs to change is :
>
> com.hp.hpl.jena.sparql.path.eval
> PathEngine.doOne
>
> specifically the call to Graph.find.
>
> If that consulted the property function registry
>
> (also check other .find calls in that package - there are very few).
>
> Test cases (JUnit code ideally) would be good; patches are better.
>
>      Andy
>
> PS and any speed ups would also be good.  The code can be become
> expensive if it's in an intense part of the query.
>
> On 29/01/14 14:07, Joshua TAYLOR wrote:
>> On Wed, Jan 29, 2014 at 12:32 AM, Rob Vesse <rv...@dotnetrdf.org> wrote:
>>> Most likely no, did you try printing the algebra for the query?
>>>
>>> This would show you whether the query plan contains a propertyfunc
>>> operator or not.
>>
>> Thanks, I haven't worked with these kind of extensions before, so I
>> didn't really know where to start.  Here are the algebra expressions
>> for simplified queries. The property function is called in the first
>> case (with (triple _ p _)), but not in the second (with (path* p)).
>> Neither algebra contains a propertyfunc operator, though.  Do I need
>> to expand this farther or something?
>>
>>    Query:   select * { ?s <java:CBDSPARQLExample$sameBlank> ?o }
>>    Algebra: (bgp (triple ?s <java:CBDSPARQLExample$sameBlank> ?o))
>>
>>    Query:   select * { ?s <java:CBDSPARQLExample$sameBlank>* ?o }
>>    Algebra: (path ?s (path* <java:CBDSPARQLExample$sameBlank>) ?o)
>>
>> Through some more experimentation, the property function isn't called
>> for (seq … p …), either.  I think this is problematic.  For the `*`
>> case, things might be complicated, but consider a sequence pattern.
>> According to 9.2 Examples [1] from the SPARQL 1.1 recommendation,
>>
>> [[[
>> Sequence: Find the names of people 2 "foaf:knows" links away.
>>
>>    {
>>      ?x foaf:mbox <ma...@example> .
>>      ?x foaf:knows/foaf:knows/foaf:name ?name .
>>    }
>>
>> This is the same as the SPARQL query:
>>
>>    SELECT ?x ?name
>>    {
>>       ?x  foaf:mbox <ma...@example> .
>>       ?x  foaf:knows [ foaf:knows [ foaf:name ?name ]].
>>    }
>> ]]]
>>
>> Of course, the SPARQL recommendation doesn't address Jena's property
>> functions, but with the current behavior, property functions will be
>> called in:
>>
>>    Query:   select * { ?s <java:CBDSPARQLExample$sameBlank> [
>> <java:CBDSPARQLExample$sameBlank> ?o ] }
>>    Algebra: (bgp
>>      (triple ?s <java:CBDSPARQLExample$sameBlank> ??0)
>>      (triple ??0 <java:CBDSPARQLExample$sameBlank> ?o)
>>    )
>>
>> but not in:
>>
>>    Query:   select * { ?s
>> <java:CBDSPARQLExample$sameBlank>/<java:CBDSPARQLExample$sameBlank> ?o
>> }
>>    Algebra: (path ?s (seq <java:CBDSPARQLExample$sameBlank>
>> <java:CBDSPARQLExample$sameBlank>) ?o)
>>
>> I did run those queries on some data, and observed the log output
>> indicating that the property function is run in the first case, but
>> not the second.  I think this is counterintuitive behavior, since what
>> the SPARQL rec says is equivalent has different behavior.  I haven't
>> looked into how property paths are matched, so I don't know how hard
>> this is to adjust.
>>
>> If this seems like something that isn't intended behavior (or even
>> just isn't documented), I'd be happy to make a minimal example
>> demonstrating the issue and put it on JIRA.
>>
>> //JT
>>
>> [1] http://www.w3.org/TR/sparql11-query/#propertypath-examples
>>
>


Re: Do custom property functions get called in property paths?

Posted by Andy Seaborne <an...@apache.org>.
[[ Rushed answer - more later ]]

The function that needs to change is :

com.hp.hpl.jena.sparql.path.eval
PathEngine.doOne

specifically the call to Graph.find.

If that consulted the property function registry

(also check other .find calls in that package - there are very few).

Test cases (JUnit code ideally) would be good; patches are better.

	Andy

PS and any speed ups would also be good.  The code can be become 
expensive if it's in an intense part of the query.

On 29/01/14 14:07, Joshua TAYLOR wrote:
> On Wed, Jan 29, 2014 at 12:32 AM, Rob Vesse <rv...@dotnetrdf.org> wrote:
>> Most likely no, did you try printing the algebra for the query?
>>
>> This would show you whether the query plan contains a propertyfunc
>> operator or not.
>
> Thanks, I haven't worked with these kind of extensions before, so I
> didn't really know where to start.  Here are the algebra expressions
> for simplified queries. The property function is called in the first
> case (with (triple _ p _)), but not in the second (with (path* p)).
> Neither algebra contains a propertyfunc operator, though.  Do I need
> to expand this farther or something?
>
>    Query:   select * { ?s <java:CBDSPARQLExample$sameBlank> ?o }
>    Algebra: (bgp (triple ?s <java:CBDSPARQLExample$sameBlank> ?o))
>
>    Query:   select * { ?s <java:CBDSPARQLExample$sameBlank>* ?o }
>    Algebra: (path ?s (path* <java:CBDSPARQLExample$sameBlank>) ?o)
>
> Through some more experimentation, the property function isn't called
> for (seq … p …), either.  I think this is problematic.  For the `*`
> case, things might be complicated, but consider a sequence pattern.
> According to 9.2 Examples [1] from the SPARQL 1.1 recommendation,
>
> [[[
> Sequence: Find the names of people 2 "foaf:knows" links away.
>
>    {
>      ?x foaf:mbox <ma...@example> .
>      ?x foaf:knows/foaf:knows/foaf:name ?name .
>    }
>
> This is the same as the SPARQL query:
>
>    SELECT ?x ?name
>    {
>       ?x  foaf:mbox <ma...@example> .
>       ?x  foaf:knows [ foaf:knows [ foaf:name ?name ]].
>    }
> ]]]
>
> Of course, the SPARQL recommendation doesn't address Jena's property
> functions, but with the current behavior, property functions will be
> called in:
>
>    Query:   select * { ?s <java:CBDSPARQLExample$sameBlank> [
> <java:CBDSPARQLExample$sameBlank> ?o ] }
>    Algebra: (bgp
>      (triple ?s <java:CBDSPARQLExample$sameBlank> ??0)
>      (triple ??0 <java:CBDSPARQLExample$sameBlank> ?o)
>    )
>
> but not in:
>
>    Query:   select * { ?s
> <java:CBDSPARQLExample$sameBlank>/<java:CBDSPARQLExample$sameBlank> ?o
> }
>    Algebra: (path ?s (seq <java:CBDSPARQLExample$sameBlank>
> <java:CBDSPARQLExample$sameBlank>) ?o)
>
> I did run those queries on some data, and observed the log output
> indicating that the property function is run in the first case, but
> not the second.  I think this is counterintuitive behavior, since what
> the SPARQL rec says is equivalent has different behavior.  I haven't
> looked into how property paths are matched, so I don't know how hard
> this is to adjust.
>
> If this seems like something that isn't intended behavior (or even
> just isn't documented), I'd be happy to make a minimal example
> demonstrating the issue and put it on JIRA.
>
> //JT
>
> [1] http://www.w3.org/TR/sparql11-query/#propertypath-examples
>


Re: Do custom property functions get called in property paths?

Posted by Joshua TAYLOR <jo...@gmail.com>.
On Wed, Jan 29, 2014 at 12:32 AM, Rob Vesse <rv...@dotnetrdf.org> wrote:
> Most likely no, did you try printing the algebra for the query?
>
> This would show you whether the query plan contains a propertyfunc
> operator or not.

Thanks, I haven't worked with these kind of extensions before, so I
didn't really know where to start.  Here are the algebra expressions
for simplified queries. The property function is called in the first
case (with (triple _ p _)), but not in the second (with (path* p)).
Neither algebra contains a propertyfunc operator, though.  Do I need
to expand this farther or something?

  Query:   select * { ?s <java:CBDSPARQLExample$sameBlank> ?o }
  Algebra: (bgp (triple ?s <java:CBDSPARQLExample$sameBlank> ?o))

  Query:   select * { ?s <java:CBDSPARQLExample$sameBlank>* ?o }
  Algebra: (path ?s (path* <java:CBDSPARQLExample$sameBlank>) ?o)

Through some more experimentation, the property function isn't called
for (seq … p …), either.  I think this is problematic.  For the `*`
case, things might be complicated, but consider a sequence pattern.
According to 9.2 Examples [1] from the SPARQL 1.1 recommendation,

[[[
Sequence: Find the names of people 2 "foaf:knows" links away.

  {
    ?x foaf:mbox <ma...@example> .
    ?x foaf:knows/foaf:knows/foaf:name ?name .
  }

This is the same as the SPARQL query:

  SELECT ?x ?name
  {
     ?x  foaf:mbox <ma...@example> .
     ?x  foaf:knows [ foaf:knows [ foaf:name ?name ]].
  }
]]]

Of course, the SPARQL recommendation doesn't address Jena's property
functions, but with the current behavior, property functions will be
called in:

  Query:   select * { ?s <java:CBDSPARQLExample$sameBlank> [
<java:CBDSPARQLExample$sameBlank> ?o ] }
  Algebra: (bgp
    (triple ?s <java:CBDSPARQLExample$sameBlank> ??0)
    (triple ??0 <java:CBDSPARQLExample$sameBlank> ?o)
  )

but not in:

  Query:   select * { ?s
<java:CBDSPARQLExample$sameBlank>/<java:CBDSPARQLExample$sameBlank> ?o
}
  Algebra: (path ?s (seq <java:CBDSPARQLExample$sameBlank>
<java:CBDSPARQLExample$sameBlank>) ?o)

I did run those queries on some data, and observed the log output
indicating that the property function is run in the first case, but
not the second.  I think this is counterintuitive behavior, since what
the SPARQL rec says is equivalent has different behavior.  I haven't
looked into how property paths are matched, so I don't know how hard
this is to adjust.

If this seems like something that isn't intended behavior (or even
just isn't documented), I'd be happy to make a minimal example
demonstrating the issue and put it on JIRA.

//JT

[1] http://www.w3.org/TR/sparql11-query/#propertypath-examples
-- 
Joshua Taylor, http://www.cs.rpi.edu/~tayloj/

Re: Do custom property functions get called in property paths?

Posted by Rob Vesse <rv...@dotnetrdf.org>.
Most likely no, did you try printing the algebra for the query?

This would show you whether the query plan contains a propertyfunc
operator or not.

Rob

On 28/01/2014 20:20, "Joshua TAYLOR" <jo...@gmail.com> wrote:

>I'm looking at implementing a property function that matches when its
>subject and object are the same blank node.  This seemed like a
>trivial case for subclassing the assign property function that's
>included with Jena.  Here's a relatively minimal example that creates
>such a property function and uses it in a SPARQL query (also available
>as a Gist, https://gist.github.com/tayloj/349dd97014121a6c710c).  I
>can see that the property function is getting called based on the
>query output and on the logger output.  However, if I change the
>property usage to be a property path, e.g., just by adding a * to it,
>i.e., changing
>
>"  ?s <java:CBDSPARQLExample$sameBlank> ?t .\n" +
>
>to
>
>"  ?s <java:CBDSPARQLExample$sameBlank>* ?t .\n" +
>
>I get no log output whatsoever, which indicates that the property
>function isn't getting called, and of course that means I get rather
>different results, too.  Are property functions supposed to be invoked
>in property paths?
>
>Thanks in advance,
>//JT
>
>import java.io.ByteArrayInputStream;
>import java.io.IOException;
>import java.io.InputStream;
>
>import org.slf4j.Logger;
>import org.slf4j.LoggerFactory;
>
>import com.hp.hpl.jena.graph.Node;
>import com.hp.hpl.jena.query.QueryExecution;
>import com.hp.hpl.jena.query.QueryExecutionFactory;
>import com.hp.hpl.jena.rdf.model.Model;
>import com.hp.hpl.jena.rdf.model.ModelFactory;
>import com.hp.hpl.jena.sparql.engine.ExecutionContext;
>import com.hp.hpl.jena.sparql.engine.QueryIterator;
>import com.hp.hpl.jena.sparql.engine.binding.Binding;
>import com.hp.hpl.jena.sparql.pfunction.library.assign;
>import com.hp.hpl.jena.sparql.util.IterLib;
>
>public class CBDSPARQLExample {
>
>  private final static Logger LOGGER = LoggerFactory.getLogger(
>CBDSPARQLExample.class );
>
>  public static class sameBlank extends assign {
>    @Override
>    public QueryIterator execEvaluated( Binding binding, Node subject,
>Node predicate, Node object, ExecutionContext execCxt) {
>      LOGGER.info( "called with {} {} {}", new Object[] { subject,
>predicate , object } );
>      if ( subject.isBlank() || object.isBlank() ) {
>        return super.execEvaluated(binding, subject, predicate,
>object, execCxt);
>      }
>      else {
>        return IterLib.noResults(execCxt);
>      }
>    }
>  }
>
>  private final static String MODEL_CONTENT = "" +
>      "@prefix : <urn:ex:>\n" +
>      "\n" +
>      ":A :p :B ;\n" +
>      "   :q [ :r :C, :D ; :s [ :t :U ] ] .\n" +
>      ":C :p :E .\n" +
>      ":D :q :F .\n";
>
>  private final static String CBD_QUERY = "" +
>      "prefix : <urn:ex:>\n" +
>      "prefix fns: <http://example.org/fns#>" +
>      "\n" +
>      "construct { ?t ?p ?o }\n" +
>      "where {\n" +
>      "  ?s ?p ?o .\n" +
>      "  ?s <java:CBDSPARQLExample$sameBlank> ?t .\n" +
>      "}\n" +
>      "";
>
>  public static void main(String[] args) throws IOException {
>    final Model model = ModelFactory.createDefaultModel();
>    try ( final InputStream in = new ByteArrayInputStream(
>MODEL_CONTENT.getBytes() )) {
>      model.read( in, null, "TTL" );
>    }
>
>    QueryExecution exec = QueryExecutionFactory.create( CBD_QUERY, model
>);
>    final Model cbd = exec.execConstruct();
>
>    cbd.write( System.out, "TTL" );
>  }
>}
>
>
>-- 
>Joshua Taylor, http://www.cs.rpi.edu/~tayloj/