You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@jena.apache.org by Martynas Jusevičius <ma...@atomgraph.com> on 2020/07/05 14:22:29 UTC

Blank node URI scheme

Hi,

I came across a situation where I want to carry over a blank node ID
in a QuerySolutionMap to QueryExecution, to match exact blank node
resources rather than have them as variables.

I found an old thread by Holger on this topic:
https://mail-archives.apache.org/mod_mbox/jena-users/201308.mbox/browser

The suggestion was to use <_:LABEL> URI scheme for blank nodes.
https://jena.apache.org/documentation/query/extension.html#blank-node-labels

Based on that, I tried this logic:

    if (instance.isURIResource()) qsm.add(SPIN.THIS_VAR_NAME, instance);
    if (instance.isAnon()) qsm.add(SPIN.THIS_VAR_NAME,
model.createResource("_:" + instance.getId()));

However I'm not getting the results I expect. So I decided to make an
isolated test:

    @Test
    public void bnodeQueryTest()
    {
        Model model = ModelFactory.createDefaultModel();
        Resource bnode = model.createResource().addProperty(FOAF.name,
"whateverest");
        AnonId id = bnode.getId();

        Query query = QueryFactory.create("SELECT * { ?s ?p ?o }");
        QuerySolutionMap qsm = new QuerySolutionMap();
        qsm.add("s", model.createResource("_:" + id));

        try (QueryExecution qex = QueryExecutionFactory.create(query,
model, qsm))
        {
            ResultSet resultSet = qex.execSelect();

            assertTrue(resultSet.hasNext());
            assertEquals(id, resultSet.next().get("s").asResource().getId());
        }
    }

The test fails on assertTrue() because SELECT returns no results.

Is the test flawed? Am I misunderstanding the use of this URI scheme?
If not, what's the purpose if it cannot match blank nodes in data?

Martynas

Re: Blank node URI scheme

Posted by Martynas Jusevičius <ma...@atomgraph.com>.
Missed the BIND(?minCount AS ?mc) FILTER bound(?mc) suggestion, will try it now.

On Mon, Jul 6, 2020 at 12:56 PM Martynas Jusevičius
<ma...@atomgraph.com> wrote:
>
> Andy,
>
> This is getting quite complicated compared to the QuerySolutionMap. I
> get that we should rather be using alternatives, but you presented
> several and neither is a drop-in replacement for the QuerySolutionMap.
> I think Jena's documentation could use a section on this topic, with a
> comparison of the approaches and some criteria which should be used
> when, plus code examples.
>
> I am trying to build a VALUES block now. My code:
>
>     Map<String, RDFNode> subs = ...
>     Query query = QueryFactory.create(wrapper.getQuery().toString());
> // can't use wrapper.getQuery().cloneQuery() due to JENA-1935
>     List<Var> variables = subs.entrySet().stream().map(e ->
> Var.alloc(e.getKey())).collect(Collectors.toList());
>     List<Binding> values = subs.entrySet().stream().map(e ->
> BindingFactory.binding(Var.alloc(e.getKey()),
> e.getValue().asNode())).collect(Collectors.toList());
>     query.setValuesDataBlock(variables, values);
>
> First of all I am wondering why a substitution map
>
>     [( ?predicate = <http://spinrdf.org/spin#body> ), ( ?comment =
> "the body of the Template" ), ( ?minCount = 0 ), ( ?maxCount = 1 )]
>
>  produces the VALUES table of the form
>
> VALUES ( ?predicate ?comment ?minCount ?maxCount ) {
>   ( spin:body UNDEF UNDEF UNDEF )
>   ( UNDEF "the body of the Template" UNDEF UNDEF )
>   ( UNDEF UNDEF 0 UNDEF )
>   ( UNDEF UNDEF UNDEF 1 )
> }
>
> and not simply
>
> VALUES ( ?predicate ?comment ?minCount ?maxCount ) {
>   ( spin:body "the body of the Template" 0 1 )
> }
>
>
> And then what do I do with expressions like FILTER (bound(?maxCount))
> which are used in SPIN's internal queries to "switch off" graph
> patterns (as I understand it) in the absence of the ?maxCount binding.
> It does not seem to have the same effect with VALUES.
>
>
>
>
> On Mon, Jul 6, 2020 at 11:28 AM Andy Seaborne <an...@apache.org> wrote:
> >
> > "bound()" is not a function in the strict sense.
> >
> > Another case where variables are necessary is "AS ?var"
> >
> > Long version:
> > https://afs.github.io/substitute.html
> >
> > The advantage of using VALUES or BIND to inject the substitution value
> > is that it preserves the original variable.
> >
> > Contrast the difference between these two:
> >
> >    QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
> >    QueryFactory.create("SELECT * { "+bn+" ?p ?o }");
> >
> > BIND(?minCount AS ?mc) FILTER bound(?mc)
> >
> >      Andy
> >
> > On 06/07/2020 09:56, Martynas Jusevičius wrote:
> > > The same problem (invalid query string) using
> > > QueryTransformOps.transformQuery().
> > >
> > > On Sun, Jul 5, 2020 at 11:34 PM Martynas Jusevičius
> > > <ma...@atomgraph.com> wrote:
> > >>
> > >> ParameterizedSparqlString does not work either (not related to bnodes).
> > >>
> > >> With a mapping ?minCount => 0, it produces an invalid query string:
> > >>
> > >> SELECT  (count(*) AS ?cardinality)
> > >>          WHERE
> > >>            { <http://spinrdf.org/spin#Templates>
> > >> <http://spinrdf.org/spin#body>  ?value
> > >>              FILTER bound(0)
> > >>            }
> > >>          HAVING ( ?cardinality < 0 )
> > >>
> > >> On Sun, Jul 5, 2020 at 10:31 PM Andy Seaborne <an...@apache.org> wrote:
> > >>>
> > >>>
> > >>>
> > >>> On 05/07/2020 20:36, Martynas Jusevičius wrote:
> > >>>> Thanks for the explanation.
> > >>>>
> > >>>> What do you mean with "inject" in 1/? ParameterizedSparqlString?
> > >>>
> > >>> initialBinding is done by making the starting condition for execution a
> > >>> binding of the variables instead of the empty root. (This works nearly
> > >>> always but is affected by variable name scopes - scopes, like subquery,
> > >>> didn't exist when the mechanism was introduced.
> > >>>
> > >>> ParameterizedSparqlString builds which is parsed so you should be able
> > >>> to put in <_:....>.
> > >>>
> > >>>       Andy
> > >>>
> > >>>>
> > >>>> On Sun, Jul 5, 2020 at 8:53 PM Andy Seaborne <an...@apache.org> wrote:
> > >>>>>
> > >>>>> <_:label> is a syntax feature, not built into the storage or query
> > >>>>> execution.
> > >>>>>
> > >>>>> model.createResource("_:" + id));
> > >>>>>
> > >>>>> creates a resource with a strange URI (which is actually illegal by RFC
> > >>>>> 3986/7).
> > >>>>>
> > >>>>> There are various ways:
> > >>>>>
> > >>>>> 1/ The app can put the bnode into the QSM and injected at execution - it
> > >>>>> won't become a bnode-variable because that happens in parsing.
> > >>>>>
> > >>>>> 2/ To put a concrete node into a query:
> > >>>>>
> > >>>>> String bn = "<_:" + id+">";
> > >>>>>
> > >>>>> then put string into SPARQL syntax:
> > >>>>>
> > >>>>> QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
> > >>>>> QueryFactory.create("SELECT * { "+bn+" ?p ?o }");
> > >>>>>
> > >>>>> 3/ rewrite the abstract syntax after parsing:
> > >>>>>
> > >>>>> Map<String, Resource> substitutions =
> > >>>>>      Collections.singletonMap("s", bnode);
> > >>>>> query = QueryFactory.create("SELECT * { ?s ?p ?o }");
> > >>>>> query = QueryTransformOps.transformQuery(query, substitutions);
> > >>>>>
> > >>>>> Forms 2 and 3 have the advantage of not relying on how execution works -
> > >>>>> QSMs are ingested inthe start of execution and e.g. aren't visible in
> > >>>>> subqueries and also interact and bypass with query optimization.
> > >>>>>
> > >>>>>        Andy
> > >>>>>
> > >>>>> On 05/07/2020 15:22, Martynas Jusevičius wrote:
> > >>>>>> Hi,
> > >>>>>>
> > >>>>>> I came across a situation where I want to carry over a blank node ID
> > >>>>>> in a QuerySolutionMap to QueryExecution, to match exact blank node
> > >>>>>> resources rather than have them as variables.
> > >>>>>>
> > >>>>>> I found an old thread by Holger on this topic:
> > >>>>>> https://mail-archives.apache.org/mod_mbox/jena-users/201308.mbox/browser
> > >>>>>>
> > >>>>>> The suggestion was to use <_:LABEL> URI scheme for blank nodes.
> > >>>>>> https://jena.apache.org/documentation/query/extension.html#blank-node-labels
> > >>>>>>
> > >>>>>> Based on that, I tried this logic:
> > >>>>>>
> > >>>>>>        if (instance.isURIResource()) qsm.add(SPIN.THIS_VAR_NAME, instance);
> > >>>>>>        if (instance.isAnon()) qsm.add(SPIN.THIS_VAR_NAME,
> > >>>>>> model.createResource("_:" + instance.getId()));
> > >>>>>>
> > >>>>>> However I'm not getting the results I expect. So I decided to make an
> > >>>>>> isolated test:
> > >>>>>>
> > >>>>>>        @Test
> > >>>>>>        public void bnodeQueryTest()
> > >>>>>>        {
> > >>>>>>            Model model = ModelFactory.createDefaultModel();
> > >>>>>>            Resource bnode = model.createResource().addProperty(FOAF.name,
> > >>>>>> "whateverest");
> > >>>>>>            AnonId id = bnode.getId();
> > >>>>>>
> > >>>>>>            Query query = QueryFactory.create("SELECT * { ?s ?p ?o }");
> > >>>>>>            QuerySolutionMap qsm = new QuerySolutionMap();
> > >>>>>>            qsm.add("s", model.createResource("_:" + id));
> > >>>>>>
> > >>>>>>            try (QueryExecution qex = QueryExecutionFactory.create(query,
> > >>>>>> model, qsm))
> > >>>>>>            {
> > >>>>>>                ResultSet resultSet = qex.execSelect();
> > >>>>>>
> > >>>>>>                assertTrue(resultSet.hasNext());
> > >>>>>>                assertEquals(id, resultSet.next().get("s").asResource().getId());
> > >>>>>>            }
> > >>>>>>        }
> > >>>>>>
> > >>>>>> The test fails on assertTrue() because SELECT returns no results.
> > >>>>>>
> > >>>>>> Is the test flawed? Am I misunderstanding the use of this URI scheme?
> > >>>>>> If not, what's the purpose if it cannot match blank nodes in data?
> > >>>>>>
> > >>>>>> Martynas
> > >>>>>>

Re: Blank node URI scheme

Posted by Martynas Jusevičius <ma...@atomgraph.com>.
Thanks, this seems to do the trick:

    List<Var> variables = subs.entrySet().stream().map(e ->
Var.alloc(e.getKey())).collect(Collectors.toList());
    BindingMap bindingMap = BindingFactory.create();
    subs.entrySet().stream().forEach(e ->
bindingMap.add(Var.alloc(e.getKey()), e.getValue().asNode()));
    List<Binding> values = Arrays.asList(bindingMap);
    query.setValuesDataBlock(variables, values);

On Mon, Jul 6, 2020 at 3:45 PM Andy Seaborne <an...@apache.org> wrote:
>
>
>
> On 06/07/2020 11:56, Martynas Jusevičius wrote:
> > Andy,
> >
> > This is getting quite complicated compared to the QuerySolutionMap. I
> > get that we should rather be using alternatives, but you presented
> > several and neither is a drop-in replacement for the QuerySolutionMap.
> > I think Jena's documentation could use a section on this topic, with a
> > comparison of the approaches and some criteria which should be used
> > when, plus code examples.
> >
> > I am trying to build a VALUES block now. My code:
> >
> >      Map<String, RDFNode> subs = ...
> >      Query query = QueryFactory.create(wrapper.getQuery().toString());
> > // can't use wrapper.getQuery().cloneQuery() due to JENA-1935
> >      List<Var> variables = subs.entrySet().stream().map(e ->
> > Var.alloc(e.getKey())).collect(Collectors.toList());
>
>
> >      List<Binding> values = subs.entrySet().stream().map(e ->
> > BindingFactory.binding(Var.alloc(e.getKey()),
> > e.getValue().asNode())).collect(Collectors.toList());
>
> That produces a new binding for key in the map, which is why you the stripe.
>
> Create one binding, add each key/value to the binding.
>
> >      query.setValuesDataBlock(variables, values);
> >
> > First of all I am wondering why a substitution map
> >
> >      [( ?predicate = <http://spinrdf.org/spin#body> ), ( ?comment =
> > "the body of the Template" ), ( ?minCount = 0 ), ( ?maxCount = 1 )]
> >
> >   produces the VALUES table of the form
> >
> > VALUES ( ?predicate ?comment ?minCount ?maxCount ) {
> >    ( spin:body UNDEF UNDEF UNDEF )
> >    ( UNDEF "the body of the Template" UNDEF UNDEF )
> >    ( UNDEF UNDEF 0 UNDEF )
> >    ( UNDEF UNDEF UNDEF 1 )
> > }
> >
> > and not simply
> >
> > VALUES ( ?predicate ?comment ?minCount ?maxCount ) {
> >    ( spin:body "the body of the Template" 0 1 )
> > }
> >
> >
> > And then what do I do with expressions like FILTER (bound(?maxCount))
> > which are used in SPIN's internal queries to "switch off" graph
> > patterns (as I understand it) in the absence of the ?maxCount binding.
> > It does not seem to have the same effect with VALUES.
> >
> >
> >
> >
> > On Mon, Jul 6, 2020 at 11:28 AM Andy Seaborne <an...@apache.org> wrote:
> >>
> >> "bound()" is not a function in the strict sense.
> >>
> >> Another case where variables are necessary is "AS ?var"
> >>
> >> Long version:
> >> https://afs.github.io/substitute.html
> >>
> >> The advantage of using VALUES or BIND to inject the substitution value
> >> is that it preserves the original variable.
> >>
> >> Contrast the difference between these two:
> >>
> >>     QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
> >>     QueryFactory.create("SELECT * { "+bn+" ?p ?o }");
> >>
> >> BIND(?minCount AS ?mc) FILTER bound(?mc)
> >>
> >>       Andy
> >>
> >> On 06/07/2020 09:56, Martynas Jusevičius wrote:
> >>> The same problem (invalid query string) using
> >>> QueryTransformOps.transformQuery().
> >>>
> >>> On Sun, Jul 5, 2020 at 11:34 PM Martynas Jusevičius
> >>> <ma...@atomgraph.com> wrote:
> >>>>
> >>>> ParameterizedSparqlString does not work either (not related to bnodes).
> >>>>
> >>>> With a mapping ?minCount => 0, it produces an invalid query string:
> >>>>
> >>>> SELECT  (count(*) AS ?cardinality)
> >>>>           WHERE
> >>>>             { <http://spinrdf.org/spin#Templates>
> >>>> <http://spinrdf.org/spin#body>  ?value
> >>>>               FILTER bound(0)
> >>>>             }
> >>>>           HAVING ( ?cardinality < 0 )
> >>>>
> >>>> On Sun, Jul 5, 2020 at 10:31 PM Andy Seaborne <an...@apache.org> wrote:
> >>>>>
> >>>>>
> >>>>>
> >>>>> On 05/07/2020 20:36, Martynas Jusevičius wrote:
> >>>>>> Thanks for the explanation.
> >>>>>>
> >>>>>> What do you mean with "inject" in 1/? ParameterizedSparqlString?
> >>>>>
> >>>>> initialBinding is done by making the starting condition for execution a
> >>>>> binding of the variables instead of the empty root. (This works nearly
> >>>>> always but is affected by variable name scopes - scopes, like subquery,
> >>>>> didn't exist when the mechanism was introduced.
> >>>>>
> >>>>> ParameterizedSparqlString builds which is parsed so you should be able
> >>>>> to put in <_:....>.
> >>>>>
> >>>>>        Andy
> >>>>>
> >>>>>>
> >>>>>> On Sun, Jul 5, 2020 at 8:53 PM Andy Seaborne <an...@apache.org> wrote:
> >>>>>>>
> >>>>>>> <_:label> is a syntax feature, not built into the storage or query
> >>>>>>> execution.
> >>>>>>>
> >>>>>>> model.createResource("_:" + id));
> >>>>>>>
> >>>>>>> creates a resource with a strange URI (which is actually illegal by RFC
> >>>>>>> 3986/7).
> >>>>>>>
> >>>>>>> There are various ways:
> >>>>>>>
> >>>>>>> 1/ The app can put the bnode into the QSM and injected at execution - it
> >>>>>>> won't become a bnode-variable because that happens in parsing.
> >>>>>>>
> >>>>>>> 2/ To put a concrete node into a query:
> >>>>>>>
> >>>>>>> String bn = "<_:" + id+">";
> >>>>>>>
> >>>>>>> then put string into SPARQL syntax:
> >>>>>>>
> >>>>>>> QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
> >>>>>>> QueryFactory.create("SELECT * { "+bn+" ?p ?o }");
> >>>>>>>
> >>>>>>> 3/ rewrite the abstract syntax after parsing:
> >>>>>>>
> >>>>>>> Map<String, Resource> substitutions =
> >>>>>>>       Collections.singletonMap("s", bnode);
> >>>>>>> query = QueryFactory.create("SELECT * { ?s ?p ?o }");
> >>>>>>> query = QueryTransformOps.transformQuery(query, substitutions);
> >>>>>>>
> >>>>>>> Forms 2 and 3 have the advantage of not relying on how execution works -
> >>>>>>> QSMs are ingested inthe start of execution and e.g. aren't visible in
> >>>>>>> subqueries and also interact and bypass with query optimization.
> >>>>>>>
> >>>>>>>         Andy
> >>>>>>>
> >>>>>>> On 05/07/2020 15:22, Martynas Jusevičius wrote:
> >>>>>>>> Hi,
> >>>>>>>>
> >>>>>>>> I came across a situation where I want to carry over a blank node ID
> >>>>>>>> in a QuerySolutionMap to QueryExecution, to match exact blank node
> >>>>>>>> resources rather than have them as variables.
> >>>>>>>>
> >>>>>>>> I found an old thread by Holger on this topic:
> >>>>>>>> https://mail-archives.apache.org/mod_mbox/jena-users/201308.mbox/browser
> >>>>>>>>
> >>>>>>>> The suggestion was to use <_:LABEL> URI scheme for blank nodes.
> >>>>>>>> https://jena.apache.org/documentation/query/extension.html#blank-node-labels
> >>>>>>>>
> >>>>>>>> Based on that, I tried this logic:
> >>>>>>>>
> >>>>>>>>         if (instance.isURIResource()) qsm.add(SPIN.THIS_VAR_NAME, instance);
> >>>>>>>>         if (instance.isAnon()) qsm.add(SPIN.THIS_VAR_NAME,
> >>>>>>>> model.createResource("_:" + instance.getId()));
> >>>>>>>>
> >>>>>>>> However I'm not getting the results I expect. So I decided to make an
> >>>>>>>> isolated test:
> >>>>>>>>
> >>>>>>>>         @Test
> >>>>>>>>         public void bnodeQueryTest()
> >>>>>>>>         {
> >>>>>>>>             Model model = ModelFactory.createDefaultModel();
> >>>>>>>>             Resource bnode = model.createResource().addProperty(FOAF.name,
> >>>>>>>> "whateverest");
> >>>>>>>>             AnonId id = bnode.getId();
> >>>>>>>>
> >>>>>>>>             Query query = QueryFactory.create("SELECT * { ?s ?p ?o }");
> >>>>>>>>             QuerySolutionMap qsm = new QuerySolutionMap();
> >>>>>>>>             qsm.add("s", model.createResource("_:" + id));
> >>>>>>>>
> >>>>>>>>             try (QueryExecution qex = QueryExecutionFactory.create(query,
> >>>>>>>> model, qsm))
> >>>>>>>>             {
> >>>>>>>>                 ResultSet resultSet = qex.execSelect();
> >>>>>>>>
> >>>>>>>>                 assertTrue(resultSet.hasNext());
> >>>>>>>>                 assertEquals(id, resultSet.next().get("s").asResource().getId());
> >>>>>>>>             }
> >>>>>>>>         }
> >>>>>>>>
> >>>>>>>> The test fails on assertTrue() because SELECT returns no results.
> >>>>>>>>
> >>>>>>>> Is the test flawed? Am I misunderstanding the use of this URI scheme?
> >>>>>>>> If not, what's the purpose if it cannot match blank nodes in data?
> >>>>>>>>
> >>>>>>>> Martynas
> >>>>>>>>

Re: Blank node URI scheme

Posted by Andy Seaborne <an...@apache.org>.

