Closed sszuev closed 5 months ago
I've already raised this issue in Dev ML (can't find the link right now).
https://lists.apache.org/thread/ztfvvz55oz3xmddtrpkfowtsgo9czg5n
Maybe you describe ONT-API briefly on this PR. Is it for managing an ontology - not for executing inference? That's not an issue - we just have to be clear what it is and what it isn't.
From the previous discussion, I don't see anything that a blocker. I'm not completely sure what the permissions connection is - it is for Model, not OntModel anyway.
1) A couple words about OWL-API and ONT-API, once again.
Each org.semanticweb.owlapi.model.OWLOntology provides access to org.semanticweb.owlapi.model.OWLAxioms which, in turn, consist of org.semanticweb.owlapi.model.OWLObjects.
There are 38 types of OWL2 axioms + SWRL-Rule "axiom".
In the default OWLAPI-impl each OWLOntology
is a set of OWLAxiom
s, everything is stored in memory.
There is a generic interface org.semanticweb.owlapi.reasoner.OWLReasoner. In OWLAPI there are several limited implementations.
+ Also, there are several external, advanced, implementations of OWLReasoner
: jfact, hermit, openllet.
ONT-API is an alternative implementation of OWLAPI-api. There is no any reasoner, but of course it can be used by any OWLReasoner
.
In ONT-API there are tree layers:
Graph
Model
with OWL2 support Thanks to the fact that we have RDF under the hood, we can use OWL2 together with SHACL, SPARQL, etc. Also, any Graph could underlay, not only in-memory implementations. If some RDF construction does not meet the OWL2 specification, it is invisible from the top-level of ONT-API.
There is concurrent support via ReadWriteLock
, but only for the first level (ReadWriteLockingGraph
) and the last one.
I think, the whole ONT-API's code is not very suitable to be merged into Jena. But second level (Jena's extended Model
) could be, it is closer to what Jena already has.
2)
Here is a spin-off of ONT-API - https://github.com/sszuev/jena-owl2 project. It contains second level: extended Jena Model
- com.github.sszuev.jena.ontapi.model.OntModel
The goal of this project is to repeat all the org.apache.jena.ontology.OntModel
's functionality, including rules-inference support, different specs, document-manager, etc. It is currently under development. At the moment there are only OWL2_MEM
, RDFS_MEM
and OWL2_DL_MEM_RDFS_BUILTIN_INF
specs. OntModel
is not InfModel
yet.
ReadWriteLockingGraph
will not be part of this model-api (at least in the first release).
OntModel
interface supports all the feature of OWL2 and also SWRL (since it is present in OWLAPI).
Example:
OntModel m = OntModelFactory.createModel().setNsPrefixes(OntModelFactory.STANDARD);
m.createDataAllValuesFrom(List.of(m.createDataProperty("dp")), m.createDataRestriction(m.getDatatype(XSD.xstring),
m.createFacetRestriction(OntFacetRestriction.MaxLength.class, m.createTypedLiteral(42))))
.addEquivalentClass(m.createOntClass("C"));
m.ontObjects(OntClass.class).forEach(System.out::println);
m.ontEntities().forEach(System.out::println);
m.write(System.out, "ttl");
For more examples see wiki https://github.com/owlcs/ont-api/wiki
There are no OWLAxiom objects, just like in org.apache.jena.ontology.OntModel
.
There is com.github.sszuev.jena.ontapi.UnionGraph, any changes in imported ontologies (owl:import
) are visible in the top-level.
For developing I use Jena's OntModel tests (tests rewritten and expanded with new tests): https://github.com/sszuev/jena-ont-tests org.apache.jena.ontology.OntModel
's documentation, and sometimes its implementation (but usually it is difficult to understand that code, it's easier to write from scratch)
General issue for OWL2 support: #2160
The first version of jena-owl2 library is ready: https://github.com/sszuev/jena-owl2 It supports all the features of the legacy OntModel. Model's level support for QL, RL, EL will be added later. Any feedback is welcome.
Model's level support for QL, RL, EL is added.
Benchmarks reflecting the current state:
Benchmark (factory) Mode Cnt Score Error Units
JmhClassIndividuals.LIST_CLASS_INDIVIDUALS_DIRECT OWL2_FULL_MEM thrpt 20 1923,911 ? 15,964 ops/s
JmhClassIndividuals.LIST_CLASS_INDIVIDUALS_DIRECT OWL2_EL_MEM thrpt 20 2032,108 ? 21,342 ops/s
JmhClassIndividuals.LIST_CLASS_INDIVIDUALS_DIRECT OWL1_LITE_MEM thrpt 20 1398,018 ? 10,840 ops/s
JmhClassIndividuals.LIST_CLASS_INDIVIDUALS_DIRECT OWL2_FULL_MEM_RDFS_INF thrpt 20 1,016 ? 0,014 ops/s
JmhClassIndividuals.LIST_CLASS_INDIVIDUALS_DIRECT OWL2_DL_MEM_BUILTIN_INF thrpt 20 956,433 ? 10,871 ops/s
JmhClassIndividuals.LIST_CLASS_INDIVIDUALS_DIRECT LEGACY_OWL_MEM thrpt 20 11215,546 ? 187,824 ops/s
JmhClassIndividuals.LIST_CLASS_INDIVIDUALS_DIRECT LEGACY_OWL_DL_MEM_RDFS_INF thrpt 20 1,012 ? 0,014 ops/s
JmhClassIndividuals.LIST_CLASS_INDIVIDUALS_INDIRECT OWL2_FULL_MEM thrpt 20 3514,486 ? 57,036 ops/s
JmhClassIndividuals.LIST_CLASS_INDIVIDUALS_INDIRECT OWL2_EL_MEM thrpt 20 3902,678 ? 45,094 ops/s
JmhClassIndividuals.LIST_CLASS_INDIVIDUALS_INDIRECT OWL1_LITE_MEM thrpt 20 2162,491 ? 74,462 ops/s
JmhClassIndividuals.LIST_CLASS_INDIVIDUALS_INDIRECT OWL2_FULL_MEM_RDFS_INF thrpt 20 1,050 ? 0,017 ops/s
JmhClassIndividuals.LIST_CLASS_INDIVIDUALS_INDIRECT OWL2_DL_MEM_BUILTIN_INF thrpt 20 1136,866 ? 6,205 ops/s
JmhClassIndividuals.LIST_CLASS_INDIVIDUALS_INDIRECT LEGACY_OWL_MEM thrpt 20 90239,833 ? 3020,189 ops/s
JmhClassIndividuals.LIST_CLASS_INDIVIDUALS_INDIRECT LEGACY_OWL_DL_MEM_RDFS_INF thrpt 20 9,621 ? 0,284 ops/s
JmhDeclaredProperties.LIST_DECLARED_PROPERTIES_DIRECT OWL2_FULL_MEM thrpt 20 602,578 ? 13,858 ops/s
JmhDeclaredProperties.LIST_DECLARED_PROPERTIES_DIRECT OWL2_EL_MEM thrpt 20 603,486 ? 15,590 ops/s
JmhDeclaredProperties.LIST_DECLARED_PROPERTIES_DIRECT OWL1_LITE_MEM thrpt 20 552,208 ? 9,938 ops/s
JmhDeclaredProperties.LIST_DECLARED_PROPERTIES_DIRECT OWL2_FULL_MEM_RDFS_INF thrpt 20 2,175 ? 0,346 ops/s
JmhDeclaredProperties.LIST_DECLARED_PROPERTIES_DIRECT OWL2_DL_MEM_BUILTIN_INF thrpt 20 577,964 ? 10,668 ops/s
JmhDeclaredProperties.LIST_DECLARED_PROPERTIES_DIRECT LEGACY_OWL_MEM thrpt 20 941,769 ? 37,638 ops/s
JmhDeclaredProperties.LIST_DECLARED_PROPERTIES_DIRECT LEGACY_OWL_DL_MEM_RDFS_INF thrpt 20 27,630 ? 0,534 ops/s
JmhDeclaredProperties.LIST_DECLARED_PROPERTIES_INDIRECT OWL2_FULL_MEM thrpt 20 609,576 ? 8,358 ops/s
JmhDeclaredProperties.LIST_DECLARED_PROPERTIES_INDIRECT OWL2_EL_MEM thrpt 20 597,792 ? 7,936 ops/s
JmhDeclaredProperties.LIST_DECLARED_PROPERTIES_INDIRECT OWL1_LITE_MEM thrpt 20 540,492 ? 17,052 ops/s
JmhDeclaredProperties.LIST_DECLARED_PROPERTIES_INDIRECT OWL2_FULL_MEM_RDFS_INF thrpt 20 2,526 ? 0,632 ops/s
JmhDeclaredProperties.LIST_DECLARED_PROPERTIES_INDIRECT OWL2_DL_MEM_BUILTIN_INF thrpt 20 576,449 ? 3,365 ops/s
JmhDeclaredProperties.LIST_DECLARED_PROPERTIES_INDIRECT LEGACY_OWL_MEM thrpt 20 998,556 ? 47,192 ops/s
JmhDeclaredProperties.LIST_DECLARED_PROPERTIES_INDIRECT LEGACY_OWL_DL_MEM_RDFS_INF thrpt 20 27,028 ? 0,679 ops/s
JmhDeclaringClasses.LIST_DECLARED_CLASSES_DIRECT OWL2_FULL_MEM thrpt 20 739,950 ? 6,990 ops/s
JmhDeclaringClasses.LIST_DECLARED_CLASSES_DIRECT OWL2_EL_MEM thrpt 20 750,253 ? 9,197 ops/s
JmhDeclaringClasses.LIST_DECLARED_CLASSES_DIRECT OWL1_LITE_MEM thrpt 20 853,760 ? 6,403 ops/s
JmhDeclaringClasses.LIST_DECLARED_CLASSES_DIRECT OWL2_FULL_MEM_RDFS_INF thrpt 20 26,372 ? 0,746 ops/s
JmhDeclaringClasses.LIST_DECLARED_CLASSES_DIRECT OWL2_DL_MEM_BUILTIN_INF thrpt 20 388,656 ? 3,079 ops/s
JmhDeclaringClasses.LIST_DECLARED_CLASSES_DIRECT LEGACY_OWL_MEM thrpt 20 2130,594 ? 31,712 ops/s
JmhDeclaringClasses.LIST_DECLARED_CLASSES_DIRECT LEGACY_OWL_DL_MEM_RDFS_INF thrpt 20 51,955 ? 1,049 ops/s
JmhDeclaringClasses.LIST_DECLARED_CLASSES_INDIRECT OWL2_FULL_MEM thrpt 20 3708,437 ? 40,225 ops/s
JmhDeclaringClasses.LIST_DECLARED_CLASSES_INDIRECT OWL2_EL_MEM thrpt 20 4092,354 ? 23,170 ops/s
JmhDeclaringClasses.LIST_DECLARED_CLASSES_INDIRECT OWL1_LITE_MEM thrpt 20 17765,737 ? 242,984 ops/s
JmhDeclaringClasses.LIST_DECLARED_CLASSES_INDIRECT OWL2_FULL_MEM_RDFS_INF thrpt 20 117,545 ? 5,883 ops/s
JmhDeclaringClasses.LIST_DECLARED_CLASSES_INDIRECT OWL2_DL_MEM_BUILTIN_INF thrpt 20 3486,673 ? 96,499 ops/s
JmhDeclaringClasses.LIST_DECLARED_CLASSES_INDIRECT LEGACY_OWL_MEM thrpt 20 8103,053 ? 191,609 ops/s
JmhDeclaringClasses.LIST_DECLARED_CLASSES_INDIRECT LEGACY_OWL_DL_MEM_RDFS_INF thrpt 20 168,471 ? 5,150 ops/s
JmhIndividualClasses.LIST_INDIVIDUAL_CLASSES_DIRECT OWL2_FULL_MEM thrpt 20 194416,995 ? 4152,421 ops/s
JmhIndividualClasses.LIST_INDIVIDUAL_CLASSES_DIRECT OWL2_EL_MEM thrpt 20 192425,384 ? 5128,301 ops/s
JmhIndividualClasses.LIST_INDIVIDUAL_CLASSES_DIRECT OWL1_LITE_MEM thrpt 20 157829,681 ? 1869,907 ops/s
JmhIndividualClasses.LIST_INDIVIDUAL_CLASSES_DIRECT OWL2_FULL_MEM_RDFS_INF thrpt 20 683,222 ? 31,047 ops/s
JmhIndividualClasses.LIST_INDIVIDUAL_CLASSES_DIRECT OWL2_DL_MEM_BUILTIN_INF thrpt 20 87477,583 ? 1256,418 ops/s
JmhIndividualClasses.LIST_INDIVIDUAL_CLASSES_DIRECT LEGACY_OWL_MEM thrpt 20 288554,472 ? 4034,018 ops/s
JmhIndividualClasses.LIST_INDIVIDUAL_CLASSES_DIRECT LEGACY_OWL_DL_MEM_RDFS_INF thrpt 20 232,062 ? 9,360 ops/s
JmhIndividualClasses.LIST_INDIVIDUAL_CLASSES_INDIRECT OWL2_FULL_MEM thrpt 20 1061883,645 ? 11899,620 ops/s
JmhIndividualClasses.LIST_INDIVIDUAL_CLASSES_INDIRECT OWL2_EL_MEM thrpt 20 979498,876 ? 22328,129 ops/s
JmhIndividualClasses.LIST_INDIVIDUAL_CLASSES_INDIRECT OWL1_LITE_MEM thrpt 20 600111,538 ? 10245,863 ops/s
JmhIndividualClasses.LIST_INDIVIDUAL_CLASSES_INDIRECT OWL2_FULL_MEM_RDFS_INF thrpt 20 323,415 ? 14,609 ops/s
JmhIndividualClasses.LIST_INDIVIDUAL_CLASSES_INDIRECT OWL2_DL_MEM_BUILTIN_INF thrpt 20 33709,495 ? 329,313 ops/s
JmhIndividualClasses.LIST_INDIVIDUAL_CLASSES_INDIRECT LEGACY_OWL_MEM thrpt 20 532256,642 ? 9438,609 ops/s
JmhIndividualClasses.LIST_INDIVIDUAL_CLASSES_INDIRECT LEGACY_OWL_DL_MEM_RDFS_INF thrpt 20 193,377 ? 8,711 ops/s
JmhListClasses.LIST_ALL_CLASSES OWL2_FULL_MEM thrpt 20 3913,181 ? 54,105 ops/s
JmhListClasses.LIST_ALL_CLASSES OWL2_EL_MEM thrpt 20 4280,284 ? 20,349 ops/s
JmhListClasses.LIST_ALL_CLASSES OWL1_LITE_MEM thrpt 20 21437,334 ? 702,863 ops/s
JmhListClasses.LIST_ALL_CLASSES OWL2_FULL_MEM_RDFS_INF thrpt 20 123,030 ? 4,547 ops/s
JmhListClasses.LIST_ALL_CLASSES OWL2_DL_MEM_BUILTIN_INF thrpt 20 3671,583 ? 72,838 ops/s
JmhListClasses.LIST_ALL_CLASSES LEGACY_OWL_MEM thrpt 20 9994,878 ? 272,441 ops/s
JmhListClasses.LIST_ALL_CLASSES LEGACY_OWL_DL_MEM_RDFS_INF thrpt 20 266,424 ? 6,418 ops/s
JmhListClasses.LIST_NAMED_CLASSES OWL2_FULL_MEM thrpt 20 34730,936 ? 1610,608 ops/s
JmhListClasses.LIST_NAMED_CLASSES OWL2_EL_MEM thrpt 20 36848,320 ? 635,520 ops/s
JmhListClasses.LIST_NAMED_CLASSES OWL1_LITE_MEM thrpt 20 23413,521 ? 486,528 ops/s
JmhListClasses.LIST_NAMED_CLASSES OWL2_FULL_MEM_RDFS_INF thrpt 20 993,880 ? 47,671 ops/s
JmhListClasses.LIST_NAMED_CLASSES OWL2_DL_MEM_BUILTIN_INF thrpt 20 32552,578 ? 1775,482 ops/s
JmhListClasses.LIST_NAMED_CLASSES LEGACY_OWL_MEM thrpt 20 9877,561 ? 285,693 ops/s
JmhListClasses.LIST_NAMED_CLASSES LEGACY_OWL_DL_MEM_RDFS_INF thrpt 20 259,240 ? 6,974 ops/s
JmhListIndividuals.LIST_INDIVIDUALS OWL2_FULL_MEM thrpt 20 2753,444 ? 31,634 ops/s
JmhListIndividuals.LIST_INDIVIDUALS OWL2_EL_MEM thrpt 20 2969,503 ? 28,523 ops/s
JmhListIndividuals.LIST_INDIVIDUALS OWL1_LITE_MEM thrpt 20 1769,376 ? 46,018 ops/s
JmhListIndividuals.LIST_INDIVIDUALS OWL2_FULL_MEM_RDFS_INF thrpt 20 0,933 ? 0,006 ops/s
JmhListIndividuals.LIST_INDIVIDUALS OWL2_DL_MEM_BUILTIN_INF thrpt 20 2711,182 ? 37,211 ops/s
JmhListIndividuals.LIST_INDIVIDUALS LEGACY_OWL_MEM thrpt 20 1333,065 ? 14,264 ops/s
JmhListIndividuals.LIST_INDIVIDUALS LEGACY_OWL_DL_MEM_RDFS_INF thrpt 20 0,017 ? 0,001 ops/s
JmhSubClasses.LIST_SUB_CLASSES_DIRECT OWL2_FULL_MEM thrpt 20 1131,328 ? 18,373 ops/s
JmhSubClasses.LIST_SUB_CLASSES_DIRECT OWL2_EL_MEM thrpt 20 1128,517 ? 18,958 ops/s
JmhSubClasses.LIST_SUB_CLASSES_DIRECT OWL1_LITE_MEM thrpt 20 1080,470 ? 11,340 ops/s
JmhSubClasses.LIST_SUB_CLASSES_DIRECT OWL2_FULL_MEM_RDFS_INF thrpt 20 48,010 ? 0,615 ops/s
JmhSubClasses.LIST_SUB_CLASSES_DIRECT OWL2_DL_MEM_BUILTIN_INF thrpt 20 86,404 ? 0,896 ops/s
JmhSubClasses.LIST_SUB_CLASSES_DIRECT LEGACY_OWL_MEM thrpt 20 3552,075 ? 121,430 ops/s
JmhSubClasses.LIST_SUB_CLASSES_DIRECT LEGACY_OWL_DL_MEM_RDFS_INF thrpt 20 19,666 ? 0,395 ops/s
JmhSubClasses.LIST_SUB_CLASSES_INDIRECT OWL2_FULL_MEM thrpt 20 96706,467 ? 1448,771 ops/s
JmhSubClasses.LIST_SUB_CLASSES_INDIRECT OWL2_EL_MEM thrpt 20 80929,295 ? 2835,746 ops/s
JmhSubClasses.LIST_SUB_CLASSES_INDIRECT OWL1_LITE_MEM thrpt 20 44455,080 ? 637,873 ops/s
JmhSubClasses.LIST_SUB_CLASSES_INDIRECT OWL2_FULL_MEM_RDFS_INF thrpt 20 164,218 ? 2,610 ops/s
JmhSubClasses.LIST_SUB_CLASSES_INDIRECT OWL2_DL_MEM_BUILTIN_INF thrpt 20 5624,272 ? 45,155 ops/s
JmhSubClasses.LIST_SUB_CLASSES_INDIRECT LEGACY_OWL_MEM thrpt 20 49828,475 ? 1656,329 ops/s
JmhSubClasses.LIST_SUB_CLASSES_INDIRECT LEGACY_OWL_DL_MEM_RDFS_INF thrpt 20 159,887 ? 3,668 ops/s
Any update on this case? I ask because my work depends on the final resolution. If approve I will think about free time to prepare PR, if reject I would like to know the reasons, in that last case I would improve the library according to the feedback, or leave it as is, having opportunity to observe the duplication of the functionality by Jena.
Any update on this case? I ask because my work depends on the final resolution. If approve I will think about free time to prepare PR,
If I'm being perfectly honest I think it's mainly because nobody active in the project has enough OWL background/interest to meaningfully review the code.
Remember that everyone who is a commuter or PMC member is purely a volunteer, while several of us have $dayjob's that involve working with Jena, none of us is directly paid by our employers specifically to do Jena work. Therefore we all tend to focus our efforts on things that affect us, bugs with widespread impact, or things that are easy to address, thus larger new features that we personally have no need for are hard to find time for.
if reject I would like to know the reasons, in that last case I would improve the library according to the feedback,
From glancing over your repository my main concern is that it appears to duplicate a lot of code from ONT-API, presumably to avoid creating a circular dependency since ONT-API already relies on Jena. Could that be achieved differently by making the Jena OWL 2 support a new Jena module that pulls in the dependency on ONT-API (explicitly excluding its own Jena dependency) so you'd get all the supporting code you need from there without duplication? As long as ONT-API is keeping reasonably aligned with Jena releases (and Jena doesn't break any APIs it relies on in a release) things should work.
As a general consideration accepting large contributions of this nature is tricky, especially when none of the active committers have the necessary background/interest to maintain it going forward, so we have to try and gauge whether there's enough community interest (beyond you as a contributor) in actually using and maintaining it.
or leave it as is, having opportunity to observe the duplication of the functionality by Jena.
Realistically Jena won't get OWL 2 support unless someone like yourself provides a PR for it. So I'm not against this proposal in any sense, I just don't have the background to do anything more than a perfunctory review.
From glancing over your repository my main concern is that it appears to duplicate a lot of code from ONT-API, presumably to avoid creating a circular dependency since ONT-API already relies on Jena.
There is no duplication of code. Since version 3.5.0 ONT-API uses Jena-OWL2 as a dependency. These libraries are responsible for different functionality: Jena-OWL2 runs RDF and InfGraph, while ONT-API runs OWLAxioms. If/when new OntModel appears in Jena, ONT-API will use it directly.
I'd like to see OWL2 support in Jena.
If/when new OntModel appears in Jena
Realistically - it's not going to happen anytime soon. Compatibility/stability is important to many Jena users. Adding a new module for OWL2 would be less constraining on the OWL2 features and no API migration lockstep.
Jena has the loose concept of "core modules" and "extra modules". "Core" is roughly those upto the Fuseki server binaries.
"Extra modules" are at risk of being removed if they don't get maintenance. We do have "one person" extra modules already.
I pulled down https://github.com/sszuev/jena-owl2 and "mvn install" worked. Updating to Jena 5.0.0 didn't work but no surprises.
mvn dependency:tree
doesn't look too worrying.
Not touching net.sourceforge.owlapi
is good! - net.sf.owlapi has some worrying license issues.
To help with the investigation and review, I have created a PR https://github.com/apache/jena/pull/2420. This is basically a copy-paste, and the alignment with the Jena rules and integration (e.g., moving/renaming vocabularies) can be done later to avoid conflicts when rebasing. All commits have been copied. Squashing can be made before merging (but I'd preserve history, it is important for investigation).
Also, there is jena-5.x.x branch in the original (https://github.com/sszuev/jena-owl2) repo.
OWL2 support is now in the codebase thanks to the work by @sszuev. It will be released in Jena version 5.1.0.
Version
4.x.x
Question
One more question.
I've already raised this issue in Dev ML (can't find the link right now). There was no final decision, or I missed it. I think it would not be bad if this issue is open again for discussion here.
Here is ONT-API. ONT-API is an RDF-centric Java library to work with OWL2. It's alternative implementation of OWL-API. Each ontology has an RDF
org.apache.jena.graph.Graph
underlying.The library consists of two parts:
com.github.owlcs.ontapi.jena.model.OntModel
(jena RDF Model, similar to theorg.apache.jena.ontology.OntModel
) andcom.github.owlcs.ontapi.Ontology
(extended OWL-APIOWLOntology
). The second part (i.e. the implementation of OWL-API itself) depends on the first one.Perhaps the first part, ONT-API's
OntModel
, would look organically in Apache Jena itself (as an replacement Jena'sOntModel
, which does not support OWL2).The problem here is that ONT-API's
OntModel
covers OWL2 syntax, but that's all. There is no support for Jena-rules, different specs, etc. To close this gap I started a new project: https://github.com/sszuev/jena-owl2 It's still under developing, so this question is preliminary, maybe it is raised too early.In any case, if this could be a part of Apache Jena, then the development could be adjusted for this purpose (via feedbacks, reviews, recommendations, etc). Otherwise, I will keep in mind that the project
jena-owl2
will be a separated library.