Skip to content

OPENNLP-547: Add a transition-based dependency parser component - #1236

Merged
mawiesne merged 4 commits into
mainfrom
OPENNLP-547-dependency-parser
Oct 8, 2026
Merged

mawiesne merged 4 commits into
mainfrom
OPENNLP-547-dependency-parser

Conversation

@krickert

@krickert krickert commented Aug 22, 2026 •

Copy link
Copy Markdown
Contributor

Adds a transition-based dependency parser: API, arc-standard maxent parser, CoNLL-U reading, evaluation, cross validation, command line tools, eval and manual chapter. The feedforward parser is #1323, stacked on this branch.

API (opennlp-api): DependencyParser, DependencySample, DependencyArc and the immutable DependencyGraph. Input validation is DependencySample.checkTokensAndTags, shared by samples and parsers, and throws IllegalArgumentException.

Parser (opennlp-runtime): DependencyParserME runs an arc-standard transition system over a classifier trained with TrainingParameters. ArcStandardOracle derives transitions from projective trees; non-projective training sentences are skipped and counted. DependencyModel persists the classifier and manifest. DependencyEvaluator and DependencyCrossValidator report UAS and LAS with and without punctuation and accept DependencyEvaluationMonitor listeners.

Formats (opennlp-formats): ConlluDependencySampleStream reads CoNLL-U. ID and HEAD are integer columns, multiword ranges and empty nodes are skipped, -tagset u or x selects UPOS or XPOS, and the data must be UTF-8.

Tools (opennlp-cli): DependencyParserTrainer, DependencyParser, DependencyParserEvaluator and DependencyParserCrossValidator, with -misclassified output.

Eval: UniversalDependencyParserEval pins scores on the English, German, Spanish and French UD treebanks from opennlp-data.zip. Eval build: https://ci-builds.apache.org/job/OpenNLP/job/eval-tests-configurable/88/

Manual: a dependency parser chapter; its examples run as ConlluDependencyParserUsageTest.

Tests: 51 in opennlp-api, 102 in opennlp-runtime, 136 in opennlp-formats, 56 in opennlp-cli for the parser and CoNLL-U classes, with checkstyle and forbiddenapis clean.

OPENNLP-547

krickert added a commit to ai-pipestream/opennlp that referenced this pull request Aug 22, 2026
krickert added a commit that referenced this pull request Aug 26, 2026
…C helper base

# Conflicts:
#	opennlp-docs/src/docbkx/dependency.xml
krickert added a commit that referenced this pull request Aug 26, 2026
…C helper base

# Conflicts:
#	opennlp-docs/src/docbkx/dependency.xml
krickert added a commit that referenced this pull request Aug 30, 2026
krickert added a commit that referenced this pull request Sep 1, 2026
Base automatically changed from OPENNLP-1888-DocumentShape to main September 1, 2026 04:43
@mawiesne

mawiesne commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

@krickert Can you rebase this one onto main? Currently changes show up here that are now already included in main.

@krickert
krickert force-pushed the OPENNLP-547-dependency-parser branch from 71da201 to 83bc298 Compare September 1, 2026 07:54
@krickert
krickert marked this pull request as ready for review September 2, 2026 00:39
krickert added a commit that referenced this pull request Sep 4, 2026
# Conflicts:
#	opennlp-docs/src/docbkx/dependency.xml
@krickert
krickert force-pushed the OPENNLP-547-dependency-parser branch from 83bc298 to 5cc4058 Compare September 4, 2026 21:59
@krickert

krickert commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Rebased on main .. good to go

#1182 merged the diff is the parser alone, 34 new files and no change to existing code.

Also a run of the review conventions.

krickert added a commit to ai-pipestream/opennlp that referenced this pull request Sep 5, 2026
# Conflicts:
#	opennlp-api/src/main/java/opennlp/tools/depparse/DependencyGraph.java
#	opennlp-api/src/main/java/opennlp/tools/depparse/DependencyParser.java
#	opennlp-api/src/main/java/opennlp/tools/depparse/DependencySample.java
#	opennlp-api/src/test/java/opennlp/tools/depparse/DependencyGraphTest.java
#	opennlp-api/src/test/java/opennlp/tools/depparse/DependencySampleTest.java
#	opennlp-core/opennlp-formats/dev/README-ud-treebanks.md
#	opennlp-core/opennlp-formats/dev/download-ud-treebank.sh
#	opennlp-core/opennlp-formats/src/main/java/opennlp/tools/formats/conllu/ConlluDependencySampleStream.java
#	opennlp-core/opennlp-formats/src/test/java/opennlp/tools/formats/conllu/ConlluDependencyParserEvalTest.java
#	opennlp-core/opennlp-formats/src/test/java/opennlp/tools/formats/conllu/ConlluDependencyParserUsageTest.java
#	opennlp-core/opennlp-formats/src/test/java/opennlp/tools/formats/conllu/ConlluDependencySampleStreamTest.java
#	opennlp-core/opennlp-runtime/src/main/java/opennlp/tools/depparse/ArcStandardOracle.java
#	opennlp-core/opennlp-runtime/src/main/java/opennlp/tools/depparse/ArcStandardState.java
#	opennlp-core/opennlp-runtime/src/main/java/opennlp/tools/depparse/DependencyContextGenerator.java
#	opennlp-core/opennlp-runtime/src/main/java/opennlp/tools/depparse/DependencyModel.java
#	opennlp-core/opennlp-runtime/src/main/java/opennlp/tools/depparse/DependencyParserME.java
#	opennlp-core/opennlp-runtime/src/main/java/opennlp/tools/depparse/FeedforwardContext.java
#	opennlp-core/opennlp-runtime/src/main/java/opennlp/tools/depparse/FeedforwardDependencyModel.java
#	opennlp-core/opennlp-runtime/src/main/java/opennlp/tools/depparse/FeedforwardDependencyParser.java
#	opennlp-core/opennlp-runtime/src/main/java/opennlp/tools/depparse/FeedforwardDependencyTrainer.java
#	opennlp-core/opennlp-runtime/src/main/java/opennlp/tools/depparse/Transition.java
#	opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/depparse/ArcStandardOracleTest.java
#	opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/depparse/ArcStandardStateTest.java
#	opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/depparse/DependencyParserEdgeCaseTest.java
#	opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/depparse/DependencyParserMETest.java
#	opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/depparse/DependencyTestSamples.java
#	opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/depparse/FeedforwardDependencyParserTest.java
#	opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/depparse/TransitionTest.java
#	opennlp-docs/src/docbkx/dependency.xml
@jzonthemtn

Copy link
Copy Markdown
Contributor

Thanks @krickert. A long open JIRA ticket for sure!

The API and graph validation look solid. I found two issues worth checking into:

  • The CoNLL-U reader accepts DEPREL=_ as a label instead of skipping the incomplete annotation.
  • Training with a tag such as UNK overwrites a reserved vocabulary entry, producing a model that serializes successfully but fails to reload.

What do you think about held-out accuracy tests for the neural parser, similar to the treebank evaluation for the classical parser?

@krickert

krickert commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

Thanks Jeff. Both are fixed, each with a failing test committed ahead of the fix. The CoNLL-U reader now skips a sentence whose relation column is the underscore placeholder, the same way it already skipped an underscore head. The feedforward trainer no longer lets a tag or label spelled like a reserved symbol take over that symbol's embedding row; it shares the row, as words already did, so the model reloads.

On held-out accuracy: I added UniversalDependencyParserEval in opennlp-eval-tests, following the AbstractEvalTest and OPENNLP_DATA_DIR pattern. It trains both parsers on the UD 2.0 English train split and pins the dev-split scores: the transition parser at UAS 0.8182 and LAS 0.7861, the feedforward parser at UAS 0.8413 and LAS 0.8174, on 25,148 words. The numbers reproduce exactly across runs. It replaces the property-gated evaluation test that lived in opennlp-formats.

@krickert

krickert commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

Eval build for this head (afd68fb) is running on Jenkins: https://ci-builds.apache.org/job/OpenNLP/job/eval-tests-configurable/74/ (eval-tests-configurable, branch OPENNLP-547-dependency-parser). It uses the opennlp-data.zip published on nightlies today and includes the new UniversalDependencyParserEval, so expect it to take longer than a regular eval run.

@krickert

krickert commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

Evals passed for this, going to re-run it as I added double precision scoring.

@rzo1
rzo1 marked this pull request as draft September 8, 2026 08:17
@rzo1

rzo1 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Evals passed for this, going to re-run it as I added double precision scoring.

Moved to draft for now. Please re-open as ready for review once all your additional checks and stuff are done.

@krickert
krickert marked this pull request as ready for review September 9, 2026 00:16
@krickert

krickert commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

@krickert

Copy link
Copy Markdown
Contributor Author

Eval ran successfully

@rzo1 rzo1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks. jzonthemtn's two issues are fixed with tests, and the eval pattern is right.

My main concern is the model. FeedforwardDependencyModel is not a BaseModel: it has its own binary format (ONLP-FFDP-1) with no manifest, language, version check or artifact serializer. Once released we have to support that format. The same goes for the rest of the component shape: training takes a Settings record instead of TrainingParameters, and there's no DependencyParserFactory extends BaseToolFactory, no CLI tools, and no stream factory registration. Every other component in OpenNLP works this way, and I don't want a second model format with 3.0.0.

I'd suggest splitting it:

  1. This PR: API (DependencyParser, DependencySample, DependencyGraph), the CoNLL-U reader, evaluator and arc-standard parts, aligned with the other components (Sample, serialVersionUID, TrainingParameters, factory, CLI).
  2. Follow-up: the feedforward model as a BaseModel, with a new eval run.

If you'd rather keep it in one PR, the model format has to be settled before we look at the details.

Other points:

  • OPENNLP-547 has no fix version. Please set 3.0.0.
  • There are 147 commits, some without a JIRA key. We will squash-merge.
  • Duplication, see inline comments.
  • dev/download-ud-treebank.sh, its README and UdTreebankDownloadScriptTest: the build doesn't use the script, since the eval reads from opennlp-data, and the unit test starts bash. Please remove all three and the reference in dependency.xml.