On 06/07/2020 11:56, Martynas Jusevičius wrote:
> Andy,
> 
> This is getting quite complicated compared to the QuerySolutionMap. I
> get that we should rather be using alternatives, but you presented
> several and neither is a drop-in replacement for the QuerySolutionMap.
> I think Jena's documentation could use a section on this topic, with a
> comparison of the approaches and some criteria which should be used
> when, plus code examples.
> 
> I am trying to build a VALUES block now. My code:
> 
>      Map<String, RDFNode> subs = ...
>      Query query = QueryFactory.create(wrapper.getQuery().toString());
> // can't use wrapper.getQuery().cloneQuery() due to JENA-1935
>      List<Var> variables = subs.entrySet().stream().map(e ->
> Var.alloc(e.getKey())).collect(Collectors.toList());


>      List<Binding> values = subs.entrySet().stream().map(e ->
> BindingFactory.binding(Var.alloc(e.getKey()),
> e.getValue().asNode())).collect(Collectors.toList());

That produces a new binding for key in the map, which is why you the stripe.

Create one binding, add each key/value to the binding.

>      query.setValuesDataBlock(variables, values);
> 
> First of all I am wondering why a substitution map
> 
>      [( ?predicate = <http://spinrdf.org/spin#body> ), ( ?comment =
> "the body of the Template" ), ( ?minCount = 0 ), ( ?maxCount = 1 )]
> 
>   produces the VALUES table of the form
> 
> VALUES ( ?predicate ?comment ?minCount ?maxCount ) {
>    ( spin:body UNDEF UNDEF UNDEF )
>    ( UNDEF "the body of the Template" UNDEF UNDEF )
>    ( UNDEF UNDEF 0 UNDEF )
>    ( UNDEF UNDEF UNDEF 1 )
> }
> 
> and not simply
> 
> VALUES ( ?predicate ?comment ?minCount ?maxCount ) {
>    ( spin:body "the body of the Template" 0 1 )
> }
> 
> 
> And then what do I do with expressions like FILTER (bound(?maxCount))
> which are used in SPIN's internal queries to "switch off" graph
> patterns (as I understand it) in the absence of the ?maxCount binding.
> It does not seem to have the same effect with VALUES.
> 
> 
> 
> 
> On Mon, Jul 6, 2020 at 11:28 AM Andy Seaborne <an...@apache.org> wrote:
>>
>> "bound()" is not a function in the strict sense.
>>
>> Another case where variables are necessary is "AS ?var"
>>
>> Long version:
>> https://afs.github.io/substitute.html
>>
>> The advantage of using VALUES or BIND to inject the substitution value
>> is that it preserves the original variable.
>>
>> Contrast the difference between these two:
>>
>>     QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
>>     QueryFactory.create("SELECT * { "+bn+" ?p ?o }");
>>
>> BIND(?minCount AS ?mc) FILTER bound(?mc)
>>
>>       Andy
>>
>> On 06/07/2020 09:56, Martynas Jusevičius wrote:
>>> The same problem (invalid query string) using
>>> QueryTransformOps.transformQuery().
>>>
>>> On Sun, Jul 5, 2020 at 11:34 PM Martynas Jusevičius
>>> <ma...@atomgraph.com> wrote:
>>>>
>>>> ParameterizedSparqlString does not work either (not related to bnodes).
>>>>
>>>> With a mapping ?minCount => 0, it produces an invalid query string:
>>>>
>>>> SELECT  (count(*) AS ?cardinality)
>>>>           WHERE
>>>>             { <http://spinrdf.org/spin#Templates>
>>>> <http://spinrdf.org/spin#body>  ?value
>>>>               FILTER bound(0)
>>>>             }
>>>>           HAVING ( ?cardinality < 0 )
>>>>
>>>> On Sun, Jul 5, 2020 at 10:31 PM Andy Seaborne <an...@apache.org> wrote:
>>>>>
>>>>>
>>>>>
>>>>> On 05/07/2020 20:36, Martynas Jusevičius wrote:
>>>>>> Thanks for the explanation.
>>>>>>
>>>>>> What do you mean with "inject" in 1/? ParameterizedSparqlString?
>>>>>
>>>>> initialBinding is done by making the starting condition for execution a
>>>>> binding of the variables instead of the empty root. (This works nearly
>>>>> always but is affected by variable name scopes - scopes, like subquery,
>>>>> didn't exist when the mechanism was introduced.
>>>>>
>>>>> ParameterizedSparqlString builds which is parsed so you should be able
>>>>> to put in <_:....>.
>>>>>
>>>>>        Andy
>>>>>
>>>>>>
>>>>>> On Sun, Jul 5, 2020 at 8:53 PM Andy Seaborne <an...@apache.org> wrote:
>>>>>>>
>>>>>>> <_:label> is a syntax feature, not built into the storage or query
>>>>>>> execution.
>>>>>>>
>>>>>>> model.createResource("_:" + id));
>>>>>>>
>>>>>>> creates a resource with a strange URI (which is actually illegal by RFC
>>>>>>> 3986/7).
>>>>>>>
>>>>>>> There are various ways:
>>>>>>>
>>>>>>> 1/ The app can put the bnode into the QSM and injected at execution - it
>>>>>>> won't become a bnode-variable because that happens in parsing.
>>>>>>>
>>>>>>> 2/ To put a concrete node into a query:
>>>>>>>
>>>>>>> String bn = "<_:" + id+">";
>>>>>>>
>>>>>>> then put string into SPARQL syntax:
>>>>>>>
>>>>>>> QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
>>>>>>> QueryFactory.create("SELECT * { "+bn+" ?p ?o }");
>>>>>>>
>>>>>>> 3/ rewrite the abstract syntax after parsing:
>>>>>>>
>>>>>>> Map<String, Resource> substitutions =
>>>>>>>       Collections.singletonMap("s", bnode);
>>>>>>> query = QueryFactory.create("SELECT * { ?s ?p ?o }");
>>>>>>> query = QueryTransformOps.transformQuery(query, substitutions);
>>>>>>>
>>>>>>> Forms 2 and 3 have the advantage of not relying on how execution works -
>>>>>>> QSMs are ingested inthe start of execution and e.g. aren't visible in
>>>>>>> subqueries and also interact and bypass with query optimization.
>>>>>>>
>>>>>>>         Andy
>>>>>>>
>>>>>>> On 05/07/2020 15:22, Martynas Jusevičius wrote:
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> I came across a situation where I want to carry over a blank node ID
>>>>>>>> in a QuerySolutionMap to QueryExecution, to match exact blank node
>>>>>>>> resources rather than have them as variables.
>>>>>>>>
>>>>>>>> I found an old thread by Holger on this topic:
>>>>>>>> https://mail-archives.apache.org/mod_mbox/jena-users/201308.mbox/browser
>>>>>>>>
>>>>>>>> The suggestion was to use <_:LABEL> URI scheme for blank nodes.
>>>>>>>> https://jena.apache.org/documentation/query/extension.html#blank-node-labels
>>>>>>>>
>>>>>>>> Based on that, I tried this logic:
>>>>>>>>
>>>>>>>>         if (instance.isURIResource()) qsm.add(SPIN.THIS_VAR_NAME, instance);
>>>>>>>>         if (instance.isAnon()) qsm.add(SPIN.THIS_VAR_NAME,
>>>>>>>> model.createResource("_:" + instance.getId()));
>>>>>>>>
>>>>>>>> However I'm not getting the results I expect. So I decided to make an
>>>>>>>> isolated test:
>>>>>>>>
>>>>>>>>         @Test
>>>>>>>>         public void bnodeQueryTest()
>>>>>>>>         {
>>>>>>>>             Model model = ModelFactory.createDefaultModel();
>>>>>>>>             Resource bnode = model.createResource().addProperty(FOAF.name,
>>>>>>>> "whateverest");
>>>>>>>>             AnonId id = bnode.getId();
>>>>>>>>
>>>>>>>>             Query query = QueryFactory.create("SELECT * { ?s ?p ?o }");
>>>>>>>>             QuerySolutionMap qsm = new QuerySolutionMap();
>>>>>>>>             qsm.add("s", model.createResource("_:" + id));
>>>>>>>>
>>>>>>>>             try (QueryExecution qex = QueryExecutionFactory.create(query,
>>>>>>>> model, qsm))
>>>>>>>>             {
>>>>>>>>                 ResultSet resultSet = qex.execSelect();
>>>>>>>>
>>>>>>>>                 assertTrue(resultSet.hasNext());
>>>>>>>>                 assertEquals(id, resultSet.next().get("s").asResource().getId());
>>>>>>>>             }
>>>>>>>>         }
>>>>>>>>
>>>>>>>> The test fails on assertTrue() because SELECT returns no results.
>>>>>>>>
>>>>>>>> Is the test flawed? Am I misunderstanding the use of this URI scheme?
>>>>>>>> If not, what's the purpose if it cannot match blank nodes in data?
>>>>>>>>
>>>>>>>> Martynas
>>>>>>>>

Re: Blank node URI scheme

Posted by Martynas Jusevičius <ma...@atomgraph.com>.
Andy,

This is getting quite complicated compared to the QuerySolutionMap. I
get that we should rather be using alternatives, but you presented
several and neither is a drop-in replacement for the QuerySolutionMap.
I think Jena's documentation could use a section on this topic, with a
comparison of the approaches and some criteria which should be used
when, plus code examples.

I am trying to build a VALUES block now. My code:

    Map<String, RDFNode> subs = ...
    Query query = QueryFactory.create(wrapper.getQuery().toString());
// can't use wrapper.getQuery().cloneQuery() due to JENA-1935
    List<Var> variables = subs.entrySet().stream().map(e ->
Var.alloc(e.getKey())).collect(Collectors.toList());
    List<Binding> values = subs.entrySet().stream().map(e ->
BindingFactory.binding(Var.alloc(e.getKey()),
e.getValue().asNode())).collect(Collectors.toList());
    query.setValuesDataBlock(variables, values);

First of all I am wondering why a substitution map

    [( ?predicate = <http://spinrdf.org/spin#body> ), ( ?comment =
"the body of the Template" ), ( ?minCount = 0 ), ( ?maxCount = 1 )]

 produces the VALUES table of the form

VALUES ( ?predicate ?comment ?minCount ?maxCount ) {
  ( spin:body UNDEF UNDEF UNDEF )
  ( UNDEF "the body of the Template" UNDEF UNDEF )
  ( UNDEF UNDEF 0 UNDEF )
  ( UNDEF UNDEF UNDEF 1 )
}

and not simply

VALUES ( ?predicate ?comment ?minCount ?maxCount ) {
  ( spin:body "the body of the Template" 0 1 )
}


And then what do I do with expressions like FILTER (bound(?maxCount))
which are used in SPIN's internal queries to "switch off" graph
patterns (as I understand it) in the absence of the ?maxCount binding.
It does not seem to have the same effect with VALUES.




On Mon, Jul 6, 2020 at 11:28 AM Andy Seaborne <an...@apache.org> wrote:
>
> "bound()" is not a function in the strict sense.
>
> Another case where variables are necessary is "AS ?var"
>
> Long version:
> https://afs.github.io/substitute.html
>
> The advantage of using VALUES or BIND to inject the substitution value
> is that it preserves the original variable.
>
> Contrast the difference between these two:
>
>    QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
>    QueryFactory.create("SELECT * { "+bn+" ?p ?o }");
>
> BIND(?minCount AS ?mc) FILTER bound(?mc)
>
>      Andy
>
> On 06/07/2020 09:56, Martynas Jusevičius wrote:
> > The same problem (invalid query string) using
> > QueryTransformOps.transformQuery().
> >
> > On Sun, Jul 5, 2020 at 11:34 PM Martynas Jusevičius
> > <ma...@atomgraph.com> wrote:
> >>
> >> ParameterizedSparqlString does not work either (not related to bnodes).
> >>
> >> With a mapping ?minCount => 0, it produces an invalid query string:
> >>
> >> SELECT  (count(*) AS ?cardinality)
> >>          WHERE
> >>            { <http://spinrdf.org/spin#Templates>
> >> <http://spinrdf.org/spin#body>  ?value
> >>              FILTER bound(0)
> >>            }
> >>          HAVING ( ?cardinality < 0 )
> >>
> >> On Sun, Jul 5, 2020 at 10:31 PM Andy Seaborne <an...@apache.org> wrote:
> >>>
> >>>
> >>>
> >>> On 05/07/2020 20:36, Martynas Jusevičius wrote:
> >>>> Thanks for the explanation.
> >>>>
> >>>> What do you mean with "inject" in 1/? ParameterizedSparqlString?
> >>>
> >>> initialBinding is done by making the starting condition for execution a
> >>> binding of the variables instead of the empty root. (This works nearly
> >>> always but is affected by variable name scopes - scopes, like subquery,
> >>> didn't exist when the mechanism was introduced.
> >>>
> >>> ParameterizedSparqlString builds which is parsed so you should be able
> >>> to put in <_:....>.
> >>>
> >>>       Andy
> >>>
> >>>>
> >>>> On Sun, Jul 5, 2020 at 8:53 PM Andy Seaborne <an...@apache.org> wrote:
> >>>>>
> >>>>> <_:label> is a syntax feature, not built into the storage or query
> >>>>> execution.
> >>>>>
> >>>>> model.createResource("_:" + id));
> >>>>>
> >>>>> creates a resource with a strange URI (which is actually illegal by RFC
> >>>>> 3986/7).
> >>>>>
> >>>>> There are various ways:
> >>>>>
> >>>>> 1/ The app can put the bnode into the QSM and injected at execution - it
> >>>>> won't become a bnode-variable because that happens in parsing.
> >>>>>
> >>>>> 2/ To put a concrete node into a query:
> >>>>>
> >>>>> String bn = "<_:" + id+">";
> >>>>>
> >>>>> then put string into SPARQL syntax:
> >>>>>
> >>>>> QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
> >>>>> QueryFactory.create("SELECT * { "+bn+" ?p ?o }");
> >>>>>
> >>>>> 3/ rewrite the abstract syntax after parsing:
> >>>>>
> >>>>> Map<String, Resource> substitutions =
> >>>>>      Collections.singletonMap("s", bnode);
> >>>>> query = QueryFactory.create("SELECT * { ?s ?p ?o }");
> >>>>> query = QueryTransformOps.transformQuery(query, substitutions);
> >>>>>
> >>>>> Forms 2 and 3 have the advantage of not relying on how execution works -
> >>>>> QSMs are ingested inthe start of execution and e.g. aren't visible in
> >>>>> subqueries and also interact and bypass with query optimization.
> >>>>>
> >>>>>        Andy
> >>>>>
> >>>>> On 05/07/2020 15:22, Martynas Jusevičius wrote:
> >>>>>> Hi,
> >>>>>>
> >>>>>> I came across a situation where I want to carry over a blank node ID
> >>>>>> in a QuerySolutionMap to QueryExecution, to match exact blank node
> >>>>>> resources rather than have them as variables.
> >>>>>>
> >>>>>> I found an old thread by Holger on this topic:
> >>>>>> https://mail-archives.apache.org/mod_mbox/jena-users/201308.mbox/browser
> >>>>>>
> >>>>>> The suggestion was to use <_:LABEL> URI scheme for blank nodes.
> >>>>>> https://jena.apache.org/documentation/query/extension.html#blank-node-labels
> >>>>>>
> >>>>>> Based on that, I tried this logic:
> >>>>>>
> >>>>>>        if (instance.isURIResource()) qsm.add(SPIN.THIS_VAR_NAME, instance);
> >>>>>>        if (instance.isAnon()) qsm.add(SPIN.THIS_VAR_NAME,
> >>>>>> model.createResource("_:" + instance.getId()));
> >>>>>>
> >>>>>> However I'm not getting the results I expect. So I decided to make an
> >>>>>> isolated test:
> >>>>>>
> >>>>>>        @Test
> >>>>>>        public void bnodeQueryTest()
> >>>>>>        {
> >>>>>>            Model model = ModelFactory.createDefaultModel();
> >>>>>>            Resource bnode = model.createResource().addProperty(FOAF.name,
> >>>>>> "whateverest");
> >>>>>>            AnonId id = bnode.getId();
> >>>>>>
> >>>>>>            Query query = QueryFactory.create("SELECT * { ?s ?p ?o }");
> >>>>>>            QuerySolutionMap qsm = new QuerySolutionMap();
> >>>>>>            qsm.add("s", model.createResource("_:" + id));
> >>>>>>
> >>>>>>            try (QueryExecution qex = QueryExecutionFactory.create(query,
> >>>>>> model, qsm))
> >>>>>>            {
> >>>>>>                ResultSet resultSet = qex.execSelect();
> >>>>>>
> >>>>>>                assertTrue(resultSet.hasNext());
> >>>>>>                assertEquals(id, resultSet.next().get("s").asResource().getId());
> >>>>>>            }
> >>>>>>        }
> >>>>>>
> >>>>>> The test fails on assertTrue() because SELECT returns no results.
> >>>>>>
> >>>>>> Is the test flawed? Am I misunderstanding the use of this URI scheme?
> >>>>>> If not, what's the purpose if it cannot match blank nodes in data?
> >>>>>>
> >>>>>> Martynas
> >>>>>>

Re: Blank node URI scheme

Posted by Andy Seaborne <an...@apache.org>.
The restriction on BOUND(?var) is done as a syntax restriction.
Internally, BOUND(constant) is possible and is true (it's a variable 
replaced so it is true) and will execute.

See JENA-1044.

On 06/07/2020 15:39, Martynas Jusevičius wrote:
> As I'm reading the spec, bound() is used with variables:
> https://www.w3.org/TR/sparql11-query/#func-bound
> 
> However QueryTransformOps.transformQuery() produces a query that looks
> like this:
> 
> SELECT  *
> WHERE
>    { <http://data/instance>
>                <http://xmlns.com/foaf/0.1/maker>  ?value
>      FILTER bound(1)
>    }
> 
> Which is invalid syntax in principle, but does execute successfully
> using execSelect().
> 
> How should that be interpreted?
> 
> On Mon, Jul 6, 2020 at 11:28 AM Andy Seaborne <an...@apache.org> wrote:
>>
>> "bound()" is not a function in the strict sense.
>>
>> Another case where variables are necessary is "AS ?var"
>>
>> Long version:
>> https://afs.github.io/substitute.html
>>
>> The advantage of using VALUES or BIND to inject the substitution value
>> is that it preserves the original variable.
>>
>> Contrast the difference between these two:
>>
>>     QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
>>     QueryFactory.create("SELECT * { "+bn+" ?p ?o }");
>>
>> BIND(?minCount AS ?mc) FILTER bound(?mc)
>>
>>       Andy
>>
>> On 06/07/2020 09:56, Martynas Jusevičius wrote:
>>> The same problem (invalid query string) using
>>> QueryTransformOps.transformQuery().
>>>
>>> On Sun, Jul 5, 2020 at 11:34 PM Martynas Jusevičius
>>> <ma...@atomgraph.com> wrote:
>>>>
>>>> ParameterizedSparqlString does not work either (not related to bnodes).
>>>>
>>>> With a mapping ?minCount => 0, it produces an invalid query string:
>>>>
>>>> SELECT  (count(*) AS ?cardinality)
>>>>           WHERE
>>>>             { <http://spinrdf.org/spin#Templates>
>>>> <http://spinrdf.org/spin#body>  ?value
>>>>               FILTER bound(0)
>>>>             }
>>>>           HAVING ( ?cardinality < 0 )
>>>>
>>>> On Sun, Jul 5, 2020 at 10:31 PM Andy Seaborne <an...@apache.org> wrote:
>>>>>
>>>>>
>>>>>
>>>>> On 05/07/2020 20:36, Martynas Jusevičius wrote:
>>>>>> Thanks for the explanation.
>>>>>>
>>>>>> What do you mean with "inject" in 1/? ParameterizedSparqlString?
>>>>>
>>>>> initialBinding is done by making the starting condition for execution a
>>>>> binding of the variables instead of the empty root. (This works nearly
>>>>> always but is affected by variable name scopes - scopes, like subquery,
>>>>> didn't exist when the mechanism was introduced.
>>>>>
>>>>> ParameterizedSparqlString builds which is parsed so you should be able
>>>>> to put in <_:....>.
>>>>>
>>>>>        Andy
>>>>>
>>>>>>
>>>>>> On Sun, Jul 5, 2020 at 8:53 PM Andy Seaborne <an...@apache.org> wrote:
>>>>>>>
>>>>>>> <_:label> is a syntax feature, not built into the storage or query
>>>>>>> execution.
>>>>>>>
>>>>>>> model.createResource("_:" + id));
>>>>>>>
>>>>>>> creates a resource with a strange URI (which is actually illegal by RFC
>>>>>>> 3986/7).
>>>>>>>
>>>>>>> There are various ways:
>>>>>>>
>>>>>>> 1/ The app can put the bnode into the QSM and injected at execution - it
>>>>>>> won't become a bnode-variable because that happens in parsing.
>>>>>>>
>>>>>>> 2/ To put a concrete node into a query:
>>>>>>>
>>>>>>> String bn = "<_:" + id+">";
>>>>>>>
>>>>>>> then put string into SPARQL syntax:
>>>>>>>
>>>>>>> QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
>>>>>>> QueryFactory.create("SELECT * { "+bn+" ?p ?o }");
>>>>>>>
>>>>>>> 3/ rewrite the abstract syntax after parsing:
>>>>>>>
>>>>>>> Map<String, Resource> substitutions =
>>>>>>>       Collections.singletonMap("s", bnode);
>>>>>>> query = QueryFactory.create("SELECT * { ?s ?p ?o }");
>>>>>>> query = QueryTransformOps.transformQuery(query, substitutions);
>>>>>>>
>>>>>>> Forms 2 and 3 have the advantage of not relying on how execution works -
>>>>>>> QSMs are ingested inthe start of execution and e.g. aren't visible in
>>>>>>> subqueries and also interact and bypass with query optimization.
>>>>>>>
>>>>>>>         Andy
>>>>>>>
>>>>>>> On 05/07/2020 15:22, Martynas Jusevičius wrote:
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> I came across a situation where I want to carry over a blank node ID
>>>>>>>> in a QuerySolutionMap to QueryExecution, to match exact blank node
>>>>>>>> resources rather than have them as variables.
>>>>>>>>
>>>>>>>> I found an old thread by Holger on this topic:
>>>>>>>> https://mail-archives.apache.org/mod_mbox/jena-users/201308.mbox/browser
>>>>>>>>
>>>>>>>> The suggestion was to use <_:LABEL> URI scheme for blank nodes.
>>>>>>>> https://jena.apache.org/documentation/query/extension.html#blank-node-labels
>>>>>>>>
>>>>>>>> Based on that, I tried this logic:
>>>>>>>>
>>>>>>>>         if (instance.isURIResource()) qsm.add(SPIN.THIS_VAR_NAME, instance);
>>>>>>>>         if (instance.isAnon()) qsm.add(SPIN.THIS_VAR_NAME,
>>>>>>>> model.createResource("_:" + instance.getId()));
>>>>>>>>
>>>>>>>> However I'm not getting the results I expect. So I decided to make an
>>>>>>>> isolated test:
>>>>>>>>
>>>>>>>>         @Test
>>>>>>>>         public void bnodeQueryTest()
>>>>>>>>         {
>>>>>>>>             Model model = ModelFactory.createDefaultModel();
>>>>>>>>             Resource bnode = model.createResource().addProperty(FOAF.name,
>>>>>>>> "whateverest");
>>>>>>>>             AnonId id = bnode.getId();
>>>>>>>>
>>>>>>>>             Query query = QueryFactory.create("SELECT * { ?s ?p ?o }");
>>>>>>>>             QuerySolutionMap qsm = new QuerySolutionMap();
>>>>>>>>             qsm.add("s", model.createResource("_:" + id));
>>>>>>>>
>>>>>>>>             try (QueryExecution qex = QueryExecutionFactory.create(query,
>>>>>>>> model, qsm))
>>>>>>>>             {
>>>>>>>>                 ResultSet resultSet = qex.execSelect();
>>>>>>>>
>>>>>>>>                 assertTrue(resultSet.hasNext());
>>>>>>>>                 assertEquals(id, resultSet.next().get("s").asResource().getId());
>>>>>>>>             }
>>>>>>>>         }
>>>>>>>>
>>>>>>>> The test fails on assertTrue() because SELECT returns no results.
>>>>>>>>
>>>>>>>> Is the test flawed? Am I misunderstanding the use of this URI scheme?
>>>>>>>> If not, what's the purpose if it cannot match blank nodes in data?
>>>>>>>>
>>>>>>>> Martynas
>>>>>>>>

