feat(finess): whitelist de mono-mots distinctifs courts (EMBRUNS, etc.)

Le matcher Aho-Corasick FINESS rejetait tous les mono-mots < 10 chars pour
éviter les faux positifs. Conséquence : EMBRUNS (7 chars), présent dans
etablissements_distinctifs.txt, était ignoré et devait être forcé en YAML
(LES EMBRUNS, REED LES EMBRUNS, EMBRUNS BIDART, regex [Ee]mbruns).

Nouveau fichier data/finess/mono_mots_distinctifs.txt contenant la whitelist
curée des mono-mots courts considérés comme distinctifs. Maintenance manuelle
(un mot par ligne, commentaires autorisés). Le matcher accepte un mono-mot
< 10 chars uniquement s'il est dans cette whitelist.

Initialisation : embruns, embrun (documents CHCB "Les Embruns").

Validation :
- _FINESS_AC matche maintenant "les embruns quelque part" et "embruns seul"
- Pas de régression sur trackare-18007562 (122 hits)

Après ce fix + futurs, on pourra retirer LES EMBRUNS / REED LES EMBRUNS /
EMBRUNS BIDART et regex [Ee]mbruns de force_mask_terms du YAML.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-15 09:35:16 +02:00
parent fd95ae5f2a
commit e6f3853426
2 changed files with 34 additions and 8 deletions

View File

@@ -3120,6 +3120,21 @@ def _build_finess_ac():
"le bourg", "le val", "le clos", "le mas", "le bourg", "le val", "le clos", "le mas",
"les pins", "les chenes", "les oliviers", "les pins", "les chenes", "les oliviers",
} }
# Whitelist explicite de mono-mots < 10 chars considérés comme distinctifs
# (sinon rejetés par le filtre général). Exemple : EMBRUNS (7 chars).
# Alimentée depuis data/finess/mono_mots_distinctifs.txt — curation manuelle.
mono_file = data_dir / "mono_mots_distinctifs.txt"
mono_whitelist: set = set()
if mono_file.exists():
try:
for _line in mono_file.read_text(encoding="utf-8").splitlines():
_w = _line.strip()
if _w and not _w.startswith("#"):
mono_whitelist.add(_w.lower())
log.info(f"FINESS mono-mots distinctifs whitelist: {len(mono_whitelist)} entrées")
except Exception as _exc:
log.warning(f"Erreur chargement mono_mots_distinctifs.txt : {_exc}")
try: try:
ac = _ahocorasick.Automaton() ac = _ahocorasick.Automaton()
count = 0 count = 0
@@ -3142,16 +3157,16 @@ def _build_finess_ac():
_PRENOM_PREFIXES = {"jean", "marie", "louis", "pierre", "saint", "sainte"} _PRENOM_PREFIXES = {"jean", "marie", "louis", "pierre", "saint", "sainte"}
if len(words) == 2 and words[0] in _PRENOM_PREFIXES and len(words[1]) < 10: if len(words) == 2 and words[0] in _PRENOM_PREFIXES and len(words[1]) < 10:
continue continue
# Filtrer : >= 8 chars et >= 2 mots, OU >= 10 chars pour 1 mot # Filtrer : >= 8 chars et >= 2 mots, OU >= 10 chars pour 1 mot,
# Les noms courts sont gérés par RE_HOPITAL_VILLE # OU présent dans la whitelist explicite de mono-mots distinctifs.
if len(words) >= 2 and len(name) >= 8: if len(words) >= 2 and len(name) >= 8:
# Exclure les multi-mots dont TOUS les mots sont dans le stop words médical # Exclure les multi-mots dont TOUS les mots sont dans le stop words médical
if all(w in _MEDICAL_STOP_WORDS_SET or len(w) <= 2 for w in words): if all(w in _MEDICAL_STOP_WORDS_SET or len(w) <= 2 for w in words):
continue continue
ac.add_word(name, name) ac.add_word(name, name)
count += 1 count += 1
elif (len(words) == 1 and len(name) >= 10 elif len(words) == 1 and (len(name) >= 10 or name in mono_whitelist):
and name not in _ac_generic_blacklist if (name not in _ac_generic_blacklist
and name not in _MEDICAL_STOP_WORDS_SET and name not in _MEDICAL_STOP_WORDS_SET
and _normalize_for_matching(name) not in _MEDICAL_STOP_WORDS_SET): and _normalize_for_matching(name) not in _MEDICAL_STOP_WORDS_SET):
ac.add_word(name, name) ac.add_word(name, name)

View File

@@ -0,0 +1,11 @@
# Mono-mots FINESS considérés comme distinctifs malgré leur longueur < 10 chars
# Permet au matcher Aho-Corasick d'accepter des noms d'établissements courts
# qui sont dans etablissements_distinctifs.txt mais filtrés par le seuil.
#
# ⚠ Ajouter uniquement des mots suffisamment RARES pour éviter les faux positifs
# (ex: "embruns" rare en français, OK — "parc", "jardin" trop génériques, NON).
#
# Un mot par ligne, lowercase, sans accents. Lignes vides et # ignorées.
embruns
embrun