Mapeo semantico
El glosario ESFC utiliza mapeo semantico avanzado potenciado por inteligencia artificial para conectar terminos de 10 vocabularios diferentes de alimentos y Analisis del Ciclo de Vida, permitiendo la coincidencia inteligente de terminos entre fuentes y el descubrimiento de relaciones.
Vision general
El mapeo semantico crea relaciones entre terminos de diferentes fuentes (FoodEx2, Hestia, ecoinvent, etc.) utilizando una sofisticada cascada de coincidencia de 4 etapas que combina coincidencia exacta, deteccion de sinonimos y embeddings de inteligencia artificial.
Caracteristicas clave:
- Coincidencia potenciada por inteligencia artificial - Embeddings de OpenAI y Google AI
- Cascada de 4 etapas - Multiples estrategias de coincidencia con alternativas
- Validacion de calidad - Puntuacion de confianza y analisis de calidad de coincidencias
- Depuracion interactiva - Visualizacion de coincidencias en tiempo real
- Sin configuracion - Retrocede al modo simulado sin claves de interfaz de programacion de aplicaciones
Estrategia de coincidencia
Cascada de 4 etapas
El sistema de coincidencia semantica utiliza un enfoque en cascada, probando metodos progresivamente mas sofisticados:
Etapa 1: Coincidencia contextual (Mayor confianza)
↓ (si no hay coincidencia)
Etapa 2: Coincidencia exacta de nombre
↓ (si no hay coincidencia)
Etapa 3: Coincidencia por sinonimos
↓ (si no hay coincidencia)
Etapa 4: Busqueda por embedding semantico
Cada etapa tiene diferentes niveles de confianza y casos de uso.
Etapa 1: Coincidencia contextual
Metodo: Combina nombre + categoria para la coincidencia Confianza: 0.95 - 1.0 (Muy alta) Caso de uso: Cuando tanto el nombre como el contexto de categoria coinciden
Algoritmo:
function contextualMatch(term: Term, targetTerms: Term[]): Match | null {
const searchKey = `${term.name} ${term.category}`.toLowerCase()
for (const target of targetTerms) {
const targetKey = `${target.name} ${target.category}`.toLowerCase()
if (searchKey === targetKey) {
return {
sourceId: term.id,
targetId: target.id,
confidence: 1.0,
method: 'contextual'
}
}
}
return null
}
Ejemplo:
Fuente: FoodEx2 "Apple" (categoria: "Fruits")
Destino: Hestia "Apple" (categoria: "Inputs & Products")
Coincidencia: Contextual (confianza: 1.0)
Etapa 2: Coincidencia exacta de nombre
Metodo: Coincidencia exacta de cadenas en nombres normalizados Confianza: 0.85 - 0.95 (Alta) Caso de uso: Nombres identicos en diferentes fuentes
Normalizacion:
- Conversion a minusculas
- Eliminacion de espacios al inicio y final
- Eliminacion de caracteres especiales
- Manejo de plurales (opcional)
Algoritmo:
function exactMatch(term: Term, targetTerms: Term[]): Match | null {
const normalized = normalizeName(term.name)
for (const target of targetTerms) {
if (normalized === normalizeName(target.name)) {
return {
sourceId: term.id,
targetId: target.id,
confidence: 0.9,
method: 'exact'
}
}
}
return null
}
function normalizeName(name: string): string {
return name.toLowerCase().trim().replace(/[^a-z0-9\s]/g, '')
}
Ejemplo:
Fuente: "Wheat grain"
Destino: "wheat grain"
Coincidencia: Exacta (confianza: 0.9)
Etapa 3: Coincidencia por sinonimos
Metodo: Diccionario de sinonimos integrado Confianza: 0.70 - 0.85 (Media-alta) Caso de uso: Nombres alternativos conocidos y variaciones comunes
Diccionario de sinonimos:
const SYNONYMS = {
'beef': ['cattle meat', 'bovine meat'],
'pork': ['pig meat', 'swine meat'],
'milk': ['dairy milk', 'cow milk'],
'wheat': ['common wheat', 'bread wheat'],
'rice': ['paddy rice', 'rice grain'],
'CO2': ['carbon dioxide', 'co2 emission'],
'CH4': ['methane', 'methane emission'],
'N2O': ['nitrous oxide', 'n2o emission']
}
Algoritmo:
function synonymMatch(term: Term, targetTerms: Term[]): Match | null {
const termSynonyms = getSynonyms(term.name)
for (const target of targetTerms) {
const targetNormalized = normalizeName(target.name)
for (const synonym of termSynonyms) {
if (normalizeName(synonym) === targetNormalized) {
return {
sourceId: term.id,
targetId: target.id,
confidence: 0.8,
method: 'synonym',
matchedSynonym: synonym
}
}
}
}
return null
}
Ejemplo:
Fuente: "Beef"
Destino: "Cattle meat"
Coincidencia: Sinonimo (confianza: 0.8, via "cattle meat")
Etapa 4: Busqueda por embedding semantico
Metodo: Similitud de vectores potenciada por inteligencia artificial usando embeddings Confianza: 0.50 - 0.70 (Media) Caso de uso: Similitud semantica cuando las coincidencias exactas fallan
Proveedores de inteligencia artificial:
-
OpenAI (Recomendado)
- Modelo:
text-embedding-3-small - Dimensiones: 1536
- Economico y preciso
- Modelo:
-
Google Generative AI (Alternativa)
- Modelo:
text-embedding-004 - Dimensiones: 768
- Buena alternativa a OpenAI
- Modelo:
-
Modo simulado (Alternativa)
- Embeddings deterministicos basados en cadenas
- No requiere clave de interfaz de programacion de aplicaciones
- Adecuado para pruebas
Algoritmo:
async function semanticMatch(
term: Term,
targetTerms: Term[],
provider: 'openai' | 'google'
): Promise<Match | null> {
// Generar embedding para termino fuente
const sourceEmbedding = await generateEmbedding(
`${term.name} ${term.category}`,
provider
)
let bestMatch: Match | null = null
let highestSimilarity = 0
for (const target of targetTerms) {
// Generar embedding para termino destino
const targetEmbedding = await generateEmbedding(
`${target.name} ${target.category}`,
provider
)
// Calcular similitud del coseno
const similarity = cosineSimilarity(sourceEmbedding, targetEmbedding)
if (similarity > highestSimilarity && similarity > 0.5) {
highestSimilarity = similarity
bestMatch = {
sourceId: term.id,
targetId: target.id,
confidence: similarity,
method: 'semantic',
similarity: similarity
}
}
}
return bestMatch
}
function cosineSimilarity(a: number[], b: number[]): number {
const dotProduct = a.reduce((sum, val, i) => sum + val * b[i], 0)
const magnitudeA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0))
const magnitudeB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0))
return dotProduct / (magnitudeA * magnitudeB)
}
Ejemplo:
Fuente: "Grass-fed beef cattle"
Destino: "Extensive pasture cattle production"
Similitud de embedding: 0.72
Coincidencia: Semantica (confianza: 0.72)
Integracion de proveedores de inteligencia artificial
Configuracion de OpenAI
# Establecer clave de interfaz de programacion de aplicaciones
export OPENAI_API_KEY="sk-..."
# Ejecutar coincidencia semantica
npm run match-glossaries
Caracteristicas de OpenAI:
- Ultimos modelos de embedding
- Alta precision para terminologia de alimentos/Analisis del Ciclo de Vida
- Costes razonables de interfaz de programacion de aplicaciones
- Tiempos de respuesta rapidos
Ejemplo de llamada a la interfaz de programacion de aplicaciones:
import OpenAI from 'openai'
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY
})
async function getEmbedding(text: string): Promise<number[]> {
const response = await openai.embeddings.create({
model: 'text-embedding-3-small',
input: text,
dimensions: 1536
})
return response.data[0].embedding
}
Configuracion de Google AI
# Establecer clave de interfaz de programacion de aplicaciones
export GOOGLE_API_KEY="AIza..."
# Ejecutar coincidencia semantica con Google
npm run match-glossaries
Caracteristicas de Google AI:
- Alternativa a OpenAI
- Buen soporte multilingue
- Precios competitivos
- Embeddings fiables
Ejemplo de llamada a la interfaz de programacion de aplicaciones:
import { GoogleGenerativeAI } from '@google/generative-ai'
const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY!)
async function getEmbedding(text: string): Promise<number[]> {
const model = genAI.getGenerativeModel({ model: 'text-embedding-004' })
const result = await model.embedContent(text)
return result.embedding.values
}
Modo simulado (sin claves de interfaz de programacion de aplicaciones)
# Ejecutar sin claves de interfaz de programacion de aplicaciones (embeddings simulados)
npm run match-glossaries:mock
Caracteristicas del modo simulado:
- Embeddings deterministicos basados en cadenas
- Sin costes de interfaz de programacion de aplicaciones
- Adecuado para pruebas
- Resultados reproducibles
Algoritmo simulado:
function mockEmbedding(text: string, dimensions: number = 1536): number[] {
const embedding = new Array(dimensions).fill(0)
for (let i = 0; i < text.length; i++) {
const charCode = text.charCodeAt(i)
embedding[i % dimensions] += charCode / 1000
}
// Normalizar
const magnitude = Math.sqrt(
embedding.reduce((sum, val) => sum + val * val, 0)
)
return embedding.map(val => val / magnitude)
}
Integracion con base de datos
Los mapeos semanticos pueden almacenarse en PostgreSQL con pgvector para busqueda de similitud eficiente:
Configuracion de pgvector
-- Habilitar extension pgvector
CREATE EXTENSION IF NOT EXISTS vector;
-- Crear tabla de embeddings
CREATE TABLE term_embeddings (
id SERIAL PRIMARY KEY,
term_id VARCHAR(255) NOT NULL,
term_name TEXT NOT NULL,
term_source VARCHAR(50) NOT NULL,
embedding vector(1536),
created_at TIMESTAMP DEFAULT NOW()
);
-- Crear indice para busqueda de similitud
CREATE INDEX ON term_embeddings
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);
-- Encontrar terminos similares usando distancia del coseno
SELECT
term_id,
term_name,
term_source,
1 - (embedding <=> query_embedding) as similarity
FROM term_embeddings
WHERE term_source != 'source_to_exclude'
ORDER BY embedding <=> query_embedding
LIMIT 10;
Almacenamiento de embeddings
import { Pool } from 'pg'
async function storeEmbedding(
termId: string,
termName: string,
source: string,
embedding: number[]
): Promise<void> {
const pool = new Pool({
connectionString: process.env.DATABASE_URL
})
await pool.query(
`INSERT INTO term_embeddings (term_id, term_name, term_source, embedding)
VALUES ($1, $2, $3, $4)`,
[termId, termName, source, `[${embedding.join(',')}]`]
)
}
Validacion de calidad
Puntuacion de confianza
A cada coincidencia se le asigna una puntuacion de confianza basada en el metodo de coincidencia:
| Metodo | Rango de confianza | Calidad |
|---|---|---|
| Contextual | 0.95 - 1.0 | Excelente |
| Exacto | 0.85 - 0.95 | Muy bueno |
| Sinonimo | 0.70 - 0.85 | Bueno |
| Semantico | 0.50 - 0.70 | Aceptable |
Umbrales de confianza:
- Alta confianza (≥ 0.85): Aceptacion automatica
- Confianza media (0.70 - 0.84): Revision recomendada
- Baja confianza (< 0.70): Revision manual requerida
Indicadores de calidad de coincidencias
Buenas coincidencias:
- Alta puntuacion de confianza (≥ 0.85)
- Categorias similares
- Mismo dominio (alimentos, Analisis del Ciclo de Vida, envasado)
- Descripciones consistentes
Coincidencias cuestionables:
- Confianza media (0.70 - 0.84)
- Categorias diferentes
- Mapeo entre dominios
- Superposicion parcial de nombres
Coincidencias pobres:
- Baja confianza (< 0.70)
- Categorias no relacionadas
- Dominios diferentes
- Desajuste semantico
Metodos de validacion
Validacion automatizada:
function validateMatch(match: Match): ValidationResult {
const issues: string[] = []
// Verificar umbral de confianza
if (match.confidence < 0.5) {
issues.push('Confianza por debajo del umbral')
}
// Verificar consistencia de categorias
if (match.sourceCategory !== match.targetCategory) {
issues.push('Desajuste de categoria')
}
// Verificar alineacion de dominios
if (!domainsAlign(match.sourceDomain, match.targetDomain)) {
issues.push('Desajuste de dominio')
}
return {
valid: issues.length === 0,
confidence: match.confidence,
issues: issues,
recommendation: issues.length === 0 ? 'accept' : 'review'
}
}
Revision manual:
- Exportar coincidencias a CSV/Excel
- Revisar coincidencias de baja confianza
- Verificar mapeos entre dominios
- Documentar decisiones de validacion
Optimizacion de rendimiento
Procesamiento por lotes
Procesar multiples terminos en lotes para reducir llamadas a la interfaz de programacion de aplicaciones:
async function batchEmbeddings(
texts: string[],
batchSize: number = 100
): Promise<number[][]> {
const batches: number[][][] = []
for (let i = 0; i < texts.length; i += batchSize) {
const batch = texts.slice(i, i + batchSize)
const embeddings = await Promise.all(
batch.map(text => generateEmbedding(text))
)
batches.push(embeddings)
}
return batches.flat()
}
Estrategia de cache
Cachear embeddings para evitar llamadas redundantes a la interfaz de programacion de aplicaciones:
import fs from 'fs'
class EmbeddingCache {
private cache: Map<string, number[]>
private cacheFile: string
constructor(cacheFile: string) {
this.cacheFile = cacheFile
this.cache = this.loadCache()
}
async getEmbedding(text: string, provider: string): Promise<number[]> {
const cacheKey = `${provider}:${text}`
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey)!
}
const embedding = await generateEmbedding(text, provider)
this.cache.set(cacheKey, embedding)
this.saveCache()
return embedding
}
private loadCache(): Map<string, number[]> {
if (fs.existsSync(this.cacheFile)) {
const data = JSON.parse(fs.readFileSync(this.cacheFile, 'utf8'))
return new Map(Object.entries(data))
}
return new Map()
}
private saveCache(): void {
const data = Object.fromEntries(this.cache)
fs.writeFileSync(this.cacheFile, JSON.stringify(data, null, 2))
}
}
Limitacion de tasa
Respetar los limites de tasa de la interfaz de programacion de aplicaciones:
import pLimit from 'p-limit'
const limit = pLimit(10) // Maximo 10 solicitudes concurrentes
async function matchWithRateLimit(
sourceTerms: Term[],
targetTerms: Term[]
): Promise<Match[]> {
const matches = await Promise.all(
sourceTerms.map(term =>
limit(() => findBestMatch(term, targetTerms))
)
)
return matches.filter(m => m !== null) as Match[]
}
Casos de uso
Mapeo entre vocabularios
FoodEx2 a Hestia:
FoodEx2: A010101 (Trigo comun)
↓ coincidencia semantica
Hestia: term/crop-wheat
↓ proporciona
Datos de impacto ambiental
ecoinvent a Eaternity:
ecoinvent: market for wheat grain | GLO
↓ coincidencia semantica
Eaternity: FlowNode.product_name = "Wheat grain"
↓ permite
Calculo de huella de carbono de EOS
Importacion de datos de usuario
Coincidencia de cabeceras de columnas CSV:
Cabecera de usuario: "Produktname" (aleman)
↓ coincidencia semantica
Propiedad de Eaternity: eaternity-property-productname
↓ mapea a
Campo de la interfaz de programacion de aplicaciones de EOS: FlowNode.product_name
Aplicaciones de investigacion
Analisis del Ciclo de Vida multifuente:
Pregunta de investigacion: "Huella de carbono de la carne de vacuno organica"
↓ coincidencia semantica
FoodEx2: F010101 (Ternera) + faceta Organico
Hestia: term/livestock-cattle-organic
ecoinvent: cattle for slaughtering, organic | CH
↓ combina
Analisis del Ciclo de Vida completo con multiples fuentes de datos
Depuracion interactiva
Caracteristicas de la interfaz web
El sitio web del glosario ESFC proporciona herramientas de depuracion interactivas:
Visualizacion de coincidencias:
- Visualizacion de calidad de coincidencias en tiempo real
- Visualizacion de puntuacion de confianza
- Indicador de metodo (contextual, exacto, sinonimo, semantico)
- Comparacion de terminos fuente/destino
Herramientas de depuracion:
- Explicacion de coincidencias (por que se selecciono esta coincidencia)
- Coincidencias alternativas (otras coincidencias potenciales)
- Puntuaciones de similitud para coincidencias semanticas
- Comparacion de categorias y dominios
Opciones de exportacion:
- Exportar coincidencias a CSV
- Descargar grafo de relaciones
- Generar informe de mapeo
- Guardar para revision manual
Ejecutar coincidencia semantica
Linea de comandos
# Coincidencia semantica completa (produccion)
npm run match-glossaries
# Modo de prueba (datos de muestra)
npm run match-glossaries:test
# Modo simulado (sin claves de interfaz de programacion de aplicaciones)
npm run match-glossaries:mock
# Pares de fuentes especificos
node scripts/glossary-matcher.js \
--source foodex2 \
--target hestia \
--output mappings.json
Configuracion
// Configuracion de scripts/glossary-matcher.js
const config = {
provider: 'openai', // o 'google'
verbose: true,
mockMode: false,
confidenceThreshold: 0.5,
maxResults: 10,
batchSize: 100,
cacheFile: './cache/embeddings.json'
}
Formatos de salida
JSON:
{
"matches": [
{
"sourceId": "foodex2-A010101",
"sourceName": "Common wheat",
"targetId": "hestia-term-crop-wheat",
"targetName": "Wheat crop",
"confidence": 0.95,
"method": "contextual",
"validated": true
}
],
"statistics": {
"totalSourceTerms": 31601,
"totalTargetTerms": 36044,
"matchesFound": 15823,
"averageConfidence": 0.82,
"methodBreakdown": {
"contextual": 8934,
"exact": 4521,
"synonym": 1876,
"semantic": 492
}
}
}
Grafo de relaciones (JSON-LD):
{
"@context": "http://www.w3.org/2004/02/skos/core#",
"@graph": [
{
"@id": "foodex2:A010101",
"@type": "Concept",
"prefLabel": "Common wheat",
"exactMatch": "hestia:term-crop-wheat",
"relatedMatch": "ecoinvent:market-wheat-grain"
}
]
}
Mejores practicas
Estrategia de coincidencia
-
Empezar con metodos de alta confianza
- Confiar en coincidencias contextuales y exactas cuando sea posible
- Usar busqueda semantica como alternativa
- Validar manualmente coincidencias de baja confianza
-
Coincidencia especifica por dominio
- Coincidir terminos de alimentos con fuentes de alimentos (FoodEx2, Hestia)
- Coincidir procesos de Analisis del Ciclo de Vida con ecoinvent
- Coincidir propiedades con el esquema de Eaternity
-
Calidad sobre cantidad
- Preferir menos coincidencias de alta calidad
- Revisar y validar coincidencias cuestionables
- Documentar decisiones de mapeo
Optimizacion de rendimiento
-
Procesamiento por lotes
- Procesar terminos en lotes
- Usar solicitudes concurrentes (con limites)
- Cachear embeddings
-
Actualizaciones incrementales
- Solo volver a coincidir terminos modificados
- Mantener historial de coincidencias
- Rastrear estado de validacion
-
Gestion de recursos
- Monitorizar uso y costes de la interfaz de programacion de aplicaciones
- Usar modo simulado para desarrollo
- Cachear embeddings localmente
Documentacion relacionada
- Fuentes de datos - Vision general de las 10 fuentes
- Esquema de Eaternity - Coincidencia de propiedades
- Formatos de datos - Exportar datos de relaciones
- Referencia de FoodEx2 - Mapeo de clasificacion de alimentos
- Referencia de Hestia - Mapeo de datos de Analisis del Ciclo de Vida