Skip to content

Commit 3ada462

Browse files
committed
fix(pii): keep every NER window's spans instead of assuming a neighbour found them
NER reads context, so a window can find a name the previous one missed or cut short; spans are now only deduplicated by exact position, and overlapping spans are left to the anonymizer to merge
1 parent aefa16a commit 3ada462

1 file changed

Lines changed: 6 additions & 13 deletions

File tree

‎apps/pii/server.py‎

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -272,12 +272,10 @@ def _analyze_long(
272272
does) and no match can straddle a cut. Only NER runs in overlapping windows
273273
(see NER_WINDOW_CHARS), asked for just its own entities, plus the pattern
274274
entities when a score_threshold makes context scoring matter (see
275-
`_window_entities`). A span touching a
276-
window's far edge may be cut short, so it is left to the next window, which
277-
sees it whole; a span ending inside the overlap before that edge was already
278-
found by the previous window and is skipped. The rest are shifted to
279-
whole-text offsets; a span found by both passes keeps its higher score, and
280-
overlapping spans are left to the anonymizer, which merges them."""
275+
`_window_entities`). Every window's spans are kept, shifted to whole-text
276+
offsets: NER reads context, so a window can find a name its neighbour missed
277+
or cut short. A span found more than once keeps its highest score, and
278+
overlapping spans of one type are merged by the anonymizer."""
281279
entities = entities or None
282280
results = analyzer.analyze(
283281
text=text,
@@ -293,18 +291,13 @@ def _analyze_long(
293291
return results
294292
step = NER_WINDOW_CHARS - NER_WINDOW_OVERLAP
295293
for start in range(0, len(text), step):
296-
window = text[start : start + NER_WINDOW_CHARS]
297-
is_last = start + NER_WINDOW_CHARS >= len(text)
298-
seen_through = NER_WINDOW_OVERLAP if start else 0
299294
for result in analyzer.analyze(
300-
text=window,
295+
text=text[start : start + NER_WINDOW_CHARS],
301296
language=language,
302297
entities=window_entities,
303298
score_threshold=score_threshold,
304299
return_decision_process=return_decision_process,
305300
):
306-
if result.end < seen_through or (not is_last and result.end >= len(window)):
307-
continue
308301
results.append(
309302
RecognizerResult(
310303
result.entity_type,
@@ -315,7 +308,7 @@ def _analyze_long(
315308
result.recognition_metadata,
316309
)
317310
)
318-
if is_last:
311+
if start + NER_WINDOW_CHARS >= len(text):
319312
break
320313
unique: dict[tuple[str, int, int], RecognizerResult] = {}
321314
for result in results:

0 commit comments

Comments
 (0)