Skip to content

Commit c83ccfe

Browse files
committed
Merge PR #1155 into OPENNLP-1833 gRPC helper
# Conflicts: # opennlp-distr/pom.xml # opennlp-distr/src/main/assembly/bin.xml # pom.xml # rat-excludes
2 parents 3a8139c + 9c0e9a0 commit c83ccfe

52 files changed

Lines changed: 6359 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

dev/test-omw-wordnets.sh

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#!/usr/bin/env bash
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to You under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
set -euo pipefail
18+
19+
readonly RELEASE_URL="https://github.com/omwn/omw-data/releases/download/v2.0"
20+
readonly IT_SHA512="d0ed09eaa6617509a7c8a1162e92d8085570328f5f773a108a168d7c517b02c8a1a79fe81297b7e94722b480b22f44f34419c46675f0c3e3af253504c2c5b380"
21+
readonly ES_SHA512="86851763f10cf9ba1c5ea42e8c09bcbff7954aea22c62fbd229bcf546f236de4d67251582ecfd7956e8dae22e975fdf1d5bfa3fd7e2fbf4d901751c89bc0ca66"
22+
readonly SV_SHA512="897a79c6a6ec43c10024c6ee55aac886bd27182e28127ef1248cc8748c1189e573b05b0b2cd9ada91756f0527b25cbac9a49b88a1f13a897f5442da7f0656c13"
23+
24+
fixture_dir=$(mktemp -d "${TMPDIR:-/tmp}/opennlp-omw.XXXXXXXX")
25+
trap 'rm -rf -- "$fixture_dir"' EXIT
26+
27+
fetch() {
28+
local language=$1
29+
local expected=$2
30+
local archive="$fixture_dir/omw-$language-2.0.tar.xz"
31+
curl --fail --location --silent --show-error \
32+
--connect-timeout 15 --max-time 120 \
33+
--output "$archive" "$RELEASE_URL/omw-$language-2.0.tar.xz"
34+
local actual
35+
actual=$(sha512sum "$archive" | cut -d' ' -f1)
36+
if [[ "$actual" != "$expected" ]]; then
37+
echo "SHA-512 mismatch for omw-$language-2.0.tar.xz" >&2
38+
exit 1
39+
fi
40+
tar -xJf "$archive" -C "$fixture_dir"
41+
}
42+
43+
fetch it "$IT_SHA512"
44+
fetch es "$ES_SHA512"
45+
fetch sv "$SV_SHA512"
46+
47+
repo_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
48+
cd "$repo_dir"
49+
./mvnw -pl opennlp-extensions/opennlp-wordnet -am \
50+
-Dopennlp.forkCount=1 -Drat.skip=true \
51+
-Dtest=WnLmfOmwIntegrationTest -Dsurefire.failIfNoSpecifiedTests=false \
52+
-Dopennlp.wordnet.omwDir="$fixture_dir" test
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package opennlp.tools.wordnet;
18+
19+
import java.util.List;
20+
import java.util.Optional;
21+
22+
/**
23+
* Lemma and synset lookup over a loaded lexical-semantic resource in the WordNet family. Synset
24+
* identity is opaque and source-qualified (see {@link Synset#id()}). Lookups return their matches
25+
* in the source's sense order and never return {@code null}.
26+
*
27+
* <p>How a queried lemma is matched against the source's written forms is implementation
28+
* specific and documented there. Returned {@link Synset#lemmas() lemmas} preserve the source's
29+
* written forms, with spaces in multiword lemmas.</p>
30+
*
31+
* <p>Thread safety is implementation specific.</p>
32+
*/
33+
public interface LexicalKnowledgeBase {
34+
35+
/**
36+
* Finds the synsets containing a lemma with a part of speech, in the source's sense order
37+
* (the most salient sense first when the source ranks senses).
38+
*
39+
* @param lemma The lemma to look up. Must not be {@code null}.
40+
* @param pos The part of speech to look it up as. Must not be {@code null}.
41+
* @return The matching synsets, never {@code null}; empty when the lexicon does not contain
42+
* the lemma with that part of speech.
43+
* @throws IllegalArgumentException Thrown if {@code lemma} or {@code pos} is {@code null}.
44+
*/
45+
List<Synset> lookup(String lemma, WordNetPOS pos);
46+
47+
/**
48+
* Finds a synset by its opaque identifier.
49+
*
50+
* @param synsetId The synset identifier, as minted by this lexicon. Must not be {@code null}.
51+
* @return The synset, or empty when this lexicon has no synset with that identifier.
52+
* @throws IllegalArgumentException Thrown if {@code synsetId} is {@code null}.
53+
*/
54+
Optional<Synset> synset(String synsetId);
55+
56+
/**
57+
* Navigates one typed relation from a synset.
58+
*
59+
* @param synsetId The source synset identifier. Must not be {@code null}.
60+
* @param relation The relation type to follow. Must not be {@code null}.
61+
* @return The target synset ids in source order, never {@code null}; empty when the synset is
62+
* unknown or has no relation of that type.
63+
* @throws IllegalArgumentException Thrown if {@code synsetId} or {@code relation} is
64+
* {@code null}.
65+
*/
66+
default List<String> related(String synsetId, WordNetRelation relation) {
67+
if (relation == null) {
68+
throw new IllegalArgumentException("Relation must not be null");
69+
}
70+
return synset(synsetId).map(s -> s.related(relation)).orElse(List.of());
71+
}
72+
73+
/**
74+
* Tests whether the lexicon contains a lemma with a part of speech. The default implementation
75+
* delegates to {@link #lookup(String, WordNetPOS)}.
76+
*
77+
* @param lemma The lemma to test. Must not be {@code null}.
78+
* @param pos The part of speech to test it as. Must not be {@code null}.
79+
* @return {@code true} if the lexicon contains the lemma with that part of speech.
80+
* @throws IllegalArgumentException Thrown if {@code lemma} or {@code pos} is {@code null}.
81+
*/
82+
default boolean contains(String lemma, WordNetPOS pos) {
83+
return !lookup(lemma, pos).isEmpty();
84+
}
85+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package opennlp.tools.wordnet;
18+
19+
import java.util.Collections;
20+
import java.util.EnumMap;
21+
import java.util.List;
22+
import java.util.Map;
23+
24+
import opennlp.tools.commons.ThreadSafe;
25+
26+
/**
27+
* One synonym set: a single lexicalized concept with its member lemmas, gloss, and typed
28+
* relations to other synsets.
29+
*
30+
* <p>The {@link #id() id} is an opaque, source-qualified string minted by the reader that
31+
* produced the synset; consumers must not parse it, only pass it back to
32+
* {@link LexicalKnowledgeBase#synset(String)} and compare it for equality. Relations map each
33+
* {@link WordNetRelation} present on this synset to the target synset ids in source order.</p>
34+
*
35+
* <p>Instances are immutable and thread-safe: the list and map components are defensively
36+
* copied to immutable views at construction.</p>
37+
*
38+
* @param id The opaque, source-qualified synset identifier. Must not be {@code null} or
39+
* empty.
40+
* @param pos The part of speech. Must not be {@code null}.
41+
* @param lemmas The member lemmas in source order, human-readable (multiword lemmas use
42+
* spaces, not the underscores some formats store). Must not be {@code null} and
43+
* must not contain {@code null} or empty elements. May be empty for an
44+
* unlexicalized concept retained as a relation target.
45+
* @param gloss The definition text, possibly empty when the source has none. Must not be
46+
* {@code null}.
47+
* @param relations The typed relations, each mapping to the target synset ids in source order.
48+
* Must not be {@code null}; keys must not be {@code null}; each value must be
49+
* a non-empty list of non-{@code null}, non-empty target ids.
50+
*/
51+
@ThreadSafe
52+
public record Synset(
53+
String id,
54+
WordNetPOS pos,
55+
List<String> lemmas,
56+
String gloss,
57+
Map<WordNetRelation, List<String>> relations) {
58+
59+
/**
60+
* Creates a synset.
61+
*
62+
* @throws IllegalArgumentException Thrown if any component violates its documented constraint.
63+
*/
64+
public Synset {
65+
if (id == null || id.isEmpty()) {
66+
throw new IllegalArgumentException("Id must not be null or empty");
67+
}
68+
if (pos == null) {
69+
throw new IllegalArgumentException("Pos must not be null");
70+
}
71+
if (lemmas == null) {
72+
throw new IllegalArgumentException("Lemmas must not be null for synset " + id);
73+
}
74+
for (final String lemma : lemmas) {
75+
if (lemma == null || lemma.isEmpty()) {
76+
throw new IllegalArgumentException(
77+
"Lemmas must not contain a null or empty element for synset " + id);
78+
}
79+
}
80+
if (gloss == null) {
81+
throw new IllegalArgumentException("Gloss must not be null for synset " + id);
82+
}
83+
if (relations == null) {
84+
throw new IllegalArgumentException("Relations must not be null for synset " + id);
85+
}
86+
final Map<WordNetRelation, List<String>> copiedRelations =
87+
new EnumMap<>(WordNetRelation.class);
88+
for (final Map.Entry<WordNetRelation, List<String>> relation : relations.entrySet()) {
89+
if (relation.getKey() == null) {
90+
throw new IllegalArgumentException("Relations must not contain a null key for synset " + id);
91+
}
92+
final List<String> targets = relation.getValue();
93+
if (targets == null || targets.isEmpty()) {
94+
throw new IllegalArgumentException("Relation " + relation.getKey()
95+
+ " must map to a non-empty target list for synset " + id);
96+
}
97+
for (final String target : targets) {
98+
if (target == null || target.isEmpty()) {
99+
throw new IllegalArgumentException("Relation " + relation.getKey()
100+
+ " must not contain a null or empty target id for synset " + id);
101+
}
102+
}
103+
copiedRelations.put(relation.getKey(), List.copyOf(targets));
104+
}
105+
lemmas = List.copyOf(lemmas);
106+
relations = Collections.unmodifiableMap(copiedRelations);
107+
}
108+
109+
/**
110+
* Finds the target synset ids of one relation type.
111+
*
112+
* @param relation The relation type. Must not be {@code null}.
113+
* @return The target synset ids in source order, never {@code null}; empty when this synset
114+
* has no relation of that type.
115+
* @throws IllegalArgumentException Thrown if {@code relation} is {@code null}.
116+
*/
117+
public List<String> related(WordNetRelation relation) {
118+
if (relation == null) {
119+
throw new IllegalArgumentException("Relation must not be null");
120+
}
121+
final List<String> targets = relations.get(relation);
122+
return targets == null ? List.of() : targets;
123+
}
124+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package opennlp.tools.wordnet;
18+
19+
/**
20+
* The four parts of speech a wordnet-style lexicon distinguishes.
21+
*
22+
* <p>The enum carries none of the single-letter codes the on-disk formats use; readers own the
23+
* mapping from their format's codes to these values. Adjective satellites normalize to
24+
* {@link #ADJECTIVE}, with the cluster structure preserved through
25+
* {@link WordNetRelation#SIMILAR_TO}.</p>
26+
*/
27+
public enum WordNetPOS {
28+
29+
/** Nouns. */
30+
NOUN,
31+
32+
/** Verbs. */
33+
VERB,
34+
35+
/** Adjectives, including adjective satellites. */
36+
ADJECTIVE,
37+
38+
/** Adverbs. */
39+
ADVERB
40+
}

0 commit comments

Comments
 (0)