Comment thread opennlp-api/src/main/java/opennlp/tools/depparse/DependencySample.java Outdated
Comment thread opennlp-core/opennlp-runtime/src/main/java/opennlp/tools/depparse/Transition.java Outdated
@rzo1

rzo1 commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

@krickert Can you fixed up this branch plz? It has 147 commits and I don't think they belong here.

@krickert
krickert force-pushed the OPENNLP-547-dependency-parser branch from 5b05ca9 to e2d7be8 Compare September 20, 2026 18:16
@krickert

Copy link
Copy Markdown
Contributor Author

R4R @rzo1

@krickert

Copy link
Copy Markdown
Contributor Author

I'm really excited about this one. It's going to be a fun feature to have. The front end is going to look really cool. I'll rebase and mark r4r after it merges. No rush and thank you - I know this one is a larger one.

@rzo1 rzo1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we rebase and make use of ArgumentChecker?

@krickert

krickert commented Oct 3, 2026

Copy link
Copy Markdown
Contributor Author

Can we rebase and make use of ArgumentChecker?

Rebased onto main and switched the null checks to ArgumentChecks. The three combined checks now name the argument that was null.

@rzo1 rzo1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please find my (human) review comments attached.

Comment thread opennlp-api/src/main/java/opennlp/tools/depparse/DependencyGraph.java Outdated
Comment thread opennlp-api/src/main/java/opennlp/tools/depparse/DependencyGraph.java Outdated
@rzo1 rzo1 added new feature New functionality (Jira: New Feature) component: parser Parser and dependency parser labels Oct 4, 2026
@krickert
krickert force-pushed the OPENNLP-547-dependency-parser branch from 1ee7fff to be6089d Compare October 5, 2026 01:42
@krickert

krickert commented Oct 5, 2026

Copy link
Copy Markdown
Contributor Author

@rzo1 followed all the suggestions and agree with all of them. Please check again

@krickert
krickert requested a review from rzo1 October 5, 2026 05:15
@rzo1

rzo1 commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Can you trigger an eval run?

@krickert

krickert commented Oct 5, 2026

Copy link
Copy Markdown
Contributor Author

@krickert

krickert commented Oct 6, 2026

Copy link
Copy Markdown
Contributor Author

Eval build on it's way.

https://ci-builds.apache.org/job/OpenNLP/job/eval-tests-configurable/95/

Eval green

krickert and others added 4 commits October 7, 2026 21:16
Add an arc-standard dependency parser with maxent and perceptron training,
model persistence, and an immutable dependency tree. Skip and count
non-projective training sentences.

Read UTF-8 CoNLL-U samples with universal or language-specific POS tags.
Add CLI tools for training, parsing, evaluation and cross-validation,
including attachment scores, evaluation listeners and -misclassified
output.

Add treebank evaluations for English, German, Spanish and French, and a
manual chapter with tested examples.

Assisted-by: Claude Code 2.1.281
Co-authored-by: Kristian Rickert <kristian@apache.org>
Co-authored-by: Claude <noreply@anthropic.com>
Reviewed-by: Kristian Rickert <kristian@apache.org>
Signed-off-by: Kristian Rickert <kristian@apache.org>
Add one internal check for non-empty parallel arrays and use it from the
private validators in DependencySample and DependencyParserME. Preserve
the validation order and name null elements by their parameter and index.

Test the shared check directly and verify that samples and parsers report
the same errors for invalid input.
@rzo1
rzo1 force-pushed the OPENNLP-547-dependency-parser branch from cad9004 to 15e4c1b Compare October 7, 2026 19:18

@mawiesne mawiesne left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@krickert Thx for the PR and the patience with the reviewers. The set of code and test additions is now in great shape (💠 ) and I don't see more reasons to wait. Let's bring this to main (🚀 ). We can apply fixes and (potential) simplifications with more compact, future PRs, that is, it can be done prior to OpenNLP 3.0.0 release, if needed.

@mawiesne mawiesne added java Pull requests that update Java code tests Pull requests that add or update test code labels Oct 8, 2026
@mawiesne mawiesne changed the title OPENNLP-547: Add a transition-based dependency parser OPENNLP-547: Add a transition-based dependency parser component Oct 8, 2026
@mawiesne
mawiesne merged commit deb80ba into main Oct 8, 2026
10 checks passed
@mawiesne
mawiesne deleted the OPENNLP-547-dependency-parser branch October 8, 2026 19:52
@krickert

krickert commented Oct 8, 2026

Copy link
Copy Markdown
Contributor Author

@mawiesne - thank you for taking the time to review which has taught me so much in a short period of time. I'll say with humility: the PR-pocolapse you dealt with required so much patience, and I can't tell ya enough of how much I appreciate your work and patience to lead through and keep the quality so high. It's taught me a lot quickly - both technically and how to do things the apache way - and looking forward to further collaborations and contributions with the team.

I don't think I've had more fun with coding since I first compiled w/gcc via slackware linux for the first time in a dorm room :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component: parser Parser and dependency parser java Pull requests that update Java code new feature New functionality (Jira: New Feature) tests Pull requests that add or update test code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants