--- name: align_relations_to_entities kind: function lang: py domain: datascience version: "1.0.0" purity: pure signature: "def align_relations_to_entities(triplets: list[dict], entity_names: list[str]) -> list[dict]" description: "Filtra y alinea triplets REBEL/mREBEL a nombres canonicos de entidades. Para cada triplet, resuelve head y tail contra entity_names con match exacto case-insensitive o substring (gana el nombre mas largo). Descarta triplets donde algun lado no resuelve o head==tail." tags: [rebel, mrebel, relation-extraction, nlp, align, knowledge-graph, datascience, python, transformer] uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "" imports: [] params: - name: triplets desc: "lista de dicts producida por parse_rebel_output, con claves head, head_type, type, tail, tail_type" - name: entity_names desc: "nombres canonicos de entidades conocidas contra los que alinear (ej. [e.name for e in entities])" output: "lista de dicts con claves from (str), kind (str), to (str), head_type (str), tail_type (str). from/to son valores tomados verbatim de entity_names." tested: true tests: - "match exacto case-insensitive resuelve correctamente" - "substring entity en span del head" - "substring span dentro del nombre de entidad" - "gana el nombre de entidad mas largo en ambiguedad" - "triplet sin match se descarta" - "triplet con head == tail se descarta (self-loop)" test_file_path: "python/functions/datascience/tests/test_align_relations_to_entities.py" file_path: "python/functions/datascience/align_relations_to_entities.py" notes: | Funcion pura. Compone con parse_rebel_output: el output de parse_rebel_output entra como triplets, y entity_names viene de [e.name for e in entities] del contexto de extraccion. Estrategia de matching: 1. Exacto case-insensitive (O(1) via dict) 2. Substring bidireccional: entity in span O span in entity (itera por longitud DESC) Esto cubre casos como mREBEL emitiendo "esta en Bilbao" cuando la entidad es "Bilbao", o "Banco Santander S.A." cuando la entidad canonizada es "Banco Santander". --- ## Ejemplo ```python from python.functions.datascience.parse_rebel_output import parse_rebel_output from python.functions.datascience.align_relations_to_entities import align_relations_to_entities decoded = "tp_XX Pablo Isla Inditex employer" triplets = parse_rebel_output(decoded) entities = ["Pablo Isla", "Inditex", "A Coruna"] aligned = align_relations_to_entities(triplets, entities) # [{'from': 'Pablo Isla', 'kind': 'employer', 'to': 'Inditex', # 'head_type': 'per', 'tail_type': 'org'}] ``` ## Estrategia de matching 1. **Exacto case-insensitive**: ``"inditex"`` == ``"Inditex"``. 2. **Substring bidireccional**: la entidad esta contenida en el span del modelo, o el span del modelo esta contenido en el nombre de la entidad. Cuando varias entidades encajan, gana la mas larga (mas especifica). ## Notas - No hace fuzzy matching (Levenshtein, etc.) — la precision sobre el recall es preferida en el contexto de grafos de conocimiento. - Para mejorar recall: normalizar entity_names antes de llamar (quitar siglas, tildes). - Los triplets con ``from == to`` (self-loops) se descartan siempre.