a03675113a
- .claude/agents/fn-orquestador/SKILL.md - .claude/commands/fn_claude.md - .claude/rules/INDEX.md - .claude/rules/cpp_apps.md - .claude/rules/ids_naming.md - CHANGELOG.md - apps/dag_engine/README.md - apps/dag_engine/api.go - apps/dag_engine/dags_migrated/example.yaml - apps/dag_engine/dags_migrated/example_lineage_tracking.yaml - ... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4.9 KiB
4.9 KiB
name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, params, output, tested, tests, test_file_path, file_path
| name | kind | lang | domain | version | purity | signature | description | tags | uses_functions | uses_types | returns | returns_optional | error_type | imports | params | output | tested | tests | test_file_path | file_path | |||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| deduplicate_entities | function | py | datascience | 1.0.0 | pure | def deduplicate_entities(candidates: list[EntityCandidate], name_threshold: float = 0.85, same_type_only: bool = True) -> DeduplicationResult | Agrupa entidades candidatas que refieren a la misma entidad real usando fuzzy matching de nombres (Levenshtein + Jaccard) y Union-Find para clusters transitivos. Retorna entidades mergeadas con mapas de resolucion de IDs y log de merges. |
|
|
|
|
false |
|
|
DeduplicationResult con entidades mergeadas, mapas de resolucion de IDs (name_to_id) y log de merges realizados | true |
|
python/functions/datascience/deduplicate_entities_test.py | python/functions/datascience/deduplicate_entities.py |
Ejemplo
from python.types.datascience.entity_candidate import EntityCandidate
from python.functions.datascience.deduplicate_entities import deduplicate_entities
candidates = [
EntityCandidate(name="John Smith", type_ref="person", confidence=0.9),
EntityCandidate(name="Smith, John", type_ref="person", confidence=0.85),
EntityCandidate(name="Google", type_ref="organization", confidence=0.95),
EntityCandidate(name="Google LLC", type_ref="organization", confidence=0.88),
]
result = deduplicate_entities(candidates, name_threshold=0.85, same_type_only=True)
# result.total_before = 4
# result.total_after = 2
# result.merge_log = [
# {"canonical": "John Smith", "merged": ["Smith, John"], "score": 0.91, "reason": "fuzzy_name"},
# {"canonical": "Google", "merged": ["Google LLC"], "score": 0.89, "reason": "fuzzy_name"},
# ]
Algoritmo
- Normalizar nombres usando
normalize_entity_name()sobre cada candidato segun sutype_ref - Comparacion pairwise dentro del mismo tipo (si
same_type_only=True):- Para tipos tecnicos (ip, email, domain, crypto_wallet, phone): matching exacto normalizado
- Para el resto:
score = max(levenshtein_sim, jaccard_sim)+ bonus por contencion (+0.3) y acronimos (+0.3)
- Union-Find para clusters transitivos: si A
B y BC, entonces {A, B, C} forman un cluster - Merge por cluster:
- Nombre canonico: candidato con mayor
confidence - Atributos:
merge_entity_attributes()sobre todos los candidatos del cluster - Confidence:
maxdel cluster - Source chunks: union de todos los candidatos
merged_from: union de todos los nombres originales
- Nombre canonico: candidato con mayor
Heuristicas de similitud de nombres
| Heuristica | Efecto |
|---|---|
| Levenshtein | 1 - (edit_distance / max_len) |
| Jaccard sobre tokens | |A ∩ B| / |A ∪ B| |
| Score base | max(lev_sim, jaccard_sim) |
| Contencion (a in b o b in a) | +0.3 hasta max 1.0 |
| Acronimo ("FBI" ~ "Federal Bureau of Investigation") | +0.3 hasta max 1.0 |
| Tipos exactos (ip/email/domain) | solo matching exacto, ignora umbral |
Complejidad
- Pairwise: O(N^2) — aceptable para <1000 entidades (tipico por documento)
- Union-Find con path compression: O(α(N)) amortizado por operacion
- Para escalar a >1000: pre-filtrar por primera letra o n-gram index antes de comparar
Notas
Funcion pura. Implementa Levenshtein y Jaccard internamente para evitar dependencias externas a este modulo. Las funciones del registry levenshtein_distance_py_cybersecurity y jaccard_similarity_py_cybersecurity son equivalentes pero requieren imports adicionales — la implementacion inline mantiene la funcion sin dependencias de stdlib.
El name_to_id del resultado es el mapa de resolucion principal para la fase de deduplicacion de relaciones: permite resolver cualquier variante de nombre de una entidad a su ID canonico.