Is your feature request related to a problem? Please describe.
LemmaContextAwareEnhancer matches recognizer context words against per-token lemma strings. For Korean (spaCy ko_core_news_sm), lemmas are morpheme-joined strings like 급+여계+좌, so whether a context word survives inside that representation depends on where the statistical morpheme splitter happens to place its + boundaries.
The outcome is unpredictable even within the same word class. 계좌 (account) does match 계좌+이체 and 본인+계좌, but not 입금계+좌 (deposit account), 급+여계+좌 (salary account) or 회사+계+좌 (company account). 은행 (bank) matches 신한+은행 but not 국민은+행. It even fails for keywords standing completely alone: 주민등록번호 (resident registration number) lemmatizes to 주민등록번+호 and 예금주 (account holder) to 예금+주, so the keyword misses its own standalone occurrence.
I measured this end-to-end over 36 realistic Korean banking/PII sentences (benchmark in the comment below). The current enhancer fires on 16/36 (44%): 3/8 standalone, 7/10 with particles, 6/18 compounds. Raw-text substring matching fires on 36/36, with zero false boosts on the no-context controls.
For an English analogy: imagine compounds were written solid, like depositaccount, and your matcher only saw a statistical split like deposit+acc+ount. German compounds have the same shape (Konto inside Gehaltskonto). The existing :-split in NlpArtifacts.set_keywords doesn't help here, since ko uses + and splitting can't recover a keyword the segmentation cuts through. This also limits the effect of the Korean context terms recently added across kr_* recognizers (#1822, #1825, #2212, #2214).
Describe the solution you'd like
An opt-in SubstringContextAwareEnhancer that matches context words as raw-text substrings within a configurable character window (say ±100 chars) around each detection, keeping the same scoring semantics as the lemma enhancer (context_similarity_factor, min_score_with_context_similarity, MAX_SCORE cap). Cost is bounded by O(context words × window); repeated measurements show no overhead distinguishable from run-to-run noise (details in the benchmark comment). We've been running this in a production Korean PII-masking deployment.
Some design questions before I write the PR:
- Configuration: the enhancer is currently replaceable only programmatically (
AnalyzerEngine(context_aware_enhancer=...)). Would you accept an AnalyzerEngineProvider yaml key to select and parameterize the enhancer, with the default unchanged (lemma)?
- Over-matching: the measurements below show the current default already substring-matches against lemma strings, so raw-text matching has the same English over-match profile (
id inside video boosts in both), and the existing context_matching_mode="whole_word" suppresses it in both. Would a per-language matching mode (whole-word for space-delimited languages, raw-substring for agglutinative ones) be the preferred shape?
- New class, or a raw-text fallback inside
LemmaContextAwareEnhancer?
Describe alternatives you've considered
- Enumerating compound variants as context words: unbounded, doesn't scale.
- Splitting keywords on the ko
+ separator (like the existing : split): doesn't recover keywords the segmentation cuts through (급+여계+좌).
- Improving Korean lemmatization/tokenization: that's spaCy-model territory, and doesn't help other agglutinative languages.
- NER-based context detection: heavier and non-deterministic. The substring approach is a small, deterministic fix.
Additional context
We have a working, production-tested implementation and can submit a PR with tests once there's direction on the questions above. Benchmark data (hit rates, per-token lemma table, over-match comparison, latency) is in the first comment below. Related active work on the context path: #2208 (locale-aware case folding), #1969 (negative context).
Is your feature request related to a problem? Please describe.
LemmaContextAwareEnhancermatches recognizer context words against per-token lemma strings. For Korean (spaCyko_core_news_sm), lemmas are morpheme-joined strings like급+여계+좌, so whether a context word survives inside that representation depends on where the statistical morpheme splitter happens to place its+boundaries.The outcome is unpredictable even within the same word class. 계좌 (account) does match 계좌+이체 and 본인+계좌, but not 입금계+좌 (deposit account), 급+여계+좌 (salary account) or 회사+계+좌 (company account). 은행 (bank) matches 신한+은행 but not 국민은+행. It even fails for keywords standing completely alone: 주민등록번호 (resident registration number) lemmatizes to
주민등록번+호and 예금주 (account holder) to예금+주, so the keyword misses its own standalone occurrence.I measured this end-to-end over 36 realistic Korean banking/PII sentences (benchmark in the comment below). The current enhancer fires on 16/36 (44%): 3/8 standalone, 7/10 with particles, 6/18 compounds. Raw-text substring matching fires on 36/36, with zero false boosts on the no-context controls.
For an English analogy: imagine compounds were written solid, like
depositaccount, and your matcher only saw a statistical split likedeposit+acc+ount. German compounds have the same shape (KontoinsideGehaltskonto). The existing:-split inNlpArtifacts.set_keywordsdoesn't help here, since ko uses+and splitting can't recover a keyword the segmentation cuts through. This also limits the effect of the Korean context terms recently added across kr_* recognizers (#1822, #1825, #2212, #2214).Describe the solution you'd like
An opt-in
SubstringContextAwareEnhancerthat matches context words as raw-text substrings within a configurable character window (say ±100 chars) around each detection, keeping the same scoring semantics as the lemma enhancer (context_similarity_factor,min_score_with_context_similarity,MAX_SCOREcap). Cost is bounded by O(context words × window); repeated measurements show no overhead distinguishable from run-to-run noise (details in the benchmark comment). We've been running this in a production Korean PII-masking deployment.Some design questions before I write the PR:
AnalyzerEngine(context_aware_enhancer=...)). Would you accept anAnalyzerEngineProvideryaml key to select and parameterize the enhancer, with the default unchanged (lemma)?idinsidevideoboosts in both), and the existingcontext_matching_mode="whole_word"suppresses it in both. Would a per-language matching mode (whole-word for space-delimited languages, raw-substring for agglutinative ones) be the preferred shape?LemmaContextAwareEnhancer?Describe alternatives you've considered
+separator (like the existing:split): doesn't recover keywords the segmentation cuts through (급+여계+좌).Additional context
We have a working, production-tested implementation and can submit a PR with tests once there's direction on the questions above. Benchmark data (hit rates, per-token lemma table, over-match comparison, latency) is in the first comment below. Related active work on the context path: #2208 (locale-aware case folding), #1969 (negative context).