Correspondance sémantique
Le Glossaire ESFC utilise une correspondance sémantique avancée assistée par intelligence artificielle pour connecter les termes à travers 10 vocabulaires alimentaires et d'Analyse du Cycle de Vie différents, permettant une mise en correspondance intelligente entre sources et la découverte de relations.
Vue d'ensemble
La correspondance sémantique crée des relations entre les termes de différentes sources (FoodEx2, Hestia, ecoinvent, etc.) en utilisant une cascade de correspondance sophistiquée à 4 étapes qui combine la correspondance exacte, la détection de synonymes et les représentations vectorielles par intelligence artificielle.
Fonctionnalités clés :
- Correspondance assistée par intelligence artificielle - Représentations vectorielles OpenAI et Google AI
- Cascade à 4 étapes - Multiples stratégies de correspondance avec solutions de repli
- Validation de la qualité - Score de confiance et analyse de la qualité des correspondances
- Débogage interactif - Visualisation des correspondances en temps réel
- Sans configuration - Repli sur le mode simulé sans clés d'interface de programmation applicative
Stratégie de correspondance
Cascade à 4 étapes
Le système de correspondance sémantique utilise une approche en cascade, essayant des méthodes de plus en plus sophistiquées :
Étape 1: Correspondance contextuelle (confiance la plus élevée)
↓ (si pas de correspondance)
Étape 2: Correspondance exacte du nom
↓ (si pas de correspondance)
Étape 3: Correspondance par synonymes
↓ (si pas de correspondance)
Étape 4: Recherche par représentation vectorielle sémantique
Chaque étape a différents niveaux de confiance et cas d'utilisation.
Étape 1 : Correspondance contextuelle
Méthode : Combine nom + catégorie pour la correspondance Confiance : 0,95 - 1,0 (très élevée) Cas d'utilisation : Lorsque le nom et le contexte de catégorie correspondent
Algorithme :
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
}
Exemple :
Source: FoodEx2 "Apple" (catégorie: "Fruits")
Cible: Hestia "Apple" (catégorie: "Inputs & Products")
Correspondance: ✅ Contextuelle (confiance: 1,0)
Étape 2 : Correspondance exacte du nom
Méthode : Correspondance exacte de chaîne sur les noms normalisés Confiance : 0,85 - 0,95 (élevée) Cas d'utilisation : Noms identiques entre différentes sources
Normalisation :
- Conversion en minuscules
- Suppression des espaces de début et fin
- Suppression des caractères spéciaux
- Gestion des pluriels (optionnel)
Algorithme :
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, '')
}
Exemple :
Source: "Wheat grain"
Cible: "wheat grain"
Correspondance: ✅ Exacte (confiance: 0,9)
Étape 3 : Correspondance par synonymes
Méthode : Dictionnaire de synonymes intégré Confiance : 0,70 - 0,85 (moyenne-élevée) Cas d'utilisation : Noms alternatifs connus et variations courantes
Dictionnaire de synonymes :
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']
}
Algorithme :
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
}
Exemple :
Source: "Beef"
Cible: "Cattle meat"
Correspondance: ✅ Synonyme (confiance: 0,8, via "cattle meat")
Étape 4 : Recherche par représentation vectorielle sémantique
Méthode : Similarité vectorielle assistée par intelligence artificielle utilisant des représentations vectorielles Confiance : 0,50 - 0,70 (moyenne) Cas d'utilisation : Similarité sémantique lorsque les correspondances exactes échouent
Fournisseurs d'intelligence artificielle :
-
OpenAI (recommandé)
- Modèle :
text-embedding-3-small - Dimensions : 1536
- Économique et précis
- Modèle :
-
Google Generative AI (alternative)
- Modèle :
text-embedding-004 - Dimensions : 768
- Bonne alternative à OpenAI
- Modèle :
-
Mode simulé (repli)
- Représentations vectorielles déterministes basées sur les chaînes
- Aucune clé d'interface de programmation applicative requise
- Adapté aux tests
Algorithme :
async function semanticMatch(
term: Term,
targetTerms: Term[],
provider: 'openai' | 'google'
): Promise<Match | null> {
// Générer la représentation vectorielle pour le terme source
const sourceEmbedding = await generateEmbedding(
`${term.name} ${term.category}`,
provider
)
let bestMatch: Match | null = null
let highestSimilarity = 0
for (const target of targetTerms) {
// Générer la représentation vectorielle pour le terme cible
const targetEmbedding = await generateEmbedding(
`${target.name} ${target.category}`,
provider
)
// Calculer la similarité cosinus
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)
}
Exemple :
Source: "Grass-fed beef cattle"
Cible: "Extensive pasture cattle production"
Similarité de représentation vectorielle: 0,72
Correspondance: ✅ Sémantique (confiance: 0,72)
Intégration des fournisseurs d'intelligence artificielle
Configuration OpenAI
# Définir la clé d'interface de programmation applicative
export OPENAI_API_KEY="sk-..."
# Exécuter la correspondance sémantique
npm run match-glossaries
Fonctionnalités OpenAI :
- Derniers modèles de représentation vectorielle
- Haute précision pour la terminologie alimentaire/Analyse du Cycle de Vie
- Coûts d'interface de programmation applicative raisonnables
- Temps de réponse rapides
Exemple d'appel d'interface de programmation applicative :
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
}
Configuration Google AI
# Définir la clé d'interface de programmation applicative
export GOOGLE_API_KEY="AIza..."
# Exécuter la correspondance sémantique avec Google
npm run match-glossaries
Fonctionnalités Google AI :
- Alternative à OpenAI
- Bon support multilingue
- Tarification compétitive
- Représentations vectorielles fiables
Exemple d'appel d'interface de programmation applicative :
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
}
Mode simulé (sans clés d'interface de programmation applicative)
# Exécuter sans clés d'interface de programmation applicative (représentations vectorielles simulées)
npm run match-glossaries:mock
Fonctionnalités du mode simulé :
- Représentations vectorielles déterministes basées sur les chaînes
- Pas de coûts d'interface de programmation applicative
- Adapté aux tests
- Résultats reproductibles
Algorithme simulé :
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
}
// Normaliser
const magnitude = Math.sqrt(
embedding.reduce((sum, val) => sum + val * val, 0)
)
return embedding.map(val => val / magnitude)
}
Intégration de base de données
Les correspondances sémantiques peuvent être stockées dans PostgreSQL avec pgvector pour une recherche de similarité efficace :
Configuration pgvector
-- Activer l'extension pgvector
CREATE EXTENSION IF NOT EXISTS vector;
-- Créer la table des représentations vectorielles
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()
);
-- Créer un index pour la recherche de similarité
CREATE INDEX ON term_embeddings
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);
-- Trouver des termes similaires en utilisant la distance cosinus
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;
Stockage des représentations vectorielles
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(',')}]`]
)
}
Validation de la qualité
Score de confiance
Chaque correspondance se voit attribuer un score de confiance basé sur la méthode de correspondance :
| Méthode | Plage de confiance | Qualité |
|---|---|---|
| Contextuelle | 0,95 - 1,0 | Excellente |
| Exacte | 0,85 - 0,95 | Très bonne |
| Synonyme | 0,70 - 0,85 | Bonne |
| Sémantique | 0,50 - 0,70 | Acceptable |
Seuils de confiance :
- Confiance élevée (≥ 0,85) : Acceptation automatique
- Confiance moyenne (0,70 - 0,84) : Révision recommandée
- Confiance faible (< 0,70) : Révision manuelle requise
Indicateurs de qualité des correspondances
Bonnes correspondances :
- ✅ Score de confiance élevé (≥ 0,85)
- ✅ Catégories similaires
- ✅ Même domaine (alimentaire, Analyse du Cycle de Vie, emballage)
- ✅ Descriptions cohérentes
Correspondances douteuses :
- ⚠️ Confiance moyenne (0,70 - 0,84)
- ⚠️ Catégories différentes
- ⚠️ Correspondance inter-domaines
- ⚠️ Chevauchement partiel des noms
Correspondances médiocres :
- Confiance faible (< 0,70)
- ❌ Catégories non liées
- ❌ Domaines différents
- ❌ Non-concordance sémantique
Méthodes de validation
Validation automatisée :
function validateMatch(match: Match): ValidationResult {
const issues: string[] = []
// Vérifier le seuil de confiance
if (match.confidence < 0.5) {
issues.push('Confidence below threshold')
}
// Vérifier la cohérence des catégories
if (match.sourceCategory !== match.targetCategory) {
issues.push('Category mismatch')
}
// Vérifier l'alignement des domaines
if (!domainsAlign(match.sourceDomain, match.targetDomain)) {
issues.push('Domain mismatch')
}
return {
valid: issues.length === 0,
confidence: match.confidence,
issues: issues,
recommendation: issues.length === 0 ? 'accept' : 'review'
}
}
Révision manuelle :
- Exporter les correspondances en CSV/Excel
- Réviser les correspondances à faible confiance
- Vérifier les correspondances inter-domaines
- Documenter les décisions de validation
Optimisation des performances
Traitement par lots
Traiter plusieurs termes par lots pour réduire les appels d'interface de programmation applicative :
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()
}
Stratégie de mise en cache
Mettre en cache les représentations vectorielles pour éviter les appels d'interface de programmation applicative redondants :
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))
}
}
Limitation de débit
Respecter les limites de débit des interfaces de programmation applicatives :
import pLimit from 'p-limit'
const limit = pLimit(10) // Max 10 requêtes simultanées
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[]
}
Cas d'utilisation
Correspondance inter-vocabulaires
FoodEx2 vers Hestia :
FoodEx2: A010101 (Blé tendre)
↓ correspondance sémantique
Hestia: term/crop-wheat
↓ fournit
Données d'incidences environnementales
ecoinvent vers Eaternity :
ecoinvent: market for wheat grain | GLO
↓ correspondance sémantique
Eaternity: FlowNode.product_name = "Wheat grain"
↓ permet
Calcul de l'empreinte carbone EOS
Import de données utilisateur
Correspondance d'en-têtes de colonnes CSV :
En-tête utilisateur: "Produktname" (allemand)
↓ correspondance sémantique
Propriété Eaternity: eaternity-property-productname
↓ correspond à
Champ de l'interface de programmation applicative EOS: FlowNode.product_name
Applications de recherche
Analyse du Cycle de Vie multi-sources :
Question de recherche: "Empreinte carbone du bœuf biologique"
↓ correspondance sémantique
FoodEx2: F010101 (Beef) + facette Biologique
Hestia: term/livestock-cattle-organic
ecoinvent: cattle for slaughtering, organic | CH
↓ combine
Analyse du Cycle de Vie complète avec multiples sources de données
Débogage interactif
Fonctionnalités de l'interface web
Le site web du Glossaire ESFC fournit des outils de débogage interactifs :
Visualisation des correspondances :
- Affichage de la qualité des correspondances en temps réel
- Visualisation du score de confiance
- Indicateur de méthode (contextuelle, exacte, synonyme, sémantique)
- Comparaison des termes source/cible
Outils de débogage :
- Explication de la correspondance (pourquoi cette correspondance a été sélectionnée)
- Correspondances alternatives (autres correspondances potentielles)
- Scores de similarité pour les correspondances sémantiques
- Comparaison de catégorie et de domaine
Options d'export :
- Exporter les correspondances en CSV
- Télécharger le graphe de relations
- Générer un rapport de correspondance
- Sauvegarder pour révision manuelle
Exécution de la correspondance sémantique
Ligne de commande
# Correspondance sémantique complète (production)
npm run match-glossaries
# Mode test (données échantillons)
npm run match-glossaries:test
# Mode simulé (sans clés d'interface de programmation applicative)
npm run match-glossaries:mock
# Paires de sources spécifiques
node scripts/glossary-matcher.js \
--source foodex2 \
--target hestia \
--output mappings.json
Configuration
// Configuration de scripts/glossary-matcher.js
const config = {
provider: 'openai', // ou 'google'
verbose: true,
mockMode: false,
confidenceThreshold: 0.5,
maxResults: 10,
batchSize: 100,
cacheFile: './cache/embeddings.json'
}
Formats de sortie
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
}
}
}
Graphe de relations (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"
}
]
}
Bonnes pratiques
Stratégie de correspondance
-
Commencer par les méthodes à haute confiance
- S'appuyer sur les correspondances contextuelles et exactes lorsque possible
- Utiliser la recherche sémantique comme repli
- Valider manuellement les correspondances à faible confiance
-
Correspondance spécifique au domaine
- Faire correspondre les termes alimentaires aux sources alimentaires (FoodEx2, Hestia)
- Faire correspondre les processus d'Analyse du Cycle de Vie à ecoinvent
- Faire correspondre les propriétés au schéma Eaternity
-
Qualité plutôt que quantité
- Préférer moins de correspondances de haute qualité
- Réviser et valider les correspondances douteuses
- Documenter les décisions de correspondance
Optimisation des performances
-
Traitement par lots
- Traiter les termes par lots
- Utiliser des requêtes simultanées (avec limites)
- Mettre en cache les représentations vectorielles
-
Mises à jour incrémentales
- Ne re-correspondre que les termes modifiés
- Maintenir l'historique des correspondances
- Suivre le statut de validation
-
Gestion des ressources
- Surveiller l'utilisation et les coûts de l'interface de programmation applicative
- Utiliser le mode simulé pour le développement
- Mettre en cache les représentations vectorielles localement
Documentation associée
- Sources de données - Vue d'ensemble des 10 sources
- Schéma Eaternity - Correspondance des propriétés
- Formats de données - Export des données de relations
- Référence FoodEx2 - Correspondance de classification alimentaire
- Référence Hestia - Correspondance des données d'Analyse du Cycle de Vie