--- name: merge_graphs kind: function lang: py domain: datascience version: "1.0.0" purity: pure signature: "def merge_graphs(graphs: list[dict], entity_key: str = 'name', similarity_threshold: float = 0.85) -> dict" description: "Mergea multiples grafos de conocimiento en uno deduplicando entities por similitud de nombre (Levenshtein normalizado). Relaciones se re-apuntan a las entities canonicas. Atributos se combinan por union." tags: [graph, merge, deduplication, knowledge-graph, levenshtein, similarity, datascience] uses_functions: [levenshtein_distance_py_cybersecurity] uses_types: [] returns: [] returns_optional: false error_type: "" imports: [sys, os] params: - name: graphs desc: "lista de grafos, cada uno con estructura {entities: [...], relations: [...]}" - name: entity_key desc: "campo de entity que se usa para fuzzy matching (defecto: 'name'). Determina similitud." - name: similarity_threshold desc: "umbral de similitud Levenshtein normalizado [0, 1] para mergear (tipico: 0.85). Mayor = mas estricto." output: "dict con estructura {entities: [...], relations: [...], merge_log: [...]}, grafo mergeado y deduplicado" tested: true tests: - "dos grafos con entity duplicada → merge" - "entities similares pero bajo threshold → no merge" - "relaciones re-apuntadas correctamente" - "merge log registra cada merge" - "tres grafos → merge transitivo" - "grafos sin overlap → concatenacion simple" test_file_path: "python/functions/datascience/merge_graphs_test.py" file_path: "python/functions/datascience/merge_graphs.py" --- ## Ejemplo ```python g1 = { "entities": [ {"id": "1", "name": "Alice Corp", "type": "company"}, {"id": "2", "name": "Bob", "type": "person"}, ], "relations": [ {"source_id": "2", "target_id": "1", "relation_type": "works_at"}, ], } g2 = { "entities": [ {"id": "3", "name": "Alice Corp.", "type": "company", "country": "US"}, ], "relations": [], } result = merge_graphs([g1, g2], similarity_threshold=0.85) # result["entities"] -> 2 entities (Alice Corp mergeada, Bob) # result["merge_log"] -> [{"merged": ["3", "1"], "into": "1", "similarity": 0.909}] # "Alice Corp." mergeada en "Alice Corp" porque similitud > 0.85 ``` ## Notas Funcion pura. Reutiliza `levenshtein_distance_py_cybersecurity` para calcular similitud normalizada entre nombres. **Algoritmo de merge transitivo**: si A~B y B~C, entonces A, B, C se mergean en uno solo. Se implementa via union-find (path compression simple). **Eleccion de canonical**: la entity con mas campos no-null gana. En caso de empate, la primera encontrada en el par. **Conflictos de atributos**: si ambas entities tienen un campo con valor, el canonical conserva el suyo (primero gana). Solo se copian campos que el canonical no tiene o tiene null. **Deduplicacion de relaciones**: por (source_id, target_id, relation_type). Si dos relaciones son identicas tras re-apuntar los IDs, se conserva la primera encontrada. **Complejidad**: O(n^2) en numero de entities por la comparacion de pares. Adecuado para grafos de knowledge tipicos (< 10K entities). Para grafos muy grandes, usar indexado por prefijo antes de comparar. **Importacion**: intenta importar `levenshtein_distance` desde el paquete `cybersecurity` del registry. Si no esta disponible, usa una reimplementacion inline equivalente.