Re: Blank node URI scheme

Posted by Martynas Jusevičius <ma...@atomgraph.com>.
As I'm reading the spec, bound() is used with variables:
https://www.w3.org/TR/sparql11-query/#func-bound

However QueryTransformOps.transformQuery() produces a query that looks
like this:

SELECT  *
WHERE
  { <http://data/instance>
              <http://xmlns.com/foaf/0.1/maker>  ?value
    FILTER bound(1)
  }

Which is invalid syntax in principle, but does execute successfully
using execSelect().

How should that be interpreted?

On Mon, Jul 6, 2020 at 11:28 AM Andy Seaborne <an...@apache.org> wrote:
>
> "bound()" is not a function in the strict sense.
>
> Another case where variables are necessary is "AS ?var"
>
> Long version:
> https://afs.github.io/substitute.html
>
> The advantage of using VALUES or BIND to inject the substitution value
> is that it preserves the original variable.
>
> Contrast the difference between these two:
>
>    QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
>    QueryFactory.create("SELECT * { "+bn+" ?p ?o }");
>
> BIND(?minCount AS ?mc) FILTER bound(?mc)
>
>      Andy
>
> On 06/07/2020 09:56, Martynas Jusevičius wrote:
> > The same problem (invalid query string) using
> > QueryTransformOps.transformQuery().
> >
> > On Sun, Jul 5, 2020 at 11:34 PM Martynas Jusevičius
> > <ma...@atomgraph.com> wrote:
> >>
> >> ParameterizedSparqlString does not work either (not related to bnodes).
> >>
> >> With a mapping ?minCount => 0, it produces an invalid query string:
> >>
> >> SELECT  (count(*) AS ?cardinality)
> >>          WHERE
> >>            { <http://spinrdf.org/spin#Templates>
> >> <http://spinrdf.org/spin#body>  ?value
> >>              FILTER bound(0)
> >>            }
> >>          HAVING ( ?cardinality < 0 )
> >>
> >> On Sun, Jul 5, 2020 at 10:31 PM Andy Seaborne <an...@apache.org> wrote:
> >>>
> >>>
> >>>
> >>> On 05/07/2020 20:36, Martynas Jusevičius wrote:
> >>>> Thanks for the explanation.
> >>>>
> >>>> What do you mean with "inject" in 1/? ParameterizedSparqlString?
> >>>
> >>> initialBinding is done by making the starting condition for execution a
> >>> binding of the variables instead of the empty root. (This works nearly
> >>> always but is affected by variable name scopes - scopes, like subquery,
> >>> didn't exist when the mechanism was introduced.
> >>>
> >>> ParameterizedSparqlString builds which is parsed so you should be able
> >>> to put in <_:....>.
> >>>
> >>>       Andy
> >>>
> >>>>
> >>>> On Sun, Jul 5, 2020 at 8:53 PM Andy Seaborne <an...@apache.org> wrote:
> >>>>>
> >>>>> <_:label> is a syntax feature, not built into the storage or query
> >>>>> execution.
> >>>>>
> >>>>> model.createResource("_:" + id));
> >>>>>
> >>>>> creates a resource with a strange URI (which is actually illegal by RFC
> >>>>> 3986/7).
> >>>>>
> >>>>> There are various ways:
> >>>>>
> >>>>> 1/ The app can put the bnode into the QSM and injected at execution - it
> >>>>> won't become a bnode-variable because that happens in parsing.
> >>>>>
> >>>>> 2/ To put a concrete node into a query:
> >>>>>
> >>>>> String bn = "<_:" + id+">";
> >>>>>
> >>>>> then put string into SPARQL syntax:
> >>>>>
> >>>>> QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
> >>>>> QueryFactory.create("SELECT * { "+bn+" ?p ?o }");
> >>>>>
> >>>>> 3/ rewrite the abstract syntax after parsing:
> >>>>>
> >>>>> Map<String, Resource> substitutions =
> >>>>>      Collections.singletonMap("s", bnode);
> >>>>> query = QueryFactory.create("SELECT * { ?s ?p ?o }");
> >>>>> query = QueryTransformOps.transformQuery(query, substitutions);
> >>>>>
> >>>>> Forms 2 and 3 have the advantage of not relying on how execution works -
> >>>>> QSMs are ingested inthe start of execution and e.g. aren't visible in
> >>>>> subqueries and also interact and bypass with query optimization.
> >>>>>
> >>>>>        Andy
> >>>>>
> >>>>> On 05/07/2020 15:22, Martynas Jusevičius wrote:
> >>>>>> Hi,
> >>>>>>
> >>>>>> I came across a situation where I want to carry over a blank node ID
> >>>>>> in a QuerySolutionMap to QueryExecution, to match exact blank node
> >>>>>> resources rather than have them as variables.
> >>>>>>
> >>>>>> I found an old thread by Holger on this topic:
> >>>>>> https://mail-archives.apache.org/mod_mbox/jena-users/201308.mbox/browser
> >>>>>>
> >>>>>> The suggestion was to use <_:LABEL> URI scheme for blank nodes.
> >>>>>> https://jena.apache.org/documentation/query/extension.html#blank-node-labels
> >>>>>>
> >>>>>> Based on that, I tried this logic:
> >>>>>>
> >>>>>>        if (instance.isURIResource()) qsm.add(SPIN.THIS_VAR_NAME, instance);
> >>>>>>        if (instance.isAnon()) qsm.add(SPIN.THIS_VAR_NAME,
> >>>>>> model.createResource("_:" + instance.getId()));
> >>>>>>
> >>>>>> However I'm not getting the results I expect. So I decided to make an
> >>>>>> isolated test:
> >>>>>>
> >>>>>>        @Test
> >>>>>>        public void bnodeQueryTest()
> >>>>>>        {
> >>>>>>            Model model = ModelFactory.createDefaultModel();
> >>>>>>            Resource bnode = model.createResource().addProperty(FOAF.name,
> >>>>>> "whateverest");
> >>>>>>            AnonId id = bnode.getId();
> >>>>>>
> >>>>>>            Query query = QueryFactory.create("SELECT * { ?s ?p ?o }");
> >>>>>>            QuerySolutionMap qsm = new QuerySolutionMap();
> >>>>>>            qsm.add("s", model.createResource("_:" + id));
> >>>>>>
> >>>>>>            try (QueryExecution qex = QueryExecutionFactory.create(query,
> >>>>>> model, qsm))
> >>>>>>            {
> >>>>>>                ResultSet resultSet = qex.execSelect();
> >>>>>>
> >>>>>>                assertTrue(resultSet.hasNext());
> >>>>>>                assertEquals(id, resultSet.next().get("s").asResource().getId());
> >>>>>>            }
> >>>>>>        }
> >>>>>>
> >>>>>> The test fails on assertTrue() because SELECT returns no results.
> >>>>>>
> >>>>>> Is the test flawed? Am I misunderstanding the use of this URI scheme?
> >>>>>> If not, what's the purpose if it cannot match blank nodes in data?
> >>>>>>
> >>>>>> Martynas
> >>>>>>

Re: Blank node URI scheme

Posted by Andy Seaborne <an...@apache.org>.
"bound()" is not a function in the strict sense.

Another case where variables are necessary is "AS ?var"

Long version:
https://afs.github.io/substitute.html

The advantage of using VALUES or BIND to inject the substitution value 
is that it preserves the original variable.

Contrast the difference between these two:

   QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
   QueryFactory.create("SELECT * { "+bn+" ?p ?o }");

BIND(?minCount AS ?mc) FILTER bound(?mc)

     Andy

On 06/07/2020 09:56, Martynas Jusevičius wrote:
> The same problem (invalid query string) using
> QueryTransformOps.transformQuery().
> 
> On Sun, Jul 5, 2020 at 11:34 PM Martynas Jusevičius
> <ma...@atomgraph.com> wrote:
>>
>> ParameterizedSparqlString does not work either (not related to bnodes).
>>
>> With a mapping ?minCount => 0, it produces an invalid query string:
>>
>> SELECT  (count(*) AS ?cardinality)
>>          WHERE
>>            { <http://spinrdf.org/spin#Templates>
>> <http://spinrdf.org/spin#body>  ?value
>>              FILTER bound(0)
>>            }
>>          HAVING ( ?cardinality < 0 )
>>
>> On Sun, Jul 5, 2020 at 10:31 PM Andy Seaborne <an...@apache.org> wrote:
>>>
>>>
>>>
>>> On 05/07/2020 20:36, Martynas Jusevičius wrote:
>>>> Thanks for the explanation.
>>>>
>>>> What do you mean with "inject" in 1/? ParameterizedSparqlString?
>>>
>>> initialBinding is done by making the starting condition for execution a
>>> binding of the variables instead of the empty root. (This works nearly
>>> always but is affected by variable name scopes - scopes, like subquery,
>>> didn't exist when the mechanism was introduced.
>>>
>>> ParameterizedSparqlString builds which is parsed so you should be able
>>> to put in <_:....>.
>>>
>>>       Andy
>>>
>>>>
>>>> On Sun, Jul 5, 2020 at 8:53 PM Andy Seaborne <an...@apache.org> wrote:
>>>>>
>>>>> <_:label> is a syntax feature, not built into the storage or query
>>>>> execution.
>>>>>
>>>>> model.createResource("_:" + id));
>>>>>
>>>>> creates a resource with a strange URI (which is actually illegal by RFC
>>>>> 3986/7).
>>>>>
>>>>> There are various ways:
>>>>>
>>>>> 1/ The app can put the bnode into the QSM and injected at execution - it
>>>>> won't become a bnode-variable because that happens in parsing.
>>>>>
>>>>> 2/ To put a concrete node into a query:
>>>>>
>>>>> String bn = "<_:" + id+">";
>>>>>
>>>>> then put string into SPARQL syntax:
>>>>>
>>>>> QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
>>>>> QueryFactory.create("SELECT * { "+bn+" ?p ?o }");
>>>>>
>>>>> 3/ rewrite the abstract syntax after parsing:
>>>>>
>>>>> Map<String, Resource> substitutions =
>>>>>      Collections.singletonMap("s", bnode);
>>>>> query = QueryFactory.create("SELECT * { ?s ?p ?o }");
>>>>> query = QueryTransformOps.transformQuery(query, substitutions);
>>>>>
>>>>> Forms 2 and 3 have the advantage of not relying on how execution works -
>>>>> QSMs are ingested inthe start of execution and e.g. aren't visible in
>>>>> subqueries and also interact and bypass with query optimization.
>>>>>
>>>>>        Andy
>>>>>
>>>>> On 05/07/2020 15:22, Martynas Jusevičius wrote:
>>>>>> Hi,
>>>>>>
>>>>>> I came across a situation where I want to carry over a blank node ID
>>>>>> in a QuerySolutionMap to QueryExecution, to match exact blank node
>>>>>> resources rather than have them as variables.
>>>>>>
>>>>>> I found an old thread by Holger on this topic:
>>>>>> https://mail-archives.apache.org/mod_mbox/jena-users/201308.mbox/browser
>>>>>>
>>>>>> The suggestion was to use <_:LABEL> URI scheme for blank nodes.
>>>>>> https://jena.apache.org/documentation/query/extension.html#blank-node-labels
>>>>>>
>>>>>> Based on that, I tried this logic:
>>>>>>
>>>>>>        if (instance.isURIResource()) qsm.add(SPIN.THIS_VAR_NAME, instance);
>>>>>>        if (instance.isAnon()) qsm.add(SPIN.THIS_VAR_NAME,
>>>>>> model.createResource("_:" + instance.getId()));
>>>>>>
>>>>>> However I'm not getting the results I expect. So I decided to make an
>>>>>> isolated test:
>>>>>>
>>>>>>        @Test
>>>>>>        public void bnodeQueryTest()
>>>>>>        {
>>>>>>            Model model = ModelFactory.createDefaultModel();
>>>>>>            Resource bnode = model.createResource().addProperty(FOAF.name,
>>>>>> "whateverest");
>>>>>>            AnonId id = bnode.getId();
>>>>>>
>>>>>>            Query query = QueryFactory.create("SELECT * { ?s ?p ?o }");
>>>>>>            QuerySolutionMap qsm = new QuerySolutionMap();
>>>>>>            qsm.add("s", model.createResource("_:" + id));
>>>>>>
>>>>>>            try (QueryExecution qex = QueryExecutionFactory.create(query,
>>>>>> model, qsm))
>>>>>>            {
>>>>>>                ResultSet resultSet = qex.execSelect();
>>>>>>
>>>>>>                assertTrue(resultSet.hasNext());
>>>>>>                assertEquals(id, resultSet.next().get("s").asResource().getId());
>>>>>>            }
>>>>>>        }
>>>>>>
>>>>>> The test fails on assertTrue() because SELECT returns no results.
>>>>>>
>>>>>> Is the test flawed? Am I misunderstanding the use of this URI scheme?
>>>>>> If not, what's the purpose if it cannot match blank nodes in data?
>>>>>>
>>>>>> Martynas
>>>>>>

Re: Blank node URI scheme

Posted by Martynas Jusevičius <ma...@atomgraph.com>.
The same problem (invalid query string) using
QueryTransformOps.transformQuery().

On Sun, Jul 5, 2020 at 11:34 PM Martynas Jusevičius
<ma...@atomgraph.com> wrote:
>
> ParameterizedSparqlString does not work either (not related to bnodes).
>
> With a mapping ?minCount => 0, it produces an invalid query string:
>
> SELECT  (count(*) AS ?cardinality)
>         WHERE
>           { <http://spinrdf.org/spin#Templates>
> <http://spinrdf.org/spin#body>  ?value
>             FILTER bound(0)
>           }
>         HAVING ( ?cardinality < 0 )
>
> On Sun, Jul 5, 2020 at 10:31 PM Andy Seaborne <an...@apache.org> wrote:
> >
> >
> >
> > On 05/07/2020 20:36, Martynas Jusevičius wrote:
> > > Thanks for the explanation.
> > >
> > > What do you mean with "inject" in 1/? ParameterizedSparqlString?
> >
> > initialBinding is done by making the starting condition for execution a
> > binding of the variables instead of the empty root. (This works nearly
> > always but is affected by variable name scopes - scopes, like subquery,
> > didn't exist when the mechanism was introduced.
> >
> > ParameterizedSparqlString builds which is parsed so you should be able
> > to put in <_:....>.
> >
> >      Andy
> >
> > >
> > > On Sun, Jul 5, 2020 at 8:53 PM Andy Seaborne <an...@apache.org> wrote:
> > >>
> > >> <_:label> is a syntax feature, not built into the storage or query
> > >> execution.
> > >>
> > >> model.createResource("_:" + id));
> > >>
> > >> creates a resource with a strange URI (which is actually illegal by RFC
> > >> 3986/7).
> > >>
> > >> There are various ways:
> > >>
> > >> 1/ The app can put the bnode into the QSM and injected at execution - it
> > >> won't become a bnode-variable because that happens in parsing.
> > >>
> > >> 2/ To put a concrete node into a query:
> > >>
> > >> String bn = "<_:" + id+">";
> > >>
> > >> then put string into SPARQL syntax:
> > >>
> > >> QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
> > >> QueryFactory.create("SELECT * { "+bn+" ?p ?o }");
> > >>
> > >> 3/ rewrite the abstract syntax after parsing:
> > >>
> > >> Map<String, Resource> substitutions =
> > >>     Collections.singletonMap("s", bnode);
> > >> query = QueryFactory.create("SELECT * { ?s ?p ?o }");
> > >> query = QueryTransformOps.transformQuery(query, substitutions);
> > >>
> > >> Forms 2 and 3 have the advantage of not relying on how execution works -
> > >> QSMs are ingested inthe start of execution and e.g. aren't visible in
> > >> subqueries and also interact and bypass with query optimization.
> > >>
> > >>       Andy
> > >>
> > >> On 05/07/2020 15:22, Martynas Jusevičius wrote:
> > >>> Hi,
> > >>>
> > >>> I came across a situation where I want to carry over a blank node ID
> > >>> in a QuerySolutionMap to QueryExecution, to match exact blank node
> > >>> resources rather than have them as variables.
> > >>>
> > >>> I found an old thread by Holger on this topic:
> > >>> https://mail-archives.apache.org/mod_mbox/jena-users/201308.mbox/browser
> > >>>
> > >>> The suggestion was to use <_:LABEL> URI scheme for blank nodes.
> > >>> https://jena.apache.org/documentation/query/extension.html#blank-node-labels
> > >>>
> > >>> Based on that, I tried this logic:
> > >>>
> > >>>       if (instance.isURIResource()) qsm.add(SPIN.THIS_VAR_NAME, instance);
> > >>>       if (instance.isAnon()) qsm.add(SPIN.THIS_VAR_NAME,
> > >>> model.createResource("_:" + instance.getId()));
> > >>>
> > >>> However I'm not getting the results I expect. So I decided to make an
> > >>> isolated test:
> > >>>
> > >>>       @Test
> > >>>       public void bnodeQueryTest()
> > >>>       {
> > >>>           Model model = ModelFactory.createDefaultModel();
> > >>>           Resource bnode = model.createResource().addProperty(FOAF.name,
> > >>> "whateverest");
> > >>>           AnonId id = bnode.getId();
> > >>>
> > >>>           Query query = QueryFactory.create("SELECT * { ?s ?p ?o }");
> > >>>           QuerySolutionMap qsm = new QuerySolutionMap();
> > >>>           qsm.add("s", model.createResource("_:" + id));
> > >>>
> > >>>           try (QueryExecution qex = QueryExecutionFactory.create(query,
> > >>> model, qsm))
> > >>>           {
> > >>>               ResultSet resultSet = qex.execSelect();
> > >>>
> > >>>               assertTrue(resultSet.hasNext());
> > >>>               assertEquals(id, resultSet.next().get("s").asResource().getId());
> > >>>           }
> > >>>       }
> > >>>
> > >>> The test fails on assertTrue() because SELECT returns no results.
> > >>>
> > >>> Is the test flawed? Am I misunderstanding the use of this URI scheme?
> > >>> If not, what's the purpose if it cannot match blank nodes in data?
> > >>>
> > >>> Martynas
> > >>>

Re: Blank node URI scheme

Posted by Martynas Jusevičius <ma...@atomgraph.com>.
ParameterizedSparqlString does not work either (not related to bnodes).

With a mapping ?minCount => 0, it produces an invalid query string:

