Grafo del Parlamento italiano: perché Camera e Senato non parlano la stessa lingua

17/06/20266 min read
Grafo del Parlamento italiano: perché Camera e Senato non parlano la stessa lingua

Risposta diretta: Camera dei Deputati e Senato della Repubblica pubblicano i loro dati come Linked Open Data, ma usano due ontologie diverse e solo parzialmente allineate — OCD per la Camera, OSR per il Senato. Lo stesso concetto (il cognome di un parlamentare, la legislatura, l'inizio di un mandato, un atto legislativo) è modellato con proprietà, formati e perfino namespace differenti. Per costruire un grafo unico e interrogabile da un agente AI non basta «unire i dati»: servono due query builder separati e un layer di normalizzazione. Qui spieghiamo i problemi concreti che abbiamo trovato mappando le relazioni, con esempi di codice.

TL;DR

  • Cognome: la Camera usa foaf:surname, il Senato foaf:lastName. Stesso dato, proprietà diversa.
  • Legislatura: la Camera la esprime come URI completo, il Senato come numero intero. Una query che funziona su un endpoint fallisce sull'altro.
  • Date di mandato: ocd:startDate/ocd:endDate (Camera) contro osr:inizio/osr:fine (Senato).
  • Gruppi parlamentari: il Senato riusa le classi della Camera (ocd:gruppoParlamentare) ma con proprietà OSR. Un ibrido che confonde.
  • Atti: ocd:atto (Camera) contro osr:Ddl (Senato) — classi e namespace diversi.
  • Documentazione: l'ontologia del Senato non ha una documentazione ufficiale completa: l'abbiamo ricostruita per reverse engineering dalle query d'esempio.
  • Conclusione: le due ontologie sono coordinate ma non identiche. Servono query builder separati per istituzione.

Perché conta: il grafo è solo buono quanto le sue relazioni

Stiamo costruendo Open·Parlamento, un agente che risponde su legge e dati pubblici citando sempre la fonte. Il cuore è un knowledge graph: nodi (parlamentari, atti, gruppi, votazioni) e relazioni tipizzate tra loro (presenta, aderisce, vota, modifica). Un agente AI può dare risposte affidabili solo se quelle relazioni sono pulite e coerenti.

Il problema è che, prima ancora di entrare nel grafo, i dati arrivano da due sorgenti SPARQL che modellano la realtà in modo diverso. Tutto è nato da RepublicMCP, il connettore open source che espone Camera e Senato come strumenti agentici: mappando le due ontologie sono emerse le incompatibilità che descriviamo qui.

Qual è la differenza tra OCD e OSR?

OCD (Ontologia Camera dei Deputati) e OSR (Ontologia Senato della Repubblica) sono i due vocabolari RDF con cui le due Camere pubblicano i propri dati. Condividono l'impostazione generale (FOAF per le persone, classi per mandati, gruppi, atti) ma divergono nei dettagli che contano per chi scrive query.

Concetto Camera (OCD) Senato (OSR) Compatibile?
Cognome foaf:surname foaf:lastName
Legislatura URI (…/repubblica_19) intero (19)
Inizio mandato ocd:startDate osr:inizio
Fine mandato ocd:endDate osr:fine
Relazione mandato ocd:rif_mandatoCamera osr:mandato
Atto legislativo ocd:atto osr:Ddl
Gruppo parlamentare ocd:gruppoParlamentare ocd:gruppoParlamentare (riuso) ⚠️ ibrido

Il caso più insidioso: la legislatura

Sembra un dettaglio, ma rompe le query. La Camera vuole l'URI completo della legislatura; il Senato un numero intero.

# Camera — serve l'URI completo
?mandato ocd:rif_leg <http://dati.camera.it/ocd/legislatura.rdf/repubblica_19> .

# Senato — basta il numero
?mandato osr:legislatura 19 .

Alla Camera il formato breve non funziona: ?mandato ocd:rif_leg 19 non restituisce nulla. È il tipo di incompatibilità silenziosa che non solleva errori — semplicemente ti dà zero risultati, ed è difficile da diagnosticare.

Le date: stesso significato, proprietà e formato diversi

Oltre ai nomi diversi (startDate/endDate vs inizio/fine), la Camera codifica le date come interi in formato YYYYMMDD:

# Camera: confronto come intero, NON come stringa
FILTER(xsd:integer(?data) >= 20240101)

E per trovare i parlamentari in carica servono due pattern SPARQL opposti:

# Camera: esclude chi ha una data di fine
MINUS { ?mandato ocd:endDate ?fine }

# Senato: filtra dove la fine non è valorizzata
OPTIONAL { ?mandato osr:fine ?fine }
FILTER(!bound(?fine))

L'ibrido dei gruppi parlamentari

Il dettaglio più sorprendente: per i gruppi parlamentari il Senato riusa le classi della Camera (ocd:gruppoParlamentare, ocd:adesioneGruppo) — ma le popola con proprietà OSR (osr:gruppo, osr:inizio, osr:fine).

PREFIX osr: <http://dati.senato.it/osr/>
PREFIX ocd: <http://dati.camera.it/ocd/>

?senatore ocd:aderisce ?adesione .       # classe Camera
?adesione osr:gruppo ?gruppo ;           # proprietà Senato!
          osr:inizio ?inizio .           # proprietà Senato!
?gruppo a ocd:gruppoParlamentare .       # di nuovo classe Camera

Lo stesso vale per i mandati: le classi ocd:mandatoCamera e ocd:mandatoSenato vivono entrambe nel namespace della Camera, anche quella del Senato. Senza una mappa esplicita di queste eccezioni, qualsiasi tentativo di scrivere una query «generica» fallisce.

E la documentazione?

Per la Camera esiste una documentazione di ontologia ragionevolmente completa. Per il Senato no: l'OSR non ha una documentazione ufficiale esplicita paragonabile. Abbiamo dovuto ricostruire il modello per reverse engineering, partendo dalle query d'esempio ufficiali e verificando empiricamente quali proprietà esistono. Alcune entità (interventi, documenti) restano parzialmente documentate.

Come si risolve: normalizzare, non «unire»

La lezione è netta: le due ontologie sono coordinate ma non identiche, quindi non puoi trattarle con lo stesso codice. La strategia che funziona:

  1. Query builder separati per istituzione. Ogni Camera ha il suo modulo che conosce i suoi nomi di proprietà, formati e pattern.
  2. Configurazione centralizzata delle differenze. Cognome, legislatura, date e operatori «in carica» vivono in una mappa per-istituzione, non sparsi nel codice.
  3. Layer di normalizzazione verso il grafo. Prima di entrare nel knowledge graph, i dati vengono mappati su un modello unico con relazioni tipizzate e provenienza — così l'agente AI interroga un grafo coerente, non due dialetti SPARQL.

È esattamente ciò che fa Open·Parlamento: trasformare fonti che, da sole, non sono interrogabili in modo affidabile in un grafo unico, citando sempre l'originale.

FAQ

Cos'è un'ontologia nei dati pubblici?

È un vocabolario formale (in RDF) che definisce le entità di un dominio e le relazioni tra loro: per il Parlamento, classi come «parlamentare», «mandato», «gruppo», «atto» e proprietà come «aderisce a» o «presenta». Permette di pubblicare dati interrogabili via SPARQL invece che in semplici tabelle.

Perché Camera e Senato non hanno un'ontologia unica?

Sono istituzioni autonome che hanno digitalizzato i propri dati in tempi e modi diversi. Il risultato sono due ontologie (OCD e OSR) che si ispirano a standard comuni (FOAF) e in parte si riusano a vicenda, ma divergono nei dettagli pratici di proprietà, formati e namespace.

Si possono comunque unire in un unico grafo?

Sì, ma serve un layer di normalizzazione: query builder separati per leggere ciascuna fonte e una mappatura verso un modello unico prima di scrivere nel knowledge graph. È quello che abbiamo costruito per Open·Parlamento.


Costruiamo agenti AI che rispondono sui dati reali — citando la fonte, non inventandola. Vedi come funziona Open·Parlamento e i progetti open source, oppure parla con noi del tuo knowledge graph.

Knowledge GraphOpen DataAISPARQL

Scritto da Giulio Garofalo