OPENNLP-1880: Add a Lexical knowledge base seam with WN-LMF and WNDB readers and a Morphy lemmatizer - #1155
Draft
krickert wants to merge 4 commits into
Draft
OPENNLP-1880: Add a Lexical knowledge base seam with WN-LMF and WNDB readers and a Morphy lemmatizer#1155krickert wants to merge 4 commits into
krickert wants to merge 4 commits into
Conversation
mawiesne
marked this pull request as draft
July 8, 2026 04:33
krickert
force-pushed
the
wordnet-api
branch
2 times, most recently
from
July 8, 2026 14:44
1a70da6 to
d01ddff
Compare
krickert
marked this pull request as ready for review
July 8, 2026 15:07
krickert
marked this pull request as draft
July 8, 2026 16:18
Contributor
Author
|
There's a minor windows-specific build issue due to line endings and Windoze. Will flip back to review once I find my windows machine and test. Code is the same though. |
krickert
force-pushed
the
wordnet-api
branch
3 times, most recently
from
July 9, 2026 19:19
0551c1d to
d01ddff
Compare
Contributor
|
Hi @krickert - as mentioned on Slack I currently dont have the time for a manual review but I just let Fable do a comprehensive review on this PR. Here is the result:
Human review will follow. |
Contributor
Author
|
Thanks, every finding is addressed in 69ead68. Point by point:
Module tests go from 86 to 112; reactor verify is clean. |
krickert
force-pushed
the
wordnet-api
branch
3 times, most recently
from
July 19, 2026 11:41
6534cdb to
8878e03
Compare
krickert
added a commit
to ai-pipestream/opennlp
that referenced
this pull request
Jul 24, 2026
…ENNLP-1895 recorded Restate the map against apache main a864230, cut as 3.0.0-M5 on 2026-07-24. apache#1177 (OPENNLP-1870) merged upstream and moves into the merged box, apache#1190 and apache#1191 are marked ready for review, and OPENNLP-1895 (quantized embedding tables) joins the diagram in its own colour: filed in JIRA with the pull request deliberately held until apache#1165 and apache#1152 move. Statuses now carry the measured GitHub draft flag and how far each head sits behind main, which surfaces three things the old text did not: apache#1182 is a draft again, apache#1167 is based on main rather than on apache#1155 and carries the seam and isBlank commits as copies, and apache#1152 reports conflicts only because its apache-hosted sentencepiece base has diverged from the refreshed head.
…s and a Morphy lemmatizer Adds the LexicalKnowledgeBase contract in opennlp.tools.wordnet and the opennlp-wordnet module implementing it twice: WnLmfReader for WN-LMF XML and WndbReader for the legacy WNDB database files, with reader-equivalence coverage over miniature fixtures of both formats. The WN-LMF reader skips DOCTYPE declarations unresolved with DTD support off, so Open English WordNet releases parse unmodified while entity expansion stays closed; the WNDB fixtures are pinned to LF so their embedded byte offsets survive Windows checkout. The Morphy lemmatizer resolves inflected forms through suffix rules and the format's exception lists. Null arguments fail loudly with IllegalArgumentException, malformed data raises the checked InvalidFormatException, and the public seam carries no brand name: WordNet stays in the names of the classes that actually read WordNet formats.
Add docbkx/wordnet.xml, wire it into the manual, and add WordNetUsageExampleTest asserting the lookups the chapter prints.
…ment with the review conventions
…undary, pin WNDB rejections - Narrow the LexicalKnowledgeBase javadoc so the interface stops prescribing what only an implementation can promise: lemma matching semantics and thread safety are now stated as implementation specific and documented where they hold, on InMemoryWordNetLexicon, which already carries @threadsafe and describes the folding it applies. - Reword the contains() javadoc to say plainly that the default implementation delegates to lookup(), instead of speculating about cheaper overrides. - Move the null-element checks in MorphyLemmatizer up to the public lemmatize() overloads, both the array form and the list form, so validation happens once at the boundary the caller sees; the private lemmasOf() no longer repeats them and now documents that its arguments are validated by the caller. - Reject a null argument in LemmaFolding.splitOnSpaces() rather than letting it fail later as a NullPointerException, and capitalize the fold() message so it matches the wording the other validators use. - Document the throws clauses that the explicit validation adds, on LemmaKey.of() and on splitOnSpaces(). - Extract the repeated WN-LMF attribute names into ID_ATTRIBUTE, PART_OF_SPEECH_ATTRIBUTE, REL_TYPE_ATTRIBUTE, and TARGET_ATTRIBUTE, and the shared error opening into MALFORMED_PREFIX, so the element handlers stop repeating string literals. - Extract the WNDB offset failure detail into MALFORMED_OFFSET, shared by the length check and the digit check. - Fold the duplicated WNDB message construction into malformedMessage(), so the tokenizer builds the text directly instead of constructing an InvalidFormatException only to read getMessage() back off it. - Drop the redundant fileName parameter from WndbReader.readAll(), which already names the full path it failed to open. - Reduce the visibility of the Parser helpers in WnLmfReader: malformed() and line() are now private instance methods like every other helper in that class. - Make MorphyLemmatizer.rulesFor() an instance method for the same reason, so the lemmatizer's private helpers are consistent. - Add the missing javadoc on the RELATION_NAMES and POINTER_SYMBOLS lookup tables and on both RawSynset holders, the last undocumented members in the readers. - Correct two stale comments: the build() comment now points at memberLemmas(), where the synset and member part-of-speech agreement is really checked, and the mutate() comment in the tests states the actual constraint, that an edit which changes a line's length is only safe when the reader is expected to fail on that line before it reads the ones after it. - Add a parameterized WNDB test pinning eight field-level rejections that had no coverage: the offset length and digit checks, the synset and index part of speech mismatches, the base-16 word count field, the minimum word count, the pointer pos, the gloss separator, and the syntactic marker. - Add pinning tests for the newly explicit validation: splitOnSpaces() on null, and the list lemmatize() overload with a null token and with a null tag. - Share the fixtures instead of duplicating them: WndbReaderTest now exposes DOG_ID, CANID_ID, and its fixtureDirectory(), WnLmfReaderTest exposes fixture(), and LexiconConcurrencyTest and WordNetUsageExampleTest use those instead of their own loader copies and hardcoded ids. - Document the package-private test fixture helpers and switch WordNetUsageExampleTest to static assertion imports, matching the other tests in the module.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the format-agnostic lexical knowledge base seam to opennlp-api (
opennlp.tools.wordnet:LexicalKnowledgeBase,Synset,WordNetPos,WordNetRelation), and a newopennlp-extensions/opennlp-wordnetmodule with two clean-room readers behind it:WnLmfReader: a StAX reader for WN-LMF XML, Open English WordNet's interchange format. XXE-hardened per the OWASP posture for DOCTYPE-bearing formats: the DOCTYPE line real OEWN releases ship is tokenized and skipped while external entities and the external DTD subset stay fully disabled, so an unmodified download parses directly; a dedicated test proves a DOCTYPE-declared internal-subset entity payload fails loud rather than expanding.WndbReader: a reader for legacy Princeton WNDB directories, validating the format's documented offset contract.Both produce equivalent immutable, thread-safe lexicon views, pinned by a structural equivalence test over matching miniature fixtures. On top of the seam,
MorphyLemmatizerimplements the existingLemmatizerinterface with the documented Morphy algorithm: exception-list lookup first, then per-POS detachment rules with every candidate validated against the lexicon.Naming: the seam interface is
LexicalKnowledgeBaserather than a WordNet-branded name; the contract is generic and only the format-specific readers carry the WordNet name.The module ships code only; users point it at a WordNet database they downloaded. Verified against Princeton 3.0 (117,659 synsets) and OEWN 2024 (120,630 synsets). No third-party WordNet library is used or referenced.
Verification: api 303/0 (+17), opennlp-wordnet 86/0, full reactor verify green.
Small upstream note found along the way:
DictionaryLemmatizerjavadoc says unknown = "0" but the code returns the letter "O"; Morphy matches the code. Filed separately.https://issues.apache.org/jira/browse/OPENNLP-1880