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