Skip to content

Support for SPARQL CONSTRUCT clauses#985

Merged
dpetran merged 16 commits intofeature/sparql-outputfrom
feature/construct
Mar 12, 2025
Merged

Support for SPARQL CONSTRUCT clauses#985
dpetran merged 16 commits intofeature/sparql-outputfrom
feature/construct

Conversation

@dpetran
Copy link
Contributor

@dpetran dpetran commented Feb 28, 2025

Return an RDF graph result using CONSTRUCT, according to the SPARQL spec

https://github.com/fluree/core/issues/170

The specification does not specify how compact the results should be, so I've elected to "flatten" the data so that all of a subject's predicates are grouped into one json object. This does come at a performance penalty, so we could elide that step and still be compliant, but I figured this way is perhaps more usable than the alternative, which is each triple produces a unique object.

I've also elected to treat all objects as multicardinal values returned in arrays, even if there's only a single item. We could do the extra step of unpacking single values, but that complicates result processing and I elected not to do it unless someone asks for it, in which case I would be happy to add it.

{"@id" "?s" "friendname" "?friendName"}
{"@id" "?friend" "name" "?friendName"}
{"@id" "?friend" "num" "?friendNum"}]}))))
#_(testing "bnode template"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using bnodes in construct templates produces nondeterministic responses since we process results in parallel. I don't have a good solution for this yet, so the flaky tests are commented out.

(cond-> {"@graph" (->> results
(sort-by #(get % id-key))
(partition-by #(get % id-key))
(mapv display/nest-multicardinal-values))}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sorting, partitioning, and nesting is not strictly required by the spec, but may greatly improve usability. If users are mainly using construct to directly inject the results into another graph processor, then this is probably unnecessary. If they are trying to use the json-ld document directly, this is probably very useful. Until we discover which use case is more common I've tried to strike a middle path.

@dpetran
Copy link
Contributor Author

dpetran commented Mar 4, 2025

As of this PR, we do not support anonymous blank node syntax in SPARQL, like this:

PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX site: <http://example.org/stats#>

CONSTRUCT { [] foaf:name ?name }
WHERE
{ [] foaf:name ?name ;
     site:hits ?hits .
}
ORDER BY desc(?hits)
LIMIT 2

Support for anonymous blank nodes is planned for a subsequent PR.

@dpetran dpetran marked this pull request as ready for review March 4, 2025 21:30
@dpetran dpetran requested a review from a team March 4, 2025 21:30
@dpetran dpetran force-pushed the feature/sparql-output branch from f74b898 to 4b1fd82 Compare March 10, 2025 15:52
@dpetran dpetran force-pushed the feature/construct branch from 8810e4f to 8c180a7 Compare March 10, 2025 16:36
@dpetran
Copy link
Contributor Author

dpetran commented Mar 10, 2025

Rebased on main.

Copy link
Contributor

@zonotope zonotope left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎩

(cond (:select-one q) (async/take 1 result-ch)

(:construct q)
(-> (async/into [] result-ch)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is just a suggestion you can take or leave, but i think you can do this and the clause below in one step using async/transduce

(async/transduce identity
                 (completing conj (partial select/wrap-construct q))
                 []
                 result-ch)

(async/transduce identity
                 (completing conj (partial select/wrap-sparql q))
                 []
                 result-ch)

I haven't tested this, but I think it should work.

@dpetran dpetran force-pushed the feature/sparql-output branch from 4b1fd82 to 1193d39 Compare March 12, 2025 15:26
@dpetran dpetran force-pushed the feature/construct branch from 28a83a3 to e997302 Compare March 12, 2025 15:28
@dpetran
Copy link
Contributor Author

dpetran commented Mar 12, 2025

Rebased on main via #973

@dpetran dpetran force-pushed the feature/construct branch from e997302 to 6b03026 Compare March 12, 2025 17:34
@dpetran
Copy link
Contributor Author

dpetran commented Mar 12, 2025

Updated to account for the removal of the display ns in #973

@dpetran dpetran merged commit a484022 into feature/sparql-output Mar 12, 2025
6 checks passed
@dpetran dpetran deleted the feature/construct branch March 12, 2025 18:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants