Mappatura Semantica
Il Glossario ESFC utilizza una mappatura semantica avanzata potenziata dall'intelligenza artificiale per connettere termini da 10 diversi vocabolari alimentari e LCA, abilitando l'abbinamento intelligente tra fonti diverse e la scoperta di relazioni.
Panoramica
La mappatura semantica crea relazioni tra termini provenienti da fonti diverse (FoodEx2, Hestia, ecoinvent, ecc.) utilizzando una sofisticata cascata di abbinamento a 4 stadi che combina abbinamento esatto, rilevamento dei sinonimi e embedding basati sull'intelligenza artificiale.
Funzionalita Chiave:
- Abbinamento Potenziato dall'IA - Embedding OpenAI e Google AI
- Cascata a 4 Stadi - Molteplici strategie di abbinamento con fallback
- Validazione della Qualita - Punteggio di confidenza e analisi della qualita degli abbinamenti
- Debug Interattivo - Visualizzazione degli abbinamenti in tempo reale
- Zero Configurazione - Fallback alla modalita mock senza chiavi API
Strategia di Abbinamento
Cascata a 4 Stadi
Il sistema di abbinamento semantico utilizza un approccio a cascata, provando metodi sempre piu sofisticati:
Stadio 1: Abbinamento Contestuale (Confidenza Massima)
↓ (se nessun abbinamento)
Stadio 2: Abbinamento Esatto del Nome
↓ (se nessun abbinamento)
Stadio 3: Abbinamento per Sinonimi
↓ (se nessun abbinamento)
Stadio 4: Ricerca con Embedding Semantici
Ogni stadio ha diversi livelli di confidenza e casi d'uso.
Stadio 1: Abbinamento Contestuale
Metodo: Combina nome + categoria per l'abbinamento Confidenza: 0.95 - 1.0 (Molto Alta) Caso d'Uso: Quando sia il nome che il contesto della categoria si allineano
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
}
Esempio:
Fonte: FoodEx2 "Apple" (categoria: "Fruits")
Target: Hestia "Apple" (categoria: "Inputs & Products")
Abbinamento: ✅ Contestuale (confidenza: 1.0)
Stadio 2: Abbinamento Esatto del Nome
Metodo: Abbinamento esatto di stringhe su nomi normalizzati Confidenza: 0.85 - 0.95 (Alta) Caso d'Uso: Nomi identici tra fonti diverse
Normalizzazione:
- Conversione in minuscolo
- Rimozione spazi bianchi
- Rimozione caratteri speciali
- Gestione plurali (opzionale)
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, '')
}
Esempio:
Fonte: "Wheat grain"
Target: "wheat grain"
Abbinamento: ✅ Esatto (confidenza: 0.9)
Stadio 3: Abbinamento per Sinonimi
Metodo: Dizionario integrato di sinonimi Confidenza: 0.70 - 0.85 (Medio-Alta) Caso d'Uso: Nomi alternativi noti e variazioni comuni
Dizionario dei Sinonimi:
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'],
'CO₂': ['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
}
Esempio:
Fonte: "Beef"
Target: "Cattle meat"
Abbinamento: ✅ Sinonimo (confidenza: 0.8, tramite "cattle meat")
Stadio 4: Ricerca con Embedding Semantici
Metodo: Similarita vettoriale potenziata dall'IA usando embedding Confidenza: 0.50 - 0.70 (Media) Caso d'Uso: Similarita semantica quando gli abbinamenti esatti falliscono
Provider di Intelligenza Artificiale:
-
OpenAI (Raccomandato)
- Modello:
text-embedding-3-small - Dimensioni: 1536
- Economico e accurato
- Modello:
-
Google Generative AI (Alternativa)
- Modello:
text-embedding-004 - Dimensioni: 768
- Buona alternativa a OpenAI
- Modello:
-
Modalita Mock (Fallback)
- Embedding deterministici basati su stringhe
- Nessuna chiave API richiesta
- Adatto per i test
Algoritmo:
async function semanticMatch(
term: Term,
targetTerms: Term[],
provider: 'openai' | 'google'
): Promise<Match | null> {
// Genera embedding per il termine sorgente
const sourceEmbedding = await generateEmbedding(
`${term.name} ${term.category}`,
provider
)
let bestMatch: Match | null = null
let highestSimilarity = 0
for (const target of targetTerms) {
// Genera embedding per il termine target
const targetEmbedding = await generateEmbedding(
`${target.name} ${target.category}`,
provider
)
// Calcola similarita 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)
}
Esempio:
Fonte: "Grass-fed beef cattle"
Target: "Extensive pasture cattle production"
Similarita Embedding: 0.72
Abbinamento: ✅ Semantico (confidenza: 0.72)
Integrazione Provider di Intelligenza Artificiale
Configurazione OpenAI
# Imposta la chiave API
export OPENAI_API_KEY="sk-..."
# Esegui l'abbinamento semantico
npm run match-glossaries
Funzionalita OpenAI:
- Ultimi modelli di embedding
- Alta accuratezza per terminologia alimentare/LCA
- Costi API ragionevoli
- Tempi di risposta veloci
Esempio di Chiamata API:
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
}
Configurazione Google AI
# Imposta la chiave API
export GOOGLE_API_KEY="AIza..."
# Esegui l'abbinamento semantico con Google
npm run match-glossaries
Funzionalita Google AI:
- Alternativa a OpenAI
- Buon supporto multilingue
- Prezzi competitivi
- Embedding affidabili
Esempio di Chiamata API:
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
}
Modalita Mock (Senza Chiavi API)
# Esegui senza chiavi API (embedding mock)
npm run match-glossaries:mock
Funzionalita Modalita Mock:
- Embedding deterministici basati su stringhe
- Nessun costo API
- Adatto per i test
- Risultati riproducibili
Algoritmo Mock:
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
}
// Normalizza
const magnitude = Math.sqrt(
embedding.reduce((sum, val) => sum + val * val, 0)
)
return embedding.map(val => val / magnitude)
}
Integrazione con Database
Le mappature semantiche possono essere archiviate in PostgreSQL con pgvector per una ricerca efficiente di similarita:
Configurazione pgvector
-- Abilita estensione pgvector
CREATE EXTENSION IF NOT EXISTS vector;
-- Crea tabella embedding
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()
);
-- Crea indice per ricerca di similarita
CREATE INDEX ON term_embeddings
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);
-- Trova termini simili usando distanza 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;
Archiviazione degli Embedding
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(',')}]`]
)
}
Validazione della Qualita
Punteggio di Confidenza
Ad ogni abbinamento viene assegnato un punteggio di confidenza basato sul metodo di abbinamento:
| Metodo | Range di Confidenza | Qualita |
|---|---|---|
| Contestuale | 0.95 - 1.0 | Eccellente |
| Esatto | 0.85 - 0.95 | Molto Buona |
| Sinonimo | 0.70 - 0.85 | Buona |
| Semantico | 0.50 - 0.70 | Discreta |
Soglie di Confidenza:
- Alta confidenza (≥ 0.85): Accettazione automatica
- Media confidenza (0.70 - 0.84): Revisione raccomandata
- Bassa confidenza (< 0.70): Revisione manuale richiesta
Indicatori di Qualita degli Abbinamenti
Abbinamenti Buoni:
- ✅ Alto punteggio di confidenza (≥ 0.85)
- ✅ Categorie simili
- ✅ Stesso dominio (alimentare, LCA, packaging)
- ✅ Descrizioni coerenti
Abbinamenti Discutibili:
- ⚠️ Media confidenza (0.70 - 0.84)
- ⚠️ Categorie diverse
- ⚠️ Mappatura tra domini diversi
- ⚠️ Sovrapposizione parziale del nome
Abbinamenti Scarsi:
- Bassa confidenza (< 0.70)
- ❌ Categorie non correlate
- ❌ Domini diversi
- ❌ Mancata corrispondenza semantica
Metodi di Validazione
Validazione Automatica:
function validateMatch(match: Match): ValidationResult {
const issues: string[] = []
// Controlla soglia di confidenza
if (match.confidence < 0.5) {
issues.push('Confidenza sotto la soglia')
}
// Controlla coerenza della categoria
if (match.sourceCategory !== match.targetCategory) {
issues.push('Mancata corrispondenza della categoria')
}
// Controlla allineamento del dominio
if (!domainsAlign(match.sourceDomain, match.targetDomain)) {
issues.push('Mancata corrispondenza del dominio')
}
return {
valid: issues.length === 0,
confidence: match.confidence,
issues: issues,
recommendation: issues.length === 0 ? 'accetta' : 'rivedi'
}
}
Revisione Manuale:
- Esporta abbinamenti in CSV/Excel
- Rivedi abbinamenti a bassa confidenza
- Verifica mappature tra domini diversi
- Documenta le decisioni di validazione
Ottimizzazione delle Prestazioni
Elaborazione in Batch
Elabora piu termini in batch per ridurre le chiamate API:
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()
}
Strategia di Caching
Memorizza in cache gli embedding per evitare chiamate API ridondanti:
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))
}
}
Rate Limiting
Rispetta i limiti di frequenza delle API:
import pLimit from 'p-limit'
const limit = pLimit(10) // Massimo 10 richieste concorrenti
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[]
}
Casi d'Uso
Mappatura tra Vocabolari
FoodEx2 verso Hestia:
FoodEx2: A010101 (Grano tenero)
↓ abbinamento semantico
Hestia: term/crop-wheat
↓ fornisce
Dati sull'impatto ambientale
ecoinvent verso Eaternity:
ecoinvent: market for wheat grain | GLO
↓ abbinamento semantico
Eaternity: FlowNode.product_name = "Wheat grain"
↓ abilita
Calcolo dell'impronta di carbonio EOS
Importazione Dati Utente
Abbinamento Intestazione Colonna CSV:
Intestazione Utente: "Produktname" (Tedesco)
↓ abbinamento semantico
Proprieta Eaternity: eaternity-property-productname
↓ mappa a
Campo API EOS: FlowNode.product_name
Applicazioni di Ricerca
LCA Multi-Fonte:
Domanda di Ricerca: "Impronta di carbonio del manzo biologico"
↓ abbinamento semantico
FoodEx2: F010101 (Manzo) + facet Biologico
Hestia: term/livestock-cattle-organic
ecoinvent: cattle for slaughtering, organic | CH
↓ combina
LCA completa con molteplici fonti dati
Debug Interattivo
Funzionalita dell'Interfaccia Web
Il sito web del Glossario ESFC fornisce strumenti di debug interattivi:
Visualizzazione degli Abbinamenti:
- Visualizzazione della qualita dell'abbinamento in tempo reale
- Visualizzazione del punteggio di confidenza
- Indicatore del metodo (contestuale, esatto, sinonimo, semantico)
- Confronto termine sorgente/target
Strumenti di Debug:
- Spiegazione dell'abbinamento (perche questo abbinamento e stato selezionato)
- Abbinamenti alternativi (altri potenziali abbinamenti)
- Punteggi di similarita per abbinamenti semantici
- Confronto categoria e dominio
Opzioni di Esportazione:
- Esporta abbinamenti in CSV
- Scarica grafo delle relazioni
- Genera report di mappatura
- Salva per revisione manuale
Esecuzione dell'Abbinamento Semantico
Linea di Comando
# Abbinamento semantico completo (produzione)
npm run match-glossaries
# Modalita test (dati campione)
npm run match-glossaries:test
# Modalita mock (senza chiavi API)
npm run match-glossaries:mock
# Coppie di fonti specifiche
node scripts/glossary-matcher.js \
--source foodex2 \
--target hestia \
--output mappings.json
Configurazione
// Configurazione scripts/glossary-matcher.js
const config = {
provider: 'openai', // oppure 'google'
verbose: true,
mockMode: false,
confidenceThreshold: 0.5,
maxResults: 10,
batchSize: 100,
cacheFile: './cache/embeddings.json'
}
Formati di Output
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 delle Relazioni (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"
}
]
}
Buone Pratiche
Strategia di Abbinamento
-
Iniziare con Metodi ad Alta Confidenza
- Affidatevi agli abbinamenti contestuali ed esatti quando possibile
- Usate la ricerca semantica come fallback
- Validate manualmente gli abbinamenti a bassa confidenza
-
Abbinamento Specifico per Dominio
- Abbinate termini alimentari a fonti alimentari (FoodEx2, Hestia)
- Abbinate processi LCA a ecoinvent
- Abbinate proprieta allo schema Eaternity
-
Qualita Prima della Quantita
- Preferite meno abbinamenti di alta qualita
- Revisionate e validate gli abbinamenti discutibili
- Documentate le decisioni di mappatura
Ottimizzazione delle Prestazioni
-
Elaborazione in Batch
- Elaborate i termini in batch
- Usate richieste concorrenti (con limiti)
- Memorizzate in cache gli embedding
-
Aggiornamenti Incrementali
- Ri-abbinate solo i termini modificati
- Mantenete lo storico degli abbinamenti
- Tracciate lo stato di validazione
-
Gestione delle Risorse
- Monitorate l'uso e i costi delle API
- Usate la modalita mock per lo sviluppo
- Memorizzate in cache gli embedding localmente
Documentazione Correlata
- Fonti Dati - Panoramica di tutte le 10 fonti
- Schema Eaternity - Abbinamento delle proprieta
- Formati Dati - Esportazione dei dati delle relazioni
- Riferimento FoodEx2 - Mappatura della classificazione alimentare
- Riferimento Hestia - Mappatura dei dati LCA