RDFLib / prez

Prez is a data-configurable Linked Data API framework that delivers profiles of Knowledge Graph data according to the Content Negotiation by Profile standard.
BSD 3-Clause "New" or "Revised" License
18 stars 7 forks source link

Fix vocprez queries to support inverse skos relationships #161

Closed edmondchuc closed 9 months ago

edmondchuc commented 9 months ago

The current set of vocprez queries to provide progressive loading of very large vocabs only supports skos:hasTopConcept and skos:broader relationships. This PR adds support for the same relationships and its inverse relationships, skos:topConceptOf and skos:narrower.

Fixes https://github.com/RDFLib/prez/issues/162.

edmondchuc commented 9 months ago

A test is skipped because the combination of the data and the generated query results in an exception in RDFLib's SPARQL processor.

Generated query ``` PREFIX prez: PREFIX rdf: PREFIX rdfs: PREFIX skos: CONSTRUCT { ?concept skos:prefLabel ?label . ?concept prez:childrenCount ?narrowerChildrenCount . ?iri prez:childrenCount ?childrenCount . ?iri skos:hasTopConcept ?concept . ?iri rdf:type ?type . ?concept rdf:type ?conceptType . } WHERE { BIND( as ?iri) OPTIONAL { ?iri skos:hasTopConcept ?concept . ?concept skos:prefLabel ?label . } OPTIONAL { ?concept skos:topConceptOf ?iri . ?concept skos:prefLabel ?label . } ?iri rdf:type ?type . ?concept rdf:type ?conceptType . { SELECT (COUNT(?childConcept) AS ?childrenCount) WHERE { BIND( as ?iri) ?iri skos:hasTopConcept ?childConcept . } } { SELECT ?concept ?label (COUNT(?narrowerConcept) AS ?narrowerChildrenCount) WHERE { BIND( as ?iri) OPTIONAL { ?iri skos:hasTopConcept ?concept . ?concept skos:prefLabel ?label . } OPTIONAL { ?concept skos:topConceptOf ?iri . ?concept skos:prefLabel ?label . } OPTIONAL { ?narrowerConcept skos:broader ?concept . } OPTIONAL { ?concept skos:narrower ?narrowerConcept . } } GROUP BY ?concept ?label ORDER BY str(?label) LIMIT 20 OFFSET 0 } } ```
Traceback ``` Traceback (most recent call last): File "/Users/edmondchuc/projects/prez/tests/local_sparql_store/store.py", line 178, in apply_sparql_query result = vocprez_graph.query(new_query) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/edmondchuc/projects/prez/venv/lib/python3.11/site-packages/rdflib/graph.py", line 1567, in query return result(processor.query(query_object, initBindings, initNs, **kwargs)) # type: ignore[arg-type] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/edmondchuc/projects/prez/venv/lib/python3.11/site-packages/rdflib/plugins/sparql/processor.py", line 140, in query return evalQuery(self.graph, query, initBindings, base) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/edmondchuc/projects/prez/venv/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py", line 695, in evalQuery return evalPart(ctx, main) ^^^^^^^^^^^^^^^^^^^ File "/Users/edmondchuc/projects/prez/venv/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py", line 323, in evalPart return evalConstructQuery(ctx, part) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/edmondchuc/projects/prez/venv/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py", line 597, in evalConstructQuery for c in evalPart(ctx, query.p): ^^^^^^^^^^^^^^^^^^^^^^ File "/Users/edmondchuc/projects/prez/venv/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py", line 303, in evalPart return evalProject(ctx, part) ^^^^^^^^^^^^^^^^^^^^^^ File "/Users/edmondchuc/projects/prez/venv/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py", line 561, in evalProject res = evalPart(ctx, project.p) ^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/edmondchuc/projects/prez/venv/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py", line 288, in evalPart return evalJoin(ctx, part) ^^^^^^^^^^^^^^^^^^^ File "/Users/edmondchuc/projects/prez/venv/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py", line 156, in evalJoin b = set(evalPart(ctx, join.p2)) ^^^^^^^^^^^^^^^^^^^^^^ File "/Users/edmondchuc/projects/prez/venv/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py", line 296, in evalPart return evalMultiset(ctx, part) ^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/edmondchuc/projects/prez/venv/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py", line 266, in evalMultiset return evalPart(ctx, part.p) ^^^^^^^^^^^^^^^^^^^^^ File "/Users/edmondchuc/projects/prez/venv/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py", line 305, in evalPart return evalSlice(ctx, part) ^^^^^^^^^^^^^^^^^^^^ File "/Users/edmondchuc/projects/prez/venv/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py", line 499, in evalSlice res = evalPart(ctx, slice.p) ^^^^^^^^^^^^^^^^^^^^^^ File "/Users/edmondchuc/projects/prez/venv/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py", line 303, in evalPart return evalProject(ctx, part) ^^^^^^^^^^^^^^^^^^^^^^ File "/Users/edmondchuc/projects/prez/venv/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py", line 561, in evalProject res = evalPart(ctx, project.p) ^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/edmondchuc/projects/prez/venv/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py", line 312, in evalPart return evalOrderBy(ctx, part) ^^^^^^^^^^^^^^^^^^^^^^ File "/Users/edmondchuc/projects/prez/venv/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py", line 491, in evalOrderBy res = sorted( ^^^^^^^ TypeError: '<' not supported between instances of 'NoneType' and 'NoneType' ```