01
📊 Contexte et enjeux
Les données produits sont le cœur de l'entreprise moderne. Pourtant, elles sont souvent éparpillées entre ERP, PIM, CMS, Excel, fournisseurs, canaux de vente. Résultat : incohérences, doublons, mauvaise qualité, et une expérience client dégradée.
30%
des données produits sont erronées
8+
sources différentes par produit
20%
de chiffre d'affaires perdu par mauvaise qualité
50%
du temps en nettoyage de données
💡 L'opportunité : Un graphe de connaissances unifie toutes les sources en une seule vue cohérente, avec des relations sémantiques entre produits, fournisseurs, catégories, attributs.
02
❌ Le défi : données produits en silos
🏭 ERP
Prix, stock, fournisseurs
📦 PIM
Descriptions, attributs, médias
🌐 CMS
Contenu web, SEO, landing pages
📊 Excel
Données marketing, promotions
🏷️ GDSN
Données fournisseurs externes
🛒 Marketplace
Amazon, Cdiscount, eBay
⚠️ Problèmes concrets :
- Le même produit a des noms différents selon les canaux ("iPhone 13" vs "Apple iPhone 13 128GB")
- Les attributs techniques sont incohérents (cm vs pouces, kg vs livres)
- Les relations produits (compatibilité, accessoires, substituts) sont implicites
- Les mises à jour produit prennent des jours (changer un prix dans 8 systèmes)
- Impossible de répondre à "quels produits sont compatibles avec X ?"
03
🧠 Solution : PIM sémantique sur graphe
🏗️ Architecture du PIM sémantique :
┌─────────────────────────────────────────────────────────┐
│ SOURCES (hétérogènes) │
│ ERP │ PIM legacy │ Excel │ Fournisseurs │ API externes │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ COUCHE D'INTÉGRATION │
│ Mapping │ Transformation │ Déduplication │ Enrichissement │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ GRAPHE DE CONNAISSANCES PRODUITS │
│ Ontologie produit │ Relations │ Inférences │ Traçabilité │
└─────────────────────────────────────────────────────────┘
│
┌──────────┬──────────┼──────────┬──────────┐
▼ ▼ ▼ ▼ ▼
Site web App mobile Marketplaces API Dashboard
Ontologie produit universelle
@prefix : <http://product.example.org/ontology#> .
@prefix schema: <https://schema.org/> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
# Classes principales
:Produit a owl:Class ;
rdfs:subClassOf schema:Product .
:Catégorie a owl:Class ;
rdfs:subClassOf skos:Concept .
:Attribut a owl:Class .
:ValeurAttribut a owl:Class .
:Fournisseur a owl:Class .
:Marque a owl:Class .
:Accessoire a owl:Class ; rdfs:subClassOf :Produit .
# Relations
:appartientÀCatégorie a owl:ObjectProperty ;
rdfs:domain :Produit ;
rdfs:range :Catégorie .
:aPourAttribut a owl:ObjectProperty ;
rdfs:domain :Produit ;
rdfs:range :Attribut .
:estCompatibleAvec a owl:ObjectProperty ;
rdfs:domain :Produit ;
rdfs:range :Produit ;
owl:symmetric true .
:estSubstitutDe a owl:ObjectProperty ;
rdfs:domain :Produit ;
rdfs:range :Produit .
:estAccessoireDe a owl:ObjectProperty ;
rdfs:domain :Accessoire ;
rdfs:range :Produit .
:estFourniPar a owl:ObjectProperty ;
rdfs:domain :Produit ;
rdfs:range :Fournisseur .
# Règle : Compatibilité transitive
[ (:estCompatibleAvec ?a ?b), (:estCompatibleAvec ?b ?c) -> (:estCompatibleAvec ?a ?c) ]
# Règle : Si produit compatible, ses accessoires le sont aussi
[ (:estAccessoireDe ?a ?p), (:estCompatibleAvec ?p ?q) -> (:estCompatibleAvec ?a ?q) ]
04
⚙️ Architecture technique
Pipeline d'intégration multi-sources
class ProductKnowledgeGraph:
def __init__(self, kg, llm, embedding_model):
self.kg = kg
self.llm = llm
self.embedder = embedding_model
def integrate_product(self, source_data, source_type):
"""Intègre un produit depuis n'importe quelle source"""
# 1. Normalisation et nettoyage
normalized = self.normalize(source_data, source_type)
# 2. Recherche de correspondance (déduplication)
existing = self.find_matching_product(normalized)
if existing:
# Fusion avec données existantes
product_id = existing['id']
self.merge_product(product_id, normalized)
else:
# Création nouveau produit
product_id = self.create_product(normalized)
# 3. Enrichissement automatique
self.enrich_product(product_id)
# 4. Détection des relations
self.discover_relations(product_id)
return product_id
def normalize(self, data, source_type):
"""Normalisation selon source"""
mapping = {
'erp': self.map_erp_to_ontology,
'pim': self.map_pim_to_ontology,
'excel': self.map_excel_to_ontology,
'supplier': self.map_supplier_to_ontology
}
return mapping[source_type](data)
def find_matching_product(self, product):
"""Détection de doublons par similarité sémantique + règles"""
# Recherche par identifiant unique (EAN, SKU)
if product.get('ean'):
existing = self.kg.query(f"""
SELECT ?p WHERE {{
?p :aPourEAN "{product['ean']}" .
}}
""")
if existing:
return existing[0]
# Recherche par similarité du nom
product_embedding = self.embedder.encode(product['name'])
candidates = self.vector_db.similarity_search(product_embedding, k=5)
for candidate in candidates:
score = self.calculate_match_score(product, candidate)
if score > 0.85:
return candidate
return None
def enrich_product(self, product_id):
"""Enrichissement via LLM et sources externes"""
product = self.kg.get_product(product_id)
# Génération de description SEO
seo_desc = self.llm.generate(f"""
Génère une description SEO pour ce produit (150-160 caractères):
Nom: {product['name']}
Catégorie: {product['category']}
Attributs: {product['attributes']}
""")
# Classification automatique dans catégories
categories = self.llm.classify(product['name'], self.kg.get_categories())
# Mise à jour du graphe
self.kg.insert(f"""
:{product_id} :aPourDescriptionSEO "{seo_desc}" ;
:appartientÀCatégorie :{categories[0]} .
""")
def discover_relations(self, product_id):
"""Détection automatique des relations produits"""
product = self.kg.get_product(product_id)
# Compatibilité technique (via attributs)
compatible = self.kg.query(f"""
SELECT ?other WHERE {{
?other a :Produit .
?other :aPourAttribut ?attr .
FILTER(?attr IN ({product['technical_attrs']}))
FILTER(?other != :{product_id})
}}
""")
for comp in compatible:
self.kg.insert(f":{product_id} :estCompatibleAvec :{comp['id']}")
# Accessoires suggérés
accessories = self.llm.suggest_accessories(product['name'], product['category'])
for acc in accessories:
self.kg.insert(f":{acc} :estAccessoireDe :{product_id}")
05
🎯 Cas d'usage concrets
🔍 Scénario 1 : Unification cross-canal
Problème : Le même produit a des prix différents sur site web, app mobile, et marketplaces.
Solution : Le graphe centralise la référence produit unique. Une mise à jour de prix se propage à tous les canaux en temps réel.
Résultat : Fin des incohérences, +15% de confiance client.
🔧 Scénario 2 : Compatibilité produits
Problème : "Quels câbles sont compatibles avec mon téléviseur ?"
Solution : Le graphe navigue les relations de compatibilité (connectique, puissance, version).
Résultat : Recommandation précise en millisecondes, +25% de panier moyen.
🏷️ Scénario 3 : Enrichissement automatique
Problème : 50 000 produits avec descriptions incomplètes.
Solution : LLM + graphe génèrent descriptions SEO, attributs manquants, catégories.
Résultat : 100% des produits enrichis en 2 jours (vs 6 mois manuellement).
📊 Scénario 4 : Analyse de gamme
Problème : "Quels produits sont en doublon avec les fournisseurs ?"
Solution : Requête SPARQL détecte les produits identiques de fournisseurs différents.
Résultat : Optimisation du sourcing, -12% de coût d'achat.
🔄 Scénario 5 : Gestion de cycle de vie
Problème : "Quels produits sont remplacés par quelles nouvelles références ?"
Solution : Propriété :remplacéPar dans le graphe.
Résultat : Site web suggère automatiquement les nouveaux produits, stock épuisé redirigé.
07
💬 Témoignage client
🎤 Boulanger - Directrice des Données Produits
"Nous avions 15 sources de données produits différentes, avec des incohérences massives. Le graphe de connaissances a unifié le tout en 6 mois. Aujourd'hui, un changement de prix se propage en 5 secondes sur tous nos canaux. Et nos clients bénéficient de recommandations compatibilité ultra-précises."