SELECT  (count(*) AS ?cardinality)
        WHERE
          { <http://spinrdf.org/spin#Templates>
<http://spinrdf.org/spin#body>  ?value
            FILTER bound(0)
          }
        HAVING ( ?cardinality < 0 )

On Sun, Jul 5, 2020 at 10:31 PM Andy Seaborne <an...@apache.org> wrote:
>
>
>
> On 05/07/2020 20:36, Martynas Jusevičius wrote:
> > Thanks for the explanation.
> >
> > What do you mean with "inject" in 1/? ParameterizedSparqlString?
>
> initialBinding is done by making the starting condition for execution a
> binding of the variables instead of the empty root. (This works nearly
> always but is affected by variable name scopes - scopes, like subquery,
> didn't exist when the mechanism was introduced.
>
> ParameterizedSparqlString builds which is parsed so you should be able
> to put in <_:....>.
>
>      Andy
>
> >
> > On Sun, Jul 5, 2020 at 8:53 PM Andy Seaborne <an...@apache.org> wrote:
> >>
> >> <_:label> is a syntax feature, not built into the storage or query
> >> execution.
> >>
> >> model.createResource("_:" + id));
> >>
> >> creates a resource with a strange URI (which is actually illegal by RFC
> >> 3986/7).
> >>
> >> There are various ways:
> >>
> >> 1/ The app can put the bnode into the QSM and injected at execution - it
> >> won't become a bnode-variable because that happens in parsing.
> >>
> >> 2/ To put a concrete node into a query:
> >>
> >> String bn = "<_:" + id+">";
> >>
> >> then put string into SPARQL syntax:
> >>
> >> QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
> >> QueryFactory.create("SELECT * { "+bn+" ?p ?o }");
> >>
> >> 3/ rewrite the abstract syntax after parsing:
> >>
> >> Map<String, Resource> substitutions =
> >>     Collections.singletonMap("s", bnode);
> >> query = QueryFactory.create("SELECT * { ?s ?p ?o }");
> >> query = QueryTransformOps.transformQuery(query, substitutions);
> >>
> >> Forms 2 and 3 have the advantage of not relying on how execution works -
> >> QSMs are ingested inthe start of execution and e.g. aren't visible in
> >> subqueries and also interact and bypass with query optimization.
> >>
> >>       Andy
> >>
> >> On 05/07/2020 15:22, Martynas Jusevičius wrote:
> >>> Hi,
> >>>
> >>> I came across a situation where I want to carry over a blank node ID
> >>> in a QuerySolutionMap to QueryExecution, to match exact blank node
> >>> resources rather than have them as variables.
> >>>
> >>> I found an old thread by Holger on this topic:
> >>> https://mail-archives.apache.org/mod_mbox/jena-users/201308.mbox/browser
> >>>
> >>> The suggestion was to use <_:LABEL> URI scheme for blank nodes.
> >>> https://jena.apache.org/documentation/query/extension.html#blank-node-labels
> >>>
> >>> Based on that, I tried this logic:
> >>>
> >>>       if (instance.isURIResource()) qsm.add(SPIN.THIS_VAR_NAME, instance);
> >>>       if (instance.isAnon()) qsm.add(SPIN.THIS_VAR_NAME,
> >>> model.createResource("_:" + instance.getId()));
> >>>
> >>> However I'm not getting the results I expect. So I decided to make an
> >>> isolated test:
> >>>
> >>>       @Test
> >>>       public void bnodeQueryTest()
> >>>       {
> >>>           Model model = ModelFactory.createDefaultModel();
> >>>           Resource bnode = model.createResource().addProperty(FOAF.name,
> >>> "whateverest");
> >>>           AnonId id = bnode.getId();
> >>>
> >>>           Query query = QueryFactory.create("SELECT * { ?s ?p ?o }");
> >>>           QuerySolutionMap qsm = new QuerySolutionMap();
> >>>           qsm.add("s", model.createResource("_:" + id));
> >>>
> >>>           try (QueryExecution qex = QueryExecutionFactory.create(query,
> >>> model, qsm))
> >>>           {
> >>>               ResultSet resultSet = qex.execSelect();
> >>>
> >>>               assertTrue(resultSet.hasNext());
> >>>               assertEquals(id, resultSet.next().get("s").asResource().getId());
> >>>           }
> >>>       }
> >>>
> >>> The test fails on assertTrue() because SELECT returns no results.
> >>>
> >>> Is the test flawed? Am I misunderstanding the use of this URI scheme?
> >>> If not, what's the purpose if it cannot match blank nodes in data?
> >>>
> >>> Martynas
> >>>

Re: Blank node URI scheme

Posted by Andy Seaborne <an...@apache.org>.

On 05/07/2020 20:36, Martynas Jusevičius wrote:
> Thanks for the explanation.
> 
> What do you mean with "inject" in 1/? ParameterizedSparqlString?

initialBinding is done by making the starting condition for execution a 
binding of the variables instead of the empty root. (This works nearly 
always but is affected by variable name scopes - scopes, like subquery, 
didn't exist when the mechanism was introduced.

ParameterizedSparqlString builds which is parsed so you should be able 
to put in <_:....>.

     Andy

> 
> On Sun, Jul 5, 2020 at 8:53 PM Andy Seaborne <an...@apache.org> wrote:
>>
>> <_:label> is a syntax feature, not built into the storage or query
>> execution.
>>
>> model.createResource("_:" + id));
>>
>> creates a resource with a strange URI (which is actually illegal by RFC
>> 3986/7).
>>
>> There are various ways:
>>
>> 1/ The app can put the bnode into the QSM and injected at execution - it
>> won't become a bnode-variable because that happens in parsing.
>>
>> 2/ To put a concrete node into a query:
>>
>> String bn = "<_:" + id+">";
>>
>> then put string into SPARQL syntax:
>>
>> QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
>> QueryFactory.create("SELECT * { "+bn+" ?p ?o }");
>>
>> 3/ rewrite the abstract syntax after parsing:
>>
>> Map<String, Resource> substitutions =
>>     Collections.singletonMap("s", bnode);
>> query = QueryFactory.create("SELECT * { ?s ?p ?o }");
>> query = QueryTransformOps.transformQuery(query, substitutions);
>>
>> Forms 2 and 3 have the advantage of not relying on how execution works -
>> QSMs are ingested inthe start of execution and e.g. aren't visible in
>> subqueries and also interact and bypass with query optimization.
>>
>>       Andy
>>
>> On 05/07/2020 15:22, Martynas Jusevičius wrote:
>>> Hi,
>>>
>>> I came across a situation where I want to carry over a blank node ID
>>> in a QuerySolutionMap to QueryExecution, to match exact blank node
>>> resources rather than have them as variables.
>>>
>>> I found an old thread by Holger on this topic:
>>> https://mail-archives.apache.org/mod_mbox/jena-users/201308.mbox/browser
>>>
>>> The suggestion was to use <_:LABEL> URI scheme for blank nodes.
>>> https://jena.apache.org/documentation/query/extension.html#blank-node-labels
>>>
>>> Based on that, I tried this logic:
>>>
>>>       if (instance.isURIResource()) qsm.add(SPIN.THIS_VAR_NAME, instance);
>>>       if (instance.isAnon()) qsm.add(SPIN.THIS_VAR_NAME,
>>> model.createResource("_:" + instance.getId()));
>>>
>>> However I'm not getting the results I expect. So I decided to make an
>>> isolated test:
>>>
>>>       @Test
>>>       public void bnodeQueryTest()
>>>       {
>>>           Model model = ModelFactory.createDefaultModel();
>>>           Resource bnode = model.createResource().addProperty(FOAF.name,
>>> "whateverest");
>>>           AnonId id = bnode.getId();
>>>
>>>           Query query = QueryFactory.create("SELECT * { ?s ?p ?o }");
>>>           QuerySolutionMap qsm = new QuerySolutionMap();
>>>           qsm.add("s", model.createResource("_:" + id));
>>>
>>>           try (QueryExecution qex = QueryExecutionFactory.create(query,
>>> model, qsm))
>>>           {
>>>               ResultSet resultSet = qex.execSelect();
>>>
>>>               assertTrue(resultSet.hasNext());
>>>               assertEquals(id, resultSet.next().get("s").asResource().getId());
>>>           }
>>>       }
>>>
>>> The test fails on assertTrue() because SELECT returns no results.
>>>
>>> Is the test flawed? Am I misunderstanding the use of this URI scheme?
>>> If not, what's the purpose if it cannot match blank nodes in data?
>>>
>>> Martynas
>>>

Re: Blank node URI scheme

Posted by Martynas Jusevičius <ma...@atomgraph.com>.
Thanks for the explanation.

What do you mean with "inject" in 1/? ParameterizedSparqlString?

On Sun, Jul 5, 2020 at 8:53 PM Andy Seaborne <an...@apache.org> wrote:
>
> <_:label> is a syntax feature, not built into the storage or query
> execution.
>
> model.createResource("_:" + id));
>
> creates a resource with a strange URI (which is actually illegal by RFC
> 3986/7).
>
> There are various ways:
>
> 1/ The app can put the bnode into the QSM and injected at execution - it
> won't become a bnode-variable because that happens in parsing.
>
> 2/ To put a concrete node into a query:
>
> String bn = "<_:" + id+">";
>
> then put string into SPARQL syntax:
>
> QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
> QueryFactory.create("SELECT * { "+bn+" ?p ?o }");
>
> 3/ rewrite the abstract syntax after parsing:
>
> Map<String, Resource> substitutions =
>    Collections.singletonMap("s", bnode);
> query = QueryFactory.create("SELECT * { ?s ?p ?o }");
> query = QueryTransformOps.transformQuery(query, substitutions);
>
> Forms 2 and 3 have the advantage of not relying on how execution works -
> QSMs are ingested inthe start of execution and e.g. aren't visible in
> subqueries and also interact and bypass with query optimization.
>
>      Andy
>
> On 05/07/2020 15:22, Martynas Jusevičius wrote:
> > Hi,
> >
> > I came across a situation where I want to carry over a blank node ID
> > in a QuerySolutionMap to QueryExecution, to match exact blank node
> > resources rather than have them as variables.
> >
> > I found an old thread by Holger on this topic:
> > https://mail-archives.apache.org/mod_mbox/jena-users/201308.mbox/browser
> >
> > The suggestion was to use <_:LABEL> URI scheme for blank nodes.
> > https://jena.apache.org/documentation/query/extension.html#blank-node-labels
> >
> > Based on that, I tried this logic:
> >
> >      if (instance.isURIResource()) qsm.add(SPIN.THIS_VAR_NAME, instance);
> >      if (instance.isAnon()) qsm.add(SPIN.THIS_VAR_NAME,
> > model.createResource("_:" + instance.getId()));
> >
> > However I'm not getting the results I expect. So I decided to make an
> > isolated test:
> >
> >      @Test
> >      public void bnodeQueryTest()
> >      {
> >          Model model = ModelFactory.createDefaultModel();
> >          Resource bnode = model.createResource().addProperty(FOAF.name,
> > "whateverest");
> >          AnonId id = bnode.getId();
> >
> >          Query query = QueryFactory.create("SELECT * { ?s ?p ?o }");
> >          QuerySolutionMap qsm = new QuerySolutionMap();
> >          qsm.add("s", model.createResource("_:" + id));
> >
> >          try (QueryExecution qex = QueryExecutionFactory.create(query,
> > model, qsm))
> >          {
> >              ResultSet resultSet = qex.execSelect();
> >
> >              assertTrue(resultSet.hasNext());
> >              assertEquals(id, resultSet.next().get("s").asResource().getId());
> >          }
> >      }
> >
> > The test fails on assertTrue() because SELECT returns no results.
> >
> > Is the test flawed? Am I misunderstanding the use of this URI scheme?
> > If not, what's the purpose if it cannot match blank nodes in data?
> >
> > Martynas
> >

Re: Blank node URI scheme

Posted by Martynas Jusevičius <ma...@atomgraph.com>.
I'm trying approach 3/.

What happens to the CONSTRUCT template though?

The original query:

PREFIX  spin: <http://spinrdf.org/spin#>

CONSTRUCT
  {
    _:c0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
spin:ConstraintViolation .
    _:c0 spin:violationRoot ?this .
    _:c0 spin:violationPath <http://example.com/constrained-predicate> .
    _:c0 spin:violationValue ?object .
  }
WHERE
  { FILTER NOT EXISTS { ?this
<http://example.com/constrained-predicate>  ?object } }

Applied transformation this => http://localhost:8085/default-subject-post

    query = QueryTransformOps.transformQuery(query,
Collections.singletonMap("this",
ResourceFactory.create("http://localhost:8085/default-subject-post")));

Resulting query:

PREFIX  spin: <http://spinrdf.org/spin#>

CONSTRUCT
  {
    _:c0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
spin:ConstraintViolation .
    _:c0 spin:violationRoot ?this .
    _:c0 spin:violationPath <http://example.com/constrained-predicate> .
    _:c0 spin:violationValue ?object .
  }
WHERE
  { FILTER NOT EXISTS { <http://localhost:8085/default-subject-post>

<http://example.com/constrained-predicate>  ?object
                      }
  }

?this mapping is present in WHERE but gets lost in the template, and
produces no triples during execution. Which is not the case using
initialBinding. Is that expected? Does not really address my use case
then.

On Sun, Jul 5, 2020 at 8:53 PM Andy Seaborne <an...@apache.org> wrote:
>
> <_:label> is a syntax feature, not built into the storage or query
> execution.
>
> model.createResource("_:" + id));
>
> creates a resource with a strange URI (which is actually illegal by RFC
> 3986/7).
>
> There are various ways:
>
> 1/ The app can put the bnode into the QSM and injected at execution - it
> won't become a bnode-variable because that happens in parsing.
>
> 2/ To put a concrete node into a query:
>
> String bn = "<_:" + id+">";
>
> then put string into SPARQL syntax:
>
> QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
> QueryFactory.create("SELECT * { "+bn+" ?p ?o }");
>
> 3/ rewrite the abstract syntax after parsing:
>
> Map<String, Resource> substitutions =
>    Collections.singletonMap("s", bnode);
> query = QueryFactory.create("SELECT * { ?s ?p ?o }");
> query = QueryTransformOps.transformQuery(query, substitutions);
>
> Forms 2 and 3 have the advantage of not relying on how execution works -
> QSMs are ingested inthe start of execution and e.g. aren't visible in
> subqueries and also interact and bypass with query optimization.
>
>      Andy
>
> On 05/07/2020 15:22, Martynas Jusevičius wrote:
> > Hi,
> >
> > I came across a situation where I want to carry over a blank node ID
> > in a QuerySolutionMap to QueryExecution, to match exact blank node
> > resources rather than have them as variables.
> >
> > I found an old thread by Holger on this topic:
> > https://mail-archives.apache.org/mod_mbox/jena-users/201308.mbox/browser
> >
> > The suggestion was to use <_:LABEL> URI scheme for blank nodes.
> > https://jena.apache.org/documentation/query/extension.html#blank-node-labels
> >
> > Based on that, I tried this logic:
> >
> >      if (instance.isURIResource()) qsm.add(SPIN.THIS_VAR_NAME, instance);
> >      if (instance.isAnon()) qsm.add(SPIN.THIS_VAR_NAME,
> > model.createResource("_:" + instance.getId()));
> >
> > However I'm not getting the results I expect. So I decided to make an
> > isolated test:
> >
> >      @Test
> >      public void bnodeQueryTest()
> >      {
> >          Model model = ModelFactory.createDefaultModel();
> >          Resource bnode = model.createResource().addProperty(FOAF.name,
> > "whateverest");
> >          AnonId id = bnode.getId();
> >
> >          Query query = QueryFactory.create("SELECT * { ?s ?p ?o }");
> >          QuerySolutionMap qsm = new QuerySolutionMap();
> >          qsm.add("s", model.createResource("_:" + id));
> >
> >          try (QueryExecution qex = QueryExecutionFactory.create(query,
> > model, qsm))
> >          {
> >              ResultSet resultSet = qex.execSelect();
> >
> >              assertTrue(resultSet.hasNext());
> >              assertEquals(id, resultSet.next().get("s").asResource().getId());
> >          }
> >      }
> >
> > The test fails on assertTrue() because SELECT returns no results.
> >
> > Is the test flawed? Am I misunderstanding the use of this URI scheme?
> > If not, what's the purpose if it cannot match blank nodes in data?
> >
> > Martynas
> >

Re: Blank node URI scheme

Posted by Andy Seaborne <an...@apache.org>.
<_:label> is a syntax feature, not built into the storage or query 
execution.

model.createResource("_:" + id));

creates a resource with a strange URI (which is actually illegal by RFC 
3986/7).

There are various ways:

1/ The app can put the bnode into the QSM and injected at execution - it 
won't become a bnode-variable because that happens in parsing.

2/ To put a concrete node into a query:

String bn = "<_:" + id+">";

then put string into SPARQL syntax:

QueryFactory.create("SELECT * { VALUES ?s {"+bn+"} ?s ?p ?o }");
QueryFactory.create("SELECT * { "+bn+" ?p ?o }");

3/ rewrite the abstract syntax after parsing:

Map<String, Resource> substitutions =
   Collections.singletonMap("s", bnode);
query = QueryFactory.create("SELECT * { ?s ?p ?o }");
query = QueryTransformOps.transformQuery(query, substitutions);

Forms 2 and 3 have the advantage of not relying on how execution works - 
QSMs are ingested inthe start of execution and e.g. aren't visible in 
subqueries and also interact and bypass with query optimization.

     Andy

On 05/07/2020 15:22, Martynas Jusevičius wrote:
> Hi,
> 
> I came across a situation where I want to carry over a blank node ID
> in a QuerySolutionMap to QueryExecution, to match exact blank node
> resources rather than have them as variables.
> 
> I found an old thread by Holger on this topic:
> https://mail-archives.apache.org/mod_mbox/jena-users/201308.mbox/browser
> 
> The suggestion was to use <_:LABEL> URI scheme for blank nodes.
> https://jena.apache.org/documentation/query/extension.html#blank-node-labels
> 
> Based on that, I tried this logic:
> 
>      if (instance.isURIResource()) qsm.add(SPIN.THIS_VAR_NAME, instance);
>      if (instance.isAnon()) qsm.add(SPIN.THIS_VAR_NAME,
> model.createResource("_:" + instance.getId()));
> 
> However I'm not getting the results I expect. So I decided to make an
> isolated test:
> 
>      @Test
>      public void bnodeQueryTest()
>      {
>          Model model = ModelFactory.createDefaultModel();
>          Resource bnode = model.createResource().addProperty(FOAF.name,
> "whateverest");
>          AnonId id = bnode.getId();
> 
>          Query query = QueryFactory.create("SELECT * { ?s ?p ?o }");
>          QuerySolutionMap qsm = new QuerySolutionMap();
>          qsm.add("s", model.createResource("_:" + id));
> 
>          try (QueryExecution qex = QueryExecutionFactory.create(query,
> model, qsm))
>          {
>              ResultSet resultSet = qex.execSelect();
> 
>              assertTrue(resultSet.hasNext());
>              assertEquals(id, resultSet.next().get("s").asResource().getId());
>          }
>      }
> 
> The test fails on assertTrue() because SELECT returns no results.
> 
> Is the test flawed? Am I misunderstanding the use of this URI scheme?
> If not, what's the purpose if it cannot match blank nodes in data?
> 
> Martynas
> 

Re: Blank node URI scheme

Posted by Martynas Jusevičius <ma...@atomgraph.com>.
Jena version: 3.16.0-SNAPSHOT

On Sun, Jul 5, 2020 at 4:22 PM Martynas Jusevičius
<ma...@atomgraph.com> wrote:
>
> Hi,
>
> I came across a situation where I want to carry over a blank node ID
> in a QuerySolutionMap to QueryExecution, to match exact blank node
> resources rather than have them as variables.
>
> I found an old thread by Holger on this topic:
> https://mail-archives.apache.org/mod_mbox/jena-users/201308.mbox/browser
>
> The suggestion was to use <_:LABEL> URI scheme for blank nodes.
> https://jena.apache.org/documentation/query/extension.html#blank-node-labels
>
> Based on that, I tried this logic:
>
>     if (instance.isURIResource()) qsm.add(SPIN.THIS_VAR_NAME, instance);
>     if (instance.isAnon()) qsm.add(SPIN.THIS_VAR_NAME,
> model.createResource("_:" + instance.getId()));
>
> However I'm not getting the results I expect. So I decided to make an
> isolated test:
>
>     @Test
>     public void bnodeQueryTest()
>     {
>         Model model = ModelFactory.createDefaultModel();
>         Resource bnode = model.createResource().addProperty(FOAF.name,
> "whateverest");
>         AnonId id = bnode.getId();
>
>         Query query = QueryFactory.create("SELECT * { ?s ?p ?o }");
>         QuerySolutionMap qsm = new QuerySolutionMap();
>         qsm.add("s", model.createResource("_:" + id));
>
>         try (QueryExecution qex = QueryExecutionFactory.create(query,
> model, qsm))
>         {
>             ResultSet resultSet = qex.execSelect();
>
>             assertTrue(resultSet.hasNext());
>             assertEquals(id, resultSet.next().get("s").asResource().getId());
>         }
>     }
>
> The test fails on assertTrue() because SELECT returns no results.
>
> Is the test flawed? Am I misunderstanding the use of this URI scheme?
> If not, what's the purpose if it cannot match blank nodes in data?
>
> Martynas