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 2024/11/26 08:56:03 UTC

VALUES not passed to SERVICE in federated queries

Hi,

I have two Fuseki 4.6.1 instances in a Docker network (fuseki-admin
and fuseki-end-user) that federate SPARQL queries between each other.

When I execute this query on fuseki-admin:

PREFIX  rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX  acl:  <http://www.w3.org/ns/auth/acl#>
PREFIX  sioc: <http://rdfs.org/sioc/ns#>

SELECT  *
FROM <urn:x-arq:UnionGraph>
WHERE
  { VALUES ( ?this ?Container ) {
      ( <https://localhost:4443/whateverest/> <https://localhost:4443/> )
    }
    SERVICE <http://fuseki-end-user:3030/ds/>
      { GRAPH ?Container
          { ?Container  a  ?Type }
      }
  }

then I can see the ?Container binding was injected into the query
string executed on fuseki-end-user:

Query = SELECT  * WHERE   { GRAPH <https://localhost:4443/>       {
<https://localhost:4443/>                   a  ?Type       }   }

However when I add FILTER NOT EXISTS to the federated part

PREFIX  rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX  acl:  <http://www.w3.org/ns/auth/acl#>
PREFIX  sioc: <http://rdfs.org/sioc/ns#>

SELECT  *
FROM <urn:x-arq:UnionGraph>
WHERE
  { VALUES (?this ?Container) { (<https://localhost:4443/whateverest/>
<https://localhost:4443/>) }
    SERVICE <http://fuseki-end-user:3030/ds/>
      {  GRAPH ?Container
              {
                ?Container  a  ?Type
              }
            FILTER NOT EXISTS { GRAPH ?this
                                  { ?this
sioc:has_parent|sioc:has_container  ?Container }
                              }
      }
  }

I see a single request in fuseki-end-user but none of the variables
are bound to anything:

Query =  Query = SELECT  * WHERE   { GRAPH ?Container       {
?Container  a  ?Type }     FILTER NOT EXISTS { GRAPH ?this
              { ?this
<http://rdfs.org/sioc/ns#has_parent>|<http://rdfs.org/sioc/ns#has_container>
?Container }

This looks plain wrong because without bindings it eliminates too many
(positive) results, and the final result on fuseki-end-user comes out
empty.

Is this a bug or am I misunderstanding something about VALUES and/or SERVICE?

Martynas

Re: VALUES not passed to SERVICE in federated queries

Posted by Martynas Jusevičius <ma...@atomgraph.com>.
Correction: "... and the final result on *fuseki-admin* comes out empty."

On Tue, Nov 26, 2024 at 9:56 AM Martynas Jusevičius
<ma...@atomgraph.com> wrote:
>
> Hi,
>
> I have two Fuseki 4.6.1 instances in a Docker network (fuseki-admin
> and fuseki-end-user) that federate SPARQL queries between each other.
>
> When I execute this query on fuseki-admin:
>
> PREFIX  rdfs: <http://www.w3.org/2000/01/rdf-schema#>
> PREFIX  acl:  <http://www.w3.org/ns/auth/acl#>
> PREFIX  sioc: <http://rdfs.org/sioc/ns#>
>
> SELECT  *
> FROM <urn:x-arq:UnionGraph>
> WHERE
>   { VALUES ( ?this ?Container ) {
>       ( <https://localhost:4443/whateverest/> <https://localhost:4443/> )
>     }
>     SERVICE <http://fuseki-end-user:3030/ds/>
>       { GRAPH ?Container
>           { ?Container  a  ?Type }
>       }
>   }
>
> then I can see the ?Container binding was injected into the query
> string executed on fuseki-end-user:
>
> Query = SELECT  * WHERE   { GRAPH <https://localhost:4443/>       {
> <https://localhost:4443/>                   a  ?Type       }   }
>
> However when I add FILTER NOT EXISTS to the federated part
>
> PREFIX  rdfs: <http://www.w3.org/2000/01/rdf-schema#>
> PREFIX  acl:  <http://www.w3.org/ns/auth/acl#>
> PREFIX  sioc: <http://rdfs.org/sioc/ns#>
>
> SELECT  *
> FROM <urn:x-arq:UnionGraph>
> WHERE
>   { VALUES (?this ?Container) { (<https://localhost:4443/whateverest/>
> <https://localhost:4443/>) }
>     SERVICE <http://fuseki-end-user:3030/ds/>
>       {  GRAPH ?Container
>               {
>                 ?Container  a  ?Type
>               }
>             FILTER NOT EXISTS { GRAPH ?this
>                                   { ?this
> sioc:has_parent|sioc:has_container  ?Container }
>                               }
>       }
>   }
>
> I see a single request in fuseki-end-user but none of the variables
> are bound to anything:
>
> Query =  Query = SELECT  * WHERE   { GRAPH ?Container       {
> ?Container  a  ?Type }     FILTER NOT EXISTS { GRAPH ?this
>               { ?this
> <http://rdfs.org/sioc/ns#has_parent>|<http://rdfs.org/sioc/ns#has_container>
> ?Container }
>
> This looks plain wrong because without bindings it eliminates too many
> (positive) results, and the final result on fuseki-end-user comes out
> empty.
>
> Is this a bug or am I misunderstanding something about VALUES and/or SERVICE?
>
> Martynas

Re: VALUES not passed to SERVICE in federated queries

Posted by Andy Seaborne <an...@apache.org>.
> PREFIX  rdfs: <http://www.w3.org/2000/01/rdf-schema#>
> PREFIX  acl:  <http://www.w3.org/ns/auth/acl#>
> PREFIX  sioc: <http://rdfs.org/sioc/ns#>
> 
> SELECT  *
> FROM <urn:x-arq:UnionGraph>
> WHERE
>   { VALUES ( ?this ?Container ) {
>       ( <https://localhost:4443/whateverest/> <https://localhost:4443/> )
>     }
>     SERVICE <http://fuseki-end-user:3030/ds/>
>       { GRAPH ?Container
>           { ?Container  a  ?Type }
>       }
>   }

For Fuseki-specific solution:
LATERAL may work

WHERE
   { VALUES ( ?this ?Container ) {
       ( <https://localhost:4443/whateverest/> <https://localhost:4443/> ) }
     LATERAL {
       SERVICE <http://fuseki-end-user:3030/ds/>
         { GRAPH ?Container
             { ?Container  a  ?Type }
         }
      }
   }

It's Fuseki-specific (ATM) becuae it needs to rewrite the SERVICE block. 
Normally, that's an alegbra rewrite but for SERVICE it needs to recreate 
query syntax and it's using LET currently.

     Andy

LET is an ARQ extension like BIND except if the variable is already 
bound to the same value it passes the soltion, and if it is a different 
value does not match. So it is a combination of BIND and FILTER sameTerm 
and is position insensitive unlike BIND.


Re: Re: VALUES not passed to SERVICE in federated queries

Posted by Claus Stadler <cs...@informatik.uni-leipzig.de>.
I did a quick successful test with the data and query below.

It wasn't sure whether the service enhancer's substitution approach 
would work with FILTER (NOT) EXISTS because IIRC I didn't write tests 
for this case, but it seems to work as expected:


Data - One product 'a' with 2 categories, of which cat1 has the feature  
f2 which should cause it to be excluded:

```sparql

INSERT DATA {
   <urn:a> <urn:hasCategory> <urn:cat1> .
   <urn:cat1> <urn:hasFeature> <urn:f1> .
   <urn:cat1> <urn:hasFeature> <urn:f2> .

   <urn:a> <urn:hasCategory> <urn:cat2> .
   <urn:cat2> <urn:hasFeature> <urn:f3> .
   <urn:cat2> <urn:hasFeature> <urn:f4> .
}

```


Query using SERVICE <loop:>:

```sparql

SELECT  *
WHERE
{
   VALUES (?product ?feature) { (<urn:a> <urn:f2>) }
   SERVICE <loop:> {
     SELECT ?category {
       ?product <urn:hasCategory> ?category .
       FILTER NOT EXISTS { ?category <urn:hasFeature> ?feature }
     }
   }
}

```


Note, that you can use SERVICE <loop:bulk+N:> to batch N bindings into a 
single request.


Output is the 'cat2' which does not have feature 'f2':


```

(?product = <urn:a>, ?feature = <urn:f2>, ?category = <urn:cat2>)
```


The substituted queries ignores the standard scoping rules and thus 
looks like:

```sparql

SELECT  *
WHERE
   {   { { SELECT  ?category
           WHERE
             { <urn:a>  <urn:hasCategory>  ?category
               FILTER NOT EXISTS { ?category <urn:hasFeature>  <urn:f2> }
             }
         }
         BIND(0 AS ?__idx__)
       }
     UNION
       { BIND(1000000000 AS ?__idx__) }
   }

```


As a side note, I have an maintenance update of the service enhancer 
plugin in the works with a some smaller fixes and improvements (e.g. 
improved cancellation handling based on recent changes I contributed to 
ARQ) of the existing system and and hope to have the PR ready during 
December.

I will also add FILTER (NOT) EXISTS this test case to the test suite.


Cheers,

Claus



On 27.11.24 20:13, Andy Seaborne wrote:
>
>
> On 26/11/2024 08:56, Martynas Jusevičius wrote:
>> Hi,
>>
>> I have two Fuseki 4.6.1 instances in a Docker network (fuseki-admin
>> and fuseki-end-user) that federate SPARQL queries between each other.
>
> If you want to provide detailed control of SERVICE, then there is
>
> https://jena.apache.org/documentation/query/service_enhancer.html
>
>
>>
>> When I execute this query on fuseki-admin:
>>
>> PREFIX  rdfs: <http://www.w3.org/2000/01/rdf-schema#>
>> PREFIX  acl:  <http://www.w3.org/ns/auth/acl#>
>> PREFIX  sioc: <http://rdfs.org/sioc/ns#>
>>
>> SELECT  *
>> FROM <urn:x-arq:UnionGraph>
>> WHERE
>>    { VALUES ( ?this ?Container ) {
>>        ( <https://localhost:4443/whateverest/> 
>> <https://localhost:4443/> )
>>      }
>>      SERVICE <http://fuseki-end-user:3030/ds/>
>>        { GRAPH ?Container
>>            { ?Container  a  ?Type }
>>        }
>>    }
>>
>> then I can see the ?Container binding was injected into the query
>> string executed on fuseki-end-user:
>>
>> Query = SELECT  * WHERE   { GRAPH <https://localhost:4443/>       {
>> <https://localhost:4443/>                   a  ?Type }   }
>>
>> However when I add FILTER NOT EXISTS to the federated part
>>
>> PREFIX  rdfs: <http://www.w3.org/2000/01/rdf-schema#>
>> PREFIX  acl:  <http://www.w3.org/ns/auth/acl#>
>> PREFIX  sioc: <http://rdfs.org/sioc/ns#>
>>
>> SELECT  *
>> FROM <urn:x-arq:UnionGraph>
>> WHERE
>>    { VALUES (?this ?Container) { (<https://localhost:4443/whateverest/>
>> <https://localhost:4443/>) }
>>      SERVICE <http://fuseki-end-user:3030/ds/>
>>        {  GRAPH ?Container
>>                {
>>                  ?Container  a  ?Type
>>                }
>>              FILTER NOT EXISTS { GRAPH ?this
>>                                    { ?this
>> sioc:has_parent|sioc:has_container  ?Container }
>>                                }
>>        }
>>    }
>
> Without the service enhancer, there is no rewrite and it is a has join:
>
> (join
>    VALUES
>    SERVICE
> )
>
> otherwise it can become a denial of service vector!
>
> With control such as correlated joins:
> https://jena.apache.org/documentation/query/service_enhancer.html#correlated-joins 
>
>
> you may be able to get the effect you want.
>
> The ?this case is changing the meaning of the query -- ?this is not 
> in-scope in the NOT EXISTS so it is undefined.
>
>     Andy
>
>>
>> I see a single request in fuseki-end-user but none of the variables
>> are bound to anything:
>>
>> Query =  Query = SELECT  * WHERE   { GRAPH ?Container       {
>> ?Container  a  ?Type }     FILTER NOT EXISTS { GRAPH ?this
>>                { ?this
>> <http://rdfs.org/sioc/ns#has_parent>|<http://rdfs.org/sioc/ns#has_container> 
>>
>> ?Container }
>>
>> This looks plain wrong because without bindings it eliminates too many
>> (positive) results, and the final result on fuseki-end-user comes out
>> empty.
>>
>> Is this a bug or am I misunderstanding something about VALUES and/or 
>> SERVICE?
>>
>> Martynas
>

Re: VALUES not passed to SERVICE in federated queries

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

On 26/11/2024 08:56, Martynas Jusevičius wrote:
> Hi,
> 
> I have two Fuseki 4.6.1 instances in a Docker network (fuseki-admin
> and fuseki-end-user) that federate SPARQL queries between each other.

If you want to provide detailed control of SERVICE, then there is

https://jena.apache.org/documentation/query/service_enhancer.html


> 
> When I execute this query on fuseki-admin:
> 
> PREFIX  rdfs: <http://www.w3.org/2000/01/rdf-schema#>
> PREFIX  acl:  <http://www.w3.org/ns/auth/acl#>
> PREFIX  sioc: <http://rdfs.org/sioc/ns#>
> 
> SELECT  *
> FROM <urn:x-arq:UnionGraph>
> WHERE
>    { VALUES ( ?this ?Container ) {
>        ( <https://localhost:4443/whateverest/> <https://localhost:4443/> )
>      }
>      SERVICE <http://fuseki-end-user:3030/ds/>
>        { GRAPH ?Container
>            { ?Container  a  ?Type }
>        }
>    }
> 
> then I can see the ?Container binding was injected into the query
> string executed on fuseki-end-user:
> 
> Query = SELECT  * WHERE   { GRAPH <https://localhost:4443/>       {
> <https://localhost:4443/>                   a  ?Type       }   }
> 
> However when I add FILTER NOT EXISTS to the federated part
> 
> PREFIX  rdfs: <http://www.w3.org/2000/01/rdf-schema#>
> PREFIX  acl:  <http://www.w3.org/ns/auth/acl#>
> PREFIX  sioc: <http://rdfs.org/sioc/ns#>
> 
> SELECT  *
> FROM <urn:x-arq:UnionGraph>
> WHERE
>    { VALUES (?this ?Container) { (<https://localhost:4443/whateverest/>
> <https://localhost:4443/>) }
>      SERVICE <http://fuseki-end-user:3030/ds/>
>        {  GRAPH ?Container
>                {
>                  ?Container  a  ?Type
>                }
>              FILTER NOT EXISTS { GRAPH ?this
>                                    { ?this
> sioc:has_parent|sioc:has_container  ?Container }
>                                }
>        }
>    }

Without the service enhancer, there is no rewrite and it is a has join:

(join
    VALUES
    SERVICE
)

otherwise it can become a denial of service vector!

With control such as correlated joins:
https://jena.apache.org/documentation/query/service_enhancer.html#correlated-joins

you may be able to get the effect you want.

The ?this case is changing the meaning of the query -- ?this is not 
in-scope in the NOT EXISTS so it is undefined.

     Andy

> 
> I see a single request in fuseki-end-user but none of the variables
> are bound to anything:
> 
> Query =  Query = SELECT  * WHERE   { GRAPH ?Container       {
> ?Container  a  ?Type }     FILTER NOT EXISTS { GRAPH ?this
>                { ?this
> <http://rdfs.org/sioc/ns#has_parent>|<http://rdfs.org/sioc/ns#has_container>
> ?Container }
> 
> This looks plain wrong because without bindings it eliminates too many
> (positive) results, and the final result on fuseki-end-user comes out
> empty.
> 
> Is this a bug or am I misunderstanding something about VALUES and/or SERVICE?
> 
> Martynas