Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return single values if OWL indicates property maximum cardinality is 1 #14

Closed
agarciadom opened this issue Nov 28, 2024 · 12 comments · Fixed by #22
Closed

Return single values if OWL indicates property maximum cardinality is 1 #14

agarciadom opened this issue Nov 28, 2024 · 12 comments · Fixed by #22
Labels
enhancement New feature or request

Comments

@agarciadom
Copy link
Member

At the moment, x.property will always return a Sequence as the driver is unaware of any OWL constraints on the cardinality of the property. It would be useful to access the OWL information from Jena to take this into account.

This section of the W3C OWL guide explains how to represent this restriction:

https://www.w3.org/TR/2004/REC-owl-guide-20040210/#simpleCardinality

@agarciadom agarciadom added the enhancement New feature or request label Nov 28, 2024
@agarciadom
Copy link
Member Author

agarciadom commented Dec 20, 2024

Note that this will actually require two things:

  1. Running the OWL/RDFS reasoners to expand the graph.
  2. Querying the graph accordingly to figure out the cardinality of the property.

In addition, we could use examples from the MOF2RDF specification, which include examples of qualifiedCardinality:

https://www.omg.org/spec/MOF2RDF/1.0/PDF

@OwenR-York
Copy link
Contributor

OwenR-York commented Jan 2, 2025

Jena inference documentation, including how to create a reasoner for accessing a graph/model

Jena inference docs

@OwenR-York
Copy link
Contributor

OwenR-York commented Jan 2, 2025

The OWL reasoner will be needed to access OWL-related information for properties. There are several reasoners for OWL, we can use either full or mini (no minimum Cardinality) both reasoners should cover maximum cardinality.

Jena OWL reasoner

Model schema = RDFDataMgr.loadModel("file:data/owlDemoSchema.rdf");
Model data = RDFDataMgr.loadModel("file:data/owlDemoData.rdf");
Reasoner reasoner = ReasonerRegistry.getOWLReasoner();
reasoner = reasoner.bindSchema(schema);
InfModel infmodel = ModelFactory.createInfModel(reasoner, data);

A reasoner is created and configured with 2 models (data and schema), and an inferred model is created (infmodel)

@OwenR-York
Copy link
Contributor

maxCardinality can be applied via a schema model, which is visible in an inferred model produced by a reasoner. However, a property owl:maxCardinality is obfuscated by a generated graph node (_:b1) produced by the reasoner at runtime. This is not the same as if the owl:maxCardinality was defined in the original data model.

:bigName42 rdf:type :Computer , owl:Thing , _:b1 , _:b0 , rdfs:Resource;
owl:sameAs :bigName42;
:hasBundle :binNameSpecialBundle;
:hasComponent :nForce2 , :bigNameSpecialMB;
:hasMotherBoard :nForce2 , :bigNameSpecialMB .

:hasMotherBoard rdf:type rdf:Property , owl:ObjectProperty , rdfs:Resource , owl:Property;
rdfs:domain owl:Thing , :Computer , rdfs:Resource , _:b0 , _:b1;
rdfs:range owl:Thing , :MotherBoard , rdfs:Resource;
rdfs:subPropertyOf :hasComponent , :hasMotherBoard .

_:b1 rdf:type owl:Class , rdfs:Class , owl:Restriction , rdfs:Resource;
rdfs:subClassOf owl:Thing , rdfs:Resource , _:b1 , _:b0;
owl:equivalentClass _:b1 , _:b0;
owl:maxCardinality "1"^^xsd:nonNegativeInteger;
owl:onProperty :hasMotherBoard .

@OwenR-York
Copy link
Contributor

Turn an Inferred model into an Ontology model, and gain access to more methods relating to OWL.

		OntModel oInfmodel = ModelFactory.createOntologyModel();
		oInfmodel.add(infmodel);
		OntResource oRes = oInfmodel.getOntResource("urn:x-hp:eg/bigName42");
		OntProperty oPro = oInfmodel.getOntProperty("urn:x-hp:eg/hasMotherBoard");

@OwenR-York
Copy link
Contributor

Gets all the Restriction types in the (ont)model (test model has referenced restrictions), gets the one that is MaxCardinality (there is only one).

		Restriction maxCardRes = oInfmodel.listRestrictions().filterKeep(res -> res.isMaxCardinalityRestriction()).next();
		System.out.println("no: " + maxCardRes.getPropertyValue(OWL.maxCardinality)); // This restriction node has an OWL maxCardinality edge (property) pointing to a node with the "value"

@OwenR-York
Copy link
Contributor

Get a property from the ont model, check its referring restrictions for max cardinality, find the node and get value (if present)

		OntProperty oPro = oInfmodel.getOntProperty("urn:x-hp:eg/hasMotherBoard");

		Restriction maxCres = oPro.listReferringRestrictions().filterKeep(maxC -> maxC.isMaxCardinalityRestriction())
				.next();
		RDFNode maxCvalue = maxCres.getPropertyValue(OWL.maxCardinality);

@agarciadom
Copy link
Member Author

During our chat today, we talked that Jena does not enforce maximum cardinalities during loading: this validation is something that has to be triggered by the user, and which will report issues, but it's perfectly possible for someone to load and query an invalid RDF model.

I have added #20 to the backlog as we may want to trigger this validation during loading in the future, but for the time being, if we have more values than what maxCardinality allows, we should print a warning on the error stream and return the first values within the maxCardinality. If, for instance, we get 2 values and we should only have one, we will print a warning, return the first one we found, and discard the other.

@agarciadom
Copy link
Member Author

agarciadom commented Jan 7, 2025

Based on the above experiments, we have tried extending RDFModel to have split schema + data URIs, and to run the OWL reasoner during loading. The next tasks for this issue would be:

  • Fix the tests that have broken after we run inference by default
  • Expose the schema URIs from the model config dialog
  • Use the OntModel to obtain the OntClasses for a given RDF resource
  • Use the OntClass to find the matching OntProperty
  • Use the OntProperty to find the max cardinality restriction, if any
  • Limit results to those of the max cardinality (give null OR raw value if max cardinality is 1)
  • Print warning if there are more values than what the max cardinality allows

Edit: after further consideration, we don't need the OntClass abstraction for the work in this issue.

@OwenR-York
Copy link
Contributor

3 Tests need reviewing to see if they are still needed/appropriate.

Originally, some tests checked a data model loaded as a Model returned X items or classes; now using OntModel we are getting more things returned. This is because a data model handled with OntModel appears to undergo some reasoning process when loaded.

@agarciadom
Copy link
Member Author

agarciadom commented Jan 10, 2025 via email

@OwenR-York
Copy link
Contributor

OwenR-York commented Jan 10, 2025 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants