µJena - poseidon.ws.dei.polimi.it

Transcript

µJena - poseidon.ws.dei.polimi.it
Politecnico di Milano
Facoltà di Ingegneria dell’Informazione
Corso di Laurea in Ingegneria Informatica
Dipartimento di Elettronica e Informazione
µJena :
Gestione di ontologie sui dispositivi mobili
Relatore: Prof. Letizia Tanca
Correlatore: Ing. Giorgio Orsi
Correlatore: Ing. Carlo Curino
Tesi di Laurea di: Fulvio CRIVELLARO matr. 670607
Gabriele GENOVESE matr. 663199
Anno Accademico 2006-2007
Ringraziamenti
Si ringraziano la Prof. Letizia Tanca e l’Ing. Giorgio Orsi per l’aiuto e la
disponibilità, l’Ing. Carlo Curino per le sempre utili e tempestive indicazioni
da oltre oceano, e l’Ing. Mario Arrigoni per il supporto teorico.
Milano, 3 Marzo 2008
iii
INDICE
Indice
1 Introduzione
1.1
1
Organizzazione dei contenuti . . . . . . . . . . . . . . . . . . . .
2
1.1.1
Prerequisiti . . . . . . . . . . . . . . . . . . . . . . . . .
2
1.1.2
Scelte progettuali e architettura . . . . . . . . . . . . . .
3
1.1.3
Analisi e conclusioni . . . . . . . . . . . . . . . . . . . .
3
1.1.4
Appendici . . . . . . . . . . . . . . . . . . . . . . . . . .
3
2 Introduzione al Web Semantico
5
2.1
Il Web Semantico . . . . . . . . . . . . . . . . . . . . . . . . . .
5
2.2
OWL (Web Ontology Language) . . . . . . . . . . . . . . . . . .
7
2.3
Il Reasoning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.4
SPARQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3 Jena
15
3.1
Cos’ è Jena . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.2
ARQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.3
Livello di sviluppo di Jena . . . . . . . . . . . . . . . . . . . . . 16
3.4
Perché Jena . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
4 J2ME
19
4.1
Evoluzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.2
Organizzazione della J2ME . . . . . . . . . . . . . . . . . . . . . 20
4.3
4.2.1
La configurazione CLDC . . . . . . . . . . . . . . . . . . 21
4.2.2
La configurazione MIDP . . . . . . . . . . . . . . . . . . 22
4.2.3
Package opzionali . . . . . . . . . . . . . . . . . . . . . . 23
La J2ME oggi: l’MSA . . . . . . . . . . . . . . . . . . . . . . . 24
5 Obiettivi e scelte progettuali
27
v
INDICE
6 Architettura del software
6.1
Organizzazione generale . . . . . . . . . . . . . . . . . . . . . . 31
6.2
Le classi Factory . . . . . . . . . . . . . . . . . . . . . . . . . . 32
6.3
Integrazioni alla J2ME . . . . . . . . . . . . . . . . . . . . . . . 33
6.4
Il livello Grafo-Tripla . . . . . . . . . . . . . . . . . . . . . . . . 34
6.5
6.6
6.7
6.4.1
Il Nodo . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6.4.2
La Tripla . . . . . . . . . . . . . . . . . . . . . . . . . . 37
6.4.3
Gli Assiomi . . . . . . . . . . . . . . . . . . . . . . . . . 37
6.4.4
Il Grafo . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
6.4.5
Principali differenze con Jena del motore di archiviazione 39
Il Reificatore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
6.5.1
Rappresentazione in memoria della tripla reificata . . . . 41
6.5.2
Le modalità di utilizzo . . . . . . . . . . . . . . . . . . . 41
6.5.3
Flusso dei dati . . . . . . . . . . . . . . . . . . . . . . . 43
6.5.4
Principali differenze con Jena del reificatore . . . . . . . 45
Il livello RDF . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
6.6.1
Il package Enhanched . . . . . . . . . . . . . . . . . . . . 45
6.6.2
Le entità . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
6.6.3
Gli Statement . . . . . . . . . . . . . . . . . . . . . . . . 47
6.6.4
L’astrazione introdotta da RDF . . . . . . . . . . . . . . 48
6.6.5
L’assenza di una struttura dati . . . . . . . . . . . . . . 50
6.6.6
Principali differenze con Jena del livello RDF . . . . . . 51
Il livello OWL . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
6.7.1
La OntResource . . . . . . . . . . . . . . . . . . . . . . . 53
6.7.2
La OntClass . . . . . . . . . . . . . . . . . . . . . . . . . 55
6.7.3
Le OntProperty . . . . . . . . . . . . . . . . . . . . . . . 58
6.7.4
Le relazione tra Risorse . . . . . . . . . . . . . . . . . . . 58
6.7.5
Principali differenze con Jena del livello OWL . . . . . . 59
7 Analisi delle prestazioni
61
7.1
Confronto diretto con Jena . . . . . . . . . . . . . . . . . . . . . 62
7.2
Tempi di elaborazione su telefono cellulare . . . . . . . . . . . . 63
7.3
Interpretazione dei risultati . . . . . . . . . . . . . . . . . . . . 65
8 Conclusioni
vi
31
67
INDICE
Appendici
69
A Indicazioni per gli sviluppatori
71
A.1 Evoluzione delle prestazioni . . . . . . . . . . . . . . . . . . . . 71
A.2 Possibili aggiunte e migliorie . . . . . . . . . . . . . . . . . . . . 73
B Manuale utente
75
B.1 Requisiti minimi . . . . . . . . . . . . . . . . . . . . . . . . . . 75
B.2 Installazione e configurazione . . . . . . . . . . . . . . . . . . . 76
B.3 Creare un’ontologia . . . . . . . . . . . . . . . . . . . . . . . . . 77
B.4 Input e output
. . . . . . . . . . . . . . . . . . . . . . . . . . . 82
C Rappresentazione delle ontologie OWL
C.1 N-TRIPLE
83
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
C.2 Versione grafica . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
C.3 Forma XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
D Licenza
89
Bibliografia
90
Bibliografia
91
vii
Capitolo 1
Introduzione
L’obiettivo del progetto è la realizzazione di una libreria software che implementi un framework per la gestione di modelli di conoscenza in linguaggio
OWL basato su piattaforma portatile.
L’innovazione introdotta dal framework µJena è la piattaforma di destinazione, ovvero la categoria di supporti hardware per i quali l’intero progetto è
stato sviluppato; si tratta di un ambiente che fino ad ora nessuna libreria simile,
e comunque nessun software per la gestione di ontologie, andava a coprire: i
dispositivi portatili. Al momento dello sviluppo e del rilascio µJena è unica nel
suo genere, in quanto non esiste una realtà alternativa nell’ambiente software
del web semantico.
Le principali caratteristiche curate nello sviluppo di µJena sono l’elaborazione del codice in favore di una piattaforma dalle potenzialità ridotte rispetto
ai personal computer; nello specifico, i limiti principali dei supporti mobili
sono le capacità di elaborazione e di archiviazione, oltre alla disponibilità di
energia, nella maggior parte dei casi vincolata all’alimentazione a batteria dei
dispositivi.
Il contesto all’interno del quale sono nati sia l’idea di sviluppare una libreria
con tali caratteristiche, sia il lavoro che ha portato all’implementazione della
stessa, è il progetto nato e sviluppato dal Dipartimento di Elettronica e Informazione del Politecnico di Milano che passa sotto il nome di Context-ADDICT
(http://context-addict.elet.polimi.it/Context-ADDICT.html). Il progetto ha
l’obiettivo di mettere a disposizione degli utenti di dispositivi portatili, quali per esempio telefoni cellulari o PDA, varie informazioni, in particolare nate
dall’unione e condivisione di dati provenienti da pi fonti, allineate e opportuna1
microJena
mente combinate a formare la vera e propria conoscenza richiesta dall’utente;
un apporto fondamentale nel portare a termine il processo di merge è dato
dall’ontologia di riferimento, che dà un significato formale alle informazioni,
rendendole interpretabili da software e di conseguenza gestibili.
Il ruolo di µJena in questo ambito è quello di permettere all’ambiente server di limitare il lavoro da svolgere sui dati, in quanto grazie alle capacità di
elaborazione introdotte nei supporti portatili questi ultimi sono ora in grado
di ricevere meta-informazioni, e di svolgere al proprio interno parte dell’elaborazione necessaria, specialmente l’ultimo passaggio, quello della presentazione
dei dati.
1.1
Organizzazione dei contenuti
La presente tesi è organizzata come segue: vengono anzitutto descritte le particolari tecnologie utilizzate, si passa poi all’analisi del lavoro vero e proprio,
concludendo con le considerazioni sull’operato.
1.1.1
Prerequisiti
Questa prima sezione analizza dettagliatamente le tecnologie e le risorse utilizzate, oltre alle basi teoriche che sono state necessarie per affrontare la creazione del software µJena e di cui è bene essere a conoscenza per una corretta
comprensione del testo.
• nel capitolo 2 è descritto il contesto del Web Semantico, degli obiettivi
che si propone di realizzare nell’evoluzione del web stesso e dei linguaggi
che lo descrivono, con particolare attenzione alla sintassi OWL.
• nel capitolo 3 vengono descritti il software Jena, sviluppato da HP, la
sua diffusione e i motivi che hanno portato a sceglierlo come modello di
sviluppo.
• nel capitolo 4 si affronta la piattaforma di sviluppo e di esecuzione Java
Micro Edition per la quale µJena è stata studiata e implementata.
2
1.1 microJena
1.1.2
Scelte progettuali e architettura
Una volta delineato il contesto generale all’interno del quale si opera, si passa
ad una descrizione più approfondita della libreria, questa volta affrontando nel
dettaglio le scelte progettuali vincolate dalla piattaforma di sviluppo e dettate
dalle precedenti scelte operate; segue una rigorosa presentazione delle diverse
fasi di implementazione svolte.
• nel capitolo 5 vengono illustrate nel dettaglio le scelte specifiche di cui
sopra.
• il capitolo 6 è il cuore dell’elaborato; descrive in modo dettagliato l’architettura realizzata, le modalità di gestione dei dati e le principali differenze
con Jena.
1.1.3
Analisi e conclusioni
Viene presentata la valutazione del software, sia in chiave assoluta che
relativamente agli obiettivi prefissi e alle previsioni.
• nel capitolo 7 si trattano le prestazioni assolute, analizzando sia i tempi
di elaborazione che le risorse necessarie, con una particolare attenzione
alla memoria; segue un confronto diretto con la libreria Jena
• nel capitolo 8 si esaminano i risultati ottenuti in relazione agli obiettivi prefissi e si valuta l’effettiva attitudine del codice all’utilizzo sui
dispositivi portatili.
1.1.4
Appendici
• Manuale utente con istruzioni per l’uso e un tutorial guidato
• Indicazioni per futuri miglioramenti e aggiunte
• Licenza del software
• Diverse tipologie possibili di rappresentazione per la medesima ontologia.
3
Capitolo 2
Introduzione al Web Semantico
2.1
Il Web Semantico
Per WebSemantico si intende l’evoluzione e la trasformazione dell’attuale agglomerato di documenti presenti nella rete (il web) in un ambiente dove le
pagine e i documenti, posti al suo interno, siano associati ad informazioni che
ne esplicitino il proprio contenuto. Il concetto fondamentale che circonda il
Web Semantico è di dare un significato ai dati in modo tale da trasformare il
contenuto delle pagine web in oggetti computer readable, allegando all’interfaccia utente delle informazioni codificate per mezzo di una sintassi condivisa;
il presupposto è dare un senso intrinseco alle pagine e ai collegamenti tra di
esse oltrepassando il semplice collegamento ipertestuale (hyper-link), il solo
usato oggi.
Le informazioni a supporto dei contenuti, ovvero la parte destinata all’elaborazione automatica, vengono chiamate meta-dati e, secondo ciò che è stato
deciso dal W3C, l’ente che gestisce e regolamenta le forme e le tecnologie per il
web, è codificata con il meta-linguaggio XML. Oltre che essere uno strumento
perfetto per descrivere la semantica dei documenti attraverso la sua struttura
a tag, XML è un linguaggio che ben si adatta alle interrogazioni e alle interpretazioni automatiche, cosı̀ come allo scambio dati tra sistemi eterogenei:
conseguenza diretta è che il suo utilizzo standardizzato è la via ideale per
attuare l’evoluzione del WebSemantico.
Per assegnare un significato ai dati o alle pagine si deve necessariamente incontrare il problema di stabilire un rapporto tra linguaggio e realtà. Il
5
microJena
medesimo problema è stato studiato nell’antichità e, secondo la tradizione
moderna, la soluzione è da attribuirsi ad un pensiero di Aristotele: il ponte
tra il linguaggio e la realtà è definito dal concetto. La rappresentazione storica
è il Triangolo Aristotelico (vedi figura 2.1).
Figura 2.1: Triangolo Aristotelico
In poche parole nella realtà si utilizza il vocabolo sedia per definire il
termine sedia (si può utilizzare qualunque altro sinonimo purché indirizzino
entrambi alla stessa idea), ma concettualmente, per raggiungere l’insieme di
tutte le sedie, o una sedia specifica (estensione del termine sedia) la mente
sfrutta il concetto di sedia (intensione del termine sedia) che fa da tramite
tra il lessico e la realtà. Queste tre sono entità separate tra di loro e, per
una corretta attribuzione del significato alle pagine, bisogna tenere conto delle
differenze tra di esse come vedremo più avanti. Sempre il W3C ha proposto
l’utilizzo di alcuni linguaggi basati su XML (OWL, RDFS, ...) per lo sviluppo
del WebSemantico.
Una fase cardine per il WebSemantico è la creazione di una base di conoscenza, ovvero un insieme di elementi e delle relazioni che sussistono tra di essi.
Concretamente per poter creare una base di conoscenza si è deciso di utilizzare
come strumento descrittivo un linguaggio ispirato alla logica predicativa e quindi che, alla base, fosse formato dall’elemento fondamentale statement, composto da tre parti: il soggetto, il predicato e l’oggetto. La forma appena descritta
mette in relazione i tre elementi che vengono definiti univocamente grazie ad
un URI (Uniform Resource Identifier). Un esempio può facilitare la comprensione: volendo esprimere il concetto Antonio studia Ingegneria Civile si
potranno creare gli elementi soggetto <Antonio> , predicato <studia> e oggetto
<Ingegneria Civile>; lo statement appena creato si può rappresentare come
<Antonio studia Ingegneria Civile>. Questo non è molto specifico poiché
<Antonio>, per esempio, non è univocamente definito, ma potrebbe indicare
un Antonio qualsiasi; a questo punto grazie all’utilizzo dell’ URI si potrebbe
6
2.2 microJena
definire Antonio con la stringa http://anagrafe.it/Antonio Monti ANTMNT.it
Studia come http://www.vocabolarioitaliano.it/ studiare.it, Ingegneria Civile
come http://www.polimi.it/ing civile.it e il nostro statement risultante
<http://anagrafe.it/Monti Antonio MNTAAN.it
@http://www.vocabolarioitaliano.it/studiare.it
http://www.polimi.it/ing civile.it>.
descrive univocamente il concetto precedente, senza lasciare più spazio ad alcun
dubbio o interpretazione.
Il primo linguaggio che ha assunto questa concezione descrittiva è RDF.
RDF è stato sviluppato in varie forme: esiste una versione grafica nella quale
le risorse sono contraddistinte da ellissi con il relativo stringa URI associato,
collegate tra loro con degli archi che definiscono i rapporti tra di esse; un’altra
versione è la N-TRIPLE che sostanzialmente utilizza lo schema a tre elementi
come è stato descritto precedentemente; per ultimo invece il modello di RDF
più utilizzato, ovvero quello scritto sottostando alle regole del XML, che, proprio per questa caratteristica, è il più diffuso nell’ambiente del WebSemantico
ed è chiamato RDFS (vedi appendice D).
2.2
OWL (Web Ontology Language)
OWL nasce dalla necessità di migliorare l’espressività dei linguaggi per il WebSemantico e di renderli computabili meccanicamente; per fare ciò OWL si è
basato, in linea generale, su una DL (Logica Descrittiva) definita SHOIN(Dn)
sigla il cui significato sarà affrontato più avanti nel capitolo e ha assunto
questa potenza descrittiva grazie ai propri costrutti. Attualmente OWL esiste
in tre forme distinte :
1. OWL full: comprende tutta l’espressività di RDF e di conseguenza non
risulta decidibile, in quanto non rimane nella logica del primo ordine
(vedi 2.3).
2. OWL DL: è lo standard al quale si fa più riferimento poiché è decidibile e ha un’ampia espressività, sfrutta, per quanto possibile, il potere
espressivo della DL SHOIN(Dn).
7
microJena
3. OWL Lite: rende possibili solo alcuni vincoli relazionali, semplice ed
intuitivo, ma poco potente e descrittivo.
L’elemento cardine sul quale si basa la conoscenza in OWL è l’ontologia; questa
si può definire come una struttura, normalmente gerarchica, dove si definiscono
l’esistenza e le relazioni che intercorrono tra i vari elementi di un dominio.
OWL aggiunge vari costrutti, ma eredita inoltre tutti quelli presenti in
RDF: in questo modo è possibile descrivere un’ontologia OWL anche con elementi esclusivamente appartenenti ad RDF; questa pratica rende compatibili le
applicazioni che prevedono l’utilizzo di entrambi, però tutto ciò va a discapito
della leggibilità poiché l’ampia espressività di OWL ridotta ai costrutti RDF
porta ad una difficile comprensione per il lettore umano.
Per poter descrivere una classe in OWL si possono utilizzare i seguenti
costrutti:
• owl:class definisce l’elemento classe
• owl:oneOf definisce una classe come l’enumerazione di più elementi
(Individui)
• owl:intersectionOf definisce una classe come intersezione di più classi
• owl:complementOf definisce una classe come il complemento di un’altra
classe
• owl:unionOf definisce una classe come l’unione (in senso logico) di più
classi
• restrizioni: vincoli sulle proprietà dove le classi sono codominio
– owl:hasValue definisce la classe come l’insieme degli elementi che
hanno un determinato valore sulla proprietà
– owl:someValuesFrom definisce la classe come l’insieme degli elementi
che hanno almeno un dato valore sulla proprietà
– owl:allValuesFrom definisce la classe come l’insieme degli elementi
che hanno tutti il dato valore sulla proprietà
– owl:hasCardinality definisce la classe come l’insieme degli elementi
che ha una cardinalità data su una proprietà
8
2.2 microJena
– owl:maxCardinality definisce la classe come l’insieme degli elementi
che hanno al massimo la cardinalità data sulla proprietà
– owl:minCardinality definisce la classe come l’insieme degli elementi
che hanno al minimo la cardinalità data sulla proprietà.
Oltre a descrivere la classe si possono anche definire determinati rapporti tra
di esse con i costrutti:
• rdfs:subClassOf definisce la struttura gerarchica tra le due classi(già
esistente in RDFS)
• owl:equivalentOf definisce l’equivalenza tra le due classi
• owl:disjointWith definisce la disgiunzione (logica) tra le classi
Gli elementi che formano una classe sono detti Individui (vedi triangolo aristotelico) e vengono definiti secondo il costrutto RDF:type derivato da RDF.
Altri costrutti sempre sugli individui sono:
• owl:sameAs che definisce l’uguaglianza tra due individui
• owl:differentFrom che definisce la disuguaglianza tra due individui
• owl:allDifferent che definisce la disuguaglianza tra un insieme di elementi
Per aggiungere descrittività alle classi di OWL vengono definite inoltre le
proprietà (costrutto rdf:property), suddivise in tre tipi: le proprietà definite
oggetto (owl:objectProperty), di tipo (owl:datatypeProperty) e di annotazione
(owl:annotationProperty). Le proprietà oggetto sono quelle che definiscono una
relazione tra le varie risorse presenti in OWL (per esempio la proprietà HaPartito può essere la proprietà che lega la classe Onorevole con la classe Partito),
in modo tale che il dominio e il codomio della proprietà siano entrambi risorse
(possono essere anche la classe owl:thing e owl:nothing); le proprietà datatype
sono quelle che mettono in relazione una classe con un codominio “concreto”,
ovvero un tipo predefinito in OWL, come gli interi o le stringhe (per esempio
HaZampe può essere definita tra la classe Animale e la classe XSD:Integer predefinita); inoltre le proprietà annotation hanno lo scopo di definire annotazioni
e commenti su altre proprietà.
Esistono diversi costrutti per dare espressività alle proprietà:
9
microJena
• rdfs:range definisce il codominio di una proprietà
• rdfs:domain definisce il dominio di una proprietà
• owl:inverseOf afferma che il dominio e il codominio della proprietà è
l’opposto della proprietà data
• rdfs:subPropertyOf afferma che la proprietà è sottoproprietà della proprietà data
• owl:equivalentProperty afferma che la proprietà è equivalente alla proprietà data
• owl:FunctionalProperty afferma che la proprietà è funzionale
• owl:InverseFunctionalProperty afferma che la proprietà è funzionale inversa
• owl:SymmetricProperty afferma che la proprietà è simmetrica
• owl:TransitiveProperty afferma che la proprietà è transitiva
Dopo aver mostrato tutti i costrutti presenti in OWL si può evidenziare il parallelismo che sussiste tra la DL sulla quale si basa il nostro
linguaggio e lo stesso.
SHOIN(Dn) è un acronimo che fa riferimento al-
la possibilità di definire sussunzioni o equivalenze attraverso la proprietà
transitiva (S=owl:TransitiveProperty), vincoli di subordinazione e struttura gerarchica (H=owl:subClassOf o owl:subPropertyOf), classi di enumerazione (O=owl:OneOf), ruoli inversi (I=owl:InveseOf), vincoli di cardinalità
(N=owl:hasCardinality o owl:minCardinality o owl:maxCardinality) e la possibilità
di utilizzare domini concreti (domini che sono istanze di XSD, come numeri interi o stringhe di caratteri). Dunque il potere espressivo di OWL è da
paragonarsi a questa DL.
Possiamo a questo punto, inoltre, mostrare come OWL può essere ben
rappresentato dal Triangolo Aristotelico precedentemente citato: gli Individui
sono l’estensione del concetto Classe definiti in OWL (vedi figura 2.2).
Ma come ci viene presentata nella realtà un’ontologia in OWL? Uno dei
punti di forza di questo linguaggio, come abbiamo già accennato all’inizio di
questo capitolo, è la completa compatibilità con il suo predecessore RDF e
con le forme in cui esso veniva presentato. Ciò che viene definito in OWL lo
10
2.3 microJena
Figura 2.2: Triangolo Aristotelico
possiamo trovare rappresentato con le stesse modalità in cui ci è stato fornito
con RDF; di conseguenza un’ontologia possiamo trovarla come un insieme
di triple, oppure come uno schema strutturato basato su XML, o ancora in
versione grafica: esistono software dedicati alla realizzazione di tali immagini,
come per esempio GrOWL (esempio in appendice C.3). È possibile visualizzare
tre esempi di rappresentazione della stessa ontologia nell’appendice 4 (esempio
in appendice C.3).
Inoltre, come già accennato, l’ontologia creata con OWL può essere descritta con i soli costrutti RDF; ovviamente risulta molto meno comprensibile per
l’utente umano.
2.3
Il Reasoning
L’altra ragione che ha spinto il W3C a definire OWL come lo standard per lo
sviluppo del WebSemantico è la caratteristica di essere un linguaggio decidibile:
ciò comporta che si possano definire servizi di ragionamento per completare e
controllare, nel limite del possibile, le ontologie create.
Il discorso sul reasoning merita particolare attenzione. I software di reasoning realizzano un servizio di ragionamento di tipo deduttivo, ovvero un
processo logico che è in grado di stabilire univocamente se da determinate
premesse si possono trarre certe conclusioni; vengono esclusi dunque il ragionamento induttivo, dagli effetti osservati alle possibili cause, e il ragionamento
abduttivo, dai fatti specifici alle regole generali.
Nel particolare, si possono individuare pochi compiti di ragionamento,
per mezzo dei quali è possibile realizzare qualsiasi interrogazione alla base
di conoscenze:
11
microJena
1. sussunzione: stabilire se una classe C sussume una classe D significa
dimostrare che ogni elemento appartenente a C appartiene anche a D
2. equivalenza: stabilire se una classe C è equivalente ad una classe D
significa dimostrare che C sussume D e D sussume C
3. soddisfacibilità: determinare che un termine C è soddisfacibile significa
dimostrare che esiste almeno un modello della base della conoscenza in
cui l’insieme degli individui che soddisfano C non è vuoto
4. disgiunzione: stabilire che due termini C e D sono disgiunti significa dimostrare che non può esistere un individuo in grado di soddisfare
entrambi i termini
5. instance check:
dati un termine C e un individuo a, significa
determinare se a soddisfa il termine C
6. retrevial: data una classe C, il servizio di retrevial fornisce tutti gli
individui che soddisfano C
7. realizzazione: dato un nominale a e un insieme di termini, il servizio identifica i termini più specifici, all’interno dell’insieme fornito, che
soddisfano a.
Come già accennato, combinando a dovere questi servizi di ragionamento,
è possibile esprimere qualsiasi interrogazione alla quale un software è in grado
di dare una risposta. A proposito delle interrogazioni, occorre fare una precisazione: soltanto i linguaggi OWL-DL e OWL-LITE sono decidibili, ovvero sono
in grado di dare sempre una risposta alle interrogazioni, positiva o negativa
che sia, in un numero finito di operazioni. Se estendiamo il linguaggio ad
OWL-FULL, invece, per garantire una maggiore espressività del linguaggio,
viene meno la decidibilità; OWL-FULL è infatti semidecidibile, il che significa
che non è garantito che i servizi di ragionamento siano in grado di portare a
termine le query assegnate.
2.4
SPARQL
“Trying to use the Semantic Web without SPARQL is like trying to use a relational database without SQL”. Cercare di utilizzare il web semantico senza fare
12
2.4 microJena
uso di SPARQL sarebbe come cercare di utilizzare una base di dati relazionale
senza SQL. Questa è l’opinione di Tim Berners-Lee, direttore del W3C. Simple Protocol And RDF Query Language, questo è quanto significa l’acronimo
SPARQL; si tratta di un vero e proprio linguaggio di query, che oltretutto è
definito dallo standard W3C http://www.w3.org/TR/rdf-sparql-query/.
SPARQL si occupa di definire 2 standard, in realtà. Il compito fondamentale è quello di definire un linguaggio di query standard; in sostanza viene
descritta la sintassi che la query vera e propria deve avere. Quello che cade
sotto il nome di SPARQL protocol, invece, definisce rigorosamente le modalità
dello scambio di dati tra una qualsiasi implementazione di motore SPARQL e
l’applicazione che ne invoca i servizi, sia per quanto riguarda inviare la query
al servizio, che per il rinvio dei risultati all’applicazione client.
Dal punto di vista del programmatore, le query sono molto intuitive, ed è in
buona parte simile al linguaggio SQL. La figura 2.3 è un esempio, direttamente
tratto dal sito W3C (http://www.w3.org/) :
Figura 2.3: Query SPARQL
13
Capitolo 3
Jena
3.1
Cos’ è Jena
Jena, in generale, è una libreria per la gestione delle ontologie, sviluppata in
linguaggio Java dalla sezione Semantic Web Programme di HP, e coperta da
una licenza open-source ispirata alla GNU Public Licence.
Più in dettaglio, Jena mette a disposizione del programmatore un insieme di
risorse e funzionalità molto completo e vario, che permette di agire a 360 gradi
su una base di conoscenze, a partire dai linguaggi supportati: infatti, anche se
l’obiettivo fondamentale è il supporto e l’operatività nell’ambito di OWL, Jena
mette a disposizione le API per poter operare, per esempio, anche in RDF, o
in DAML+OIL, o in alternativa a basso livello, lasciando al programmatore la
completa gestione di nodi e triple, i fondamenti della base di conoscenze.
Dal punto di vista operativo, Jena fornisce al programmatore la più ampia
scelta di operazioni da svolgere con e sulle ontologie. Anzitutto è in grado di
accettare in input file che descrivono basi di conoscenze in diversi linguaggi;
riconosce N3 ed N-TRIPLE, descrizioni a basso livello, dove di nuovo vediamo
l’ontologia sempre descritta come lista di tutte le triple che la compongono,
ma con due convenzioni diverse, oppure RDF-XML, un linguaggio basato sulle
specifiche XML che descrive l’ontologia più ad alto livello, basandosi su di una
sintassi più intuitiva. Simmetricamente, Jena è in grado di salvare la base di
conoscenze in ognuno di questi formati, a cui si aggiunge un ulteriore RDFXML cosiddetto abbreviato, che viene serializzato sempre più ad alto livello,
e caratterizzato da una lettura sempre più intuitiva e pulita, che però sfrutta
15
microJena
algoritmi molto complessi, che necessitano di una certa capacità di calcolo,
che cresce esponenzialmente con la complessità del modello. Jena implementa
tutte le funzioni necessarie alla creazione di una base di conoscenze a partire da
un modello vuoto, oltre ovviamente a implementare tutti i metodi necessari
alla gestione ed elaborazione di un qualsiasi modello già esistente. Ultima
funzione di Jena è il reasoning: viene messo a disposizione infatti un vero e
proprio servizio di ragionamento.
3.2
ARQ
All’interno di Jena, l’implementazione del protocollo SPARQL si chiama ARQ,
ed è direttamente invocabile grazie ai metodi definiti all’interno delle classi. Al
modello viene associato un oggetto che si occupa del reasoning vero e proprio,
ed è possibile scegliere tra diverse modalità di operative, di diverso livello di
complessità e intelligenza, che offrono risultati sempre più precisi e sempre più
ampi, mano a mano che il reasoning si fa più profondo. Ovviamente questo
richiede uno sfruttamento sempre maggiore di risorse. Ricorrendo di nuovo
al sito del W3C, è possibile accedere ai risultati di un test svolto su diverse
implementazioni basate sullo standard SPARQL, di cui, una per una e divise
le funzioni in un numero limitato di gruppi principali, viene valutato il rispetto
del protocollo, e l’allineamento dei risultati con quelli previsti dal protocollo
stesso. Vediamo nella figura 3.1 come ARQ si distingua dalla maggioranza delle
implementazioni, dimostrando una compatibilità del 100% con lo standard
proposto dal W3C, e come questa qualità sia riconosciuta dal W3C stesso.
3.3
Livello di sviluppo di Jena
Jena è tuttora in fase di sviluppo definitivo. Proprio nel corso dello sviluppo
del progetto, anzi, è stata rilasciata un’ulteriore versione, la 2.5.4; e non si è
trattato di un aggiornamento di poco conto, perché al momento di effettuare il
test sulle prestazioni è stato rilevato un aumento di velocità di quasi il doppio.
La libreria è continuamente aggiornata, allargata, e adattata al contesto
dinamico da cui è caratterizzato il web semantico al giorno d’oggi; ogni volta
che il W3C riconosce un valido protocollo e lo definisce come proprio standard
16
3.4 microJena
Figura 3.1: Prestazioni Reasoner
è necessario allineare interfaccia e implementazione perché lo rispetti e, anche
al momento di esaminare il codice sorgente, sono emersi alcuni punti in cui
gli sviluppatori hanno tuttora lasciato dei particolari da sistemare o reimplementare a seconda delle necessità; non mancano i commenti in merito: viene
precisato che l’algoritmo potrebbe non essere accurato oppure che il metodo
non è ottimizzato e se ne attende una sua migliore implementazione, o altre
situazioni simili. Dunque il lavoro riguardo Jena è tutt’altro che terminato,
e nonostante ogni release sia perfettamente funzionante, gli sviluppatori HP
lavorano al suo costante miglioramento.
3.4
Perché Jena
La scelta di modello su cui operare è caduta proprio su Jena; i motivi sono
quasi tutti all’interno della spiegazione dettagliata appena illustrata a riguardo:
Jena dal punto di vista dei linguaggi è molto completa.
L’obiettivo principale resta una API per lavorare sui modelli descritti da
OWL; tuttavia sono implementate le interfacce per lavorare con RDF, TURTLE e DAML+OIL, per citarne qualcuno, e viene data la possibilità di lavorare
su basi di conoscenza a basso livello. Questo elemento permette al programmatore di acquisire modelli di vario tipo, tradurli in sintassi OWL, lavorarci e
ricavarne infine in output un file descritto secondo OWL.
17
microJena
Jena comprende un reasoner che rispetta alla perfezione lo standard che
il W3C definisce riguardo al linguaggio SPARQL; anche se, come vedremo in
dettaglio nel capitolo dedicato (capitolo 6), µJena non comprende un reasoner
sui modelli a causa dei limiti dei supporti hardware utilizzati, questa particolarità va a favore della solidità di Jena, e quindi della validità di questa
scelta. L’esame del codice ha rivelato quanto le interfacce dei metodi e delle
funzioni disponibili al programmatore siano semplici e intuitive; questo dato
ci ha permesso di mantenere al 100% il rispetto delle interfacce, peculiarità
che ha portato grandi vantaggi, che affronteremo nel capitolo specifico (vedi
capitolo 5).
Ciò che più importa ai fini del progetto è che tutte queste qualità hanno
fatto di Jena uno standard de facto riguardo la gestione di ontologie RDF e
OWL; proporre dunque una libreria mobile ispirata a Jena, e che ne rispetti la
sintassi e l’organizzazione, significa rendere disponibile al programmatore uno
strumento che ha di innovativo la possibilità di essere eseguito su dispositivi
portatili, ma che potenzialmente è già perfettamente in grado di utilizzare, dato
che richiede esattamente le stesse attitudini e conoscenze necessarie all’utilizzo
di Jena.
18
Capitolo 4
J2ME
J2ME è l’acronimo di Java 2, Micro Edition. Si tratta di una versione ridotta del linguaggio Java studiata per adattarsi ai limiti e alle particolarità dei
supporti mobili. Si può vedere nell’immagine 4.1 dove Sun colloca la J2ME
all’interno delle gerarchie di macchine virtuali Java che realizza.
Figura 4.1: Le distribuzioni Java
4.1
Evoluzione
La J2ME nasce con un obiettivo leggermente diverso da quello a cui si è giunti
oggigiorno; con il passare del tempo, delle esigenze del mercato e della tecno19
microJena
logia disponibile, le modalità con cui opera e per le quali viene studiata sono
variate.
In principio, veniva definita come un insieme di tecnologie e specifiche in
grado, combinate tra loro, di creare una piattaforma software che realizzasse
una vera e propria Java Runtime Environment, studiata appositamente perché
si adattasse ad uno specifico dispositivo. Veniva messo a disposizione un buon
numero di librerie distinte, ognuna circoscritta ad una serie di compiti molto
ristretta, e la combinazione di più librerie forniva la vera e propria macchina
virtuale che operava sui dispositivi.
Oggigiorno la divisione logica della libreria in diversi package viene mantenuta; ognuno dei package ha le proprie specifiche e le proprie versioni, ma
la tendenza è quella di portare l’intero mercato dei dispositivi verso un’unica
versione della libreria, in modo che tutti i prodotti sul mercato abbiano esattamente le stesse potenzialità, il tutto a vantaggio di chi sviluppa il software e
della portabilità del software stesso.
4.2
Organizzazione della J2ME
Analizzando la libreria divisa nei package già citati, si trovano fondamentalmente tre categorie:
1. Configurazione: con configurazione si intende un package che metta a
disposizione un numero limitato di funzioni basilari, e una macchina
virtuale che realizzi l’esecuzione, il tutto studiato per una grande quantità
di supporti
2. Profilo: con il profilo si entra più nello specifico; esso tratta una serie
di API più complesse ed è caratterizzato da maggior specializzazione
riguardo ai dispositivi che supporta.
3. Package opzionale: si tratta di package molto specifici, che di norma si
occupano di realizzare funzioni riguardo ad una tecnologia in particolare
Il requisito minimo indispensabile perché un dispositivo possa effettivamente eseguire software codificati secondo la J2ME è che abbia implementata al
suo interno una configurazione, associata ad un profilo. Questa combinazione
20
4.2 microJena
assicura una vera e propria Java Runtime Environment, in quanto implementa
tutto il necessario, dal core di esecuzione fino all’interfaccia utente.
4.2.1
La configurazione CLDC
Lo standard attuale, che la J2ME propone riguardo alla libreria di configurazione, si divide in due: il Connected Device Configuration (CDC), studiato
per dispositivi particolarmente performanti, quali palmari high-end o set-top
box, e il Connected Limited Device Configuration (CLDC), sviluppato per
dispositivi più a basso profilo, a cui questo progetto è indirizzato.
Si tratta di una versione della macchina virtuale Java adattata per operare
secondo disponibilità di potenza di calcolo e memoria disponibile, condizioni
tipiche di dispositivi come telefoni cellulari, palmari o in generale dispositivi
a basso profilo; altro elemento da tenere in considerazione è che la grande
maggioranza dell’hardware in questione opera alimentato da una batteria.
Una prima e ovvia riduzione è il numero vero e proprio delle classi: nella
Micro Edition ne troviamo circa 80 a disposizione dello sviluppatore, mentre la Standard Edition si compone di quasi 4000 classi; basti pensare che
la versione immediatamente precedente a quella attualmente in uso, la 1.0,
non implementava numeri e operazioni in virgola mobile. La J2ME è dunque
ridotta al minimo; per citare un esempio, alcuni oggetti molto particolareggiati
sono stati “collassati” verso l’alto: non si trovano più strutture dati complesse
come List e Set, che peraltro venivano implementate in diversi modi, lasciando
al programmatore il compito di scegliere quale implementazione risultasse la
migliore per il particolare uso che ne deve fare all’interno dell’algoritmo. La
J2ME prevede una e una sola struttura dati complessa: il Vector; sta al programmatore sfruttarne le potenzialità per far sı̀ che si adatti ai propri scopi.
Inoltre gli algoritmi sono stati ottimizzati; sempre per citare l’esempio dei
Vector, lo storage, l’hash e l’organizzazione stessa dei dati viene sviluppata
ovviamente per un numero ragionevole di oggetti, che nella Standard Edition
è invece molto più elevato. Si vedrà in seguito come queste limitazioni siano
state risolte al fine di realizzare il software obiettivo del progetto.
Il CLDC si propone tre obiettivi fondamentali:
1. ridurre il footprint, ovvero lo spazio necessario sia in memoria di massa
21
microJena
per ospitare il software, che la memoria di lavoro richiesta effettivamente
a runtime
2. estendere le potenzialità dell’hardware in questione
3. rendere le applicazioni portabili di dispositivo in dispositivo
Quest’ultima peculiarità non è banale: significa che ogni produttore deve
sviluppare all’interno dei propri dispositivi la compatibilità con la J2ME, oppure integrare una macchina virtuale specificamente sviluppata per il proprio
hardware. Esattamente come succede per il codice Java, un applicativo può essere eseguito su una qualsiasi piattaforma e su un qualunque sistema operativo,
sempre a patto che abbia il software Java installato. A questo proposito Sun
offre alcuni “Technology Compatibility Kit”, tool appositamente realizzati in
grado di essere eseguiti su ciascuna particolare implementazione della CLDC
e in grado di portare a termine una serie di test mirati a verificarne l’effettiva
compatibilità con le specifiche Java per la libreria.
4.2.2
La configurazione MIDP
Oltre il profilo, appena trattato, la configurazione è il secondo elemento chiave.
Lo standard J2ME propone, come base minima per realizzare un’applicazione
Java Micro Edition, il CLDC e la configurazione MIDP; la combinazione dei
due package realizza una vera e propria Java Runtime Environment (JRE),
una piattaforma autosufficiente in grado di eseguire un’applicazione dall’inizio
alla fine.
La caratteristica più utile del MIDP è l’implementazione di tutte le funzioni necessarie per sviluppare l’interfaccia grafica dell’applicazione; si parte
da specifiche di base, sviluppate sin dalla prima versione 1.0 del MIDP, fino a
giungere all’ultima versione installata oggi sulla maggior parte dei dispositivi,
la quale permette di realizzare una veste grafica molto semplice ed intuitiva per
la propria applicazione. Tutte le funzioni grafiche sono ottimizzate per schermi
di piccole dimensioni, cosı̀ come tutti i metodi di input-output sono studiati
appositamente per le tastiere tipiche dei telefonini, per eventuali touch-screen
o per piccole tastiere QWERTY integrate.
Altra caratteristica fondamentale del profilo MIDP è l’implementazione dei
servizi di connettività: è infatti in grado di sfruttare connessioni temporanee,
22
4.2 microJena
quali la linea telefonica di un cellulare, fino ai veri e propri servizi di rete
disponibili su un palmare dotato di connessione Wi-Fi. È in grado di spedire
e ricevere messaggi SMS sfruttando la linea GSM dei cellulari, e di dialogare
con i protocolli HTTP e HTTPS, sfruttare veri e propri socket, comunicare
attraverso le sempre più comuni porte seriali USB. L’estesa connettività del
profilo MIDP permette inoltre di integrare nelle applicazioni distribuite servizi
di aggiornamento On-Line, e download di intere nuove applicazioni direttamente sul dispositivo. Viene dato spazio anche ad un ramo applicativo in
forte crescita, ovvero le applicazioni a carattere ludico: i videogame. Oltre a
implementare classi studiate appositamente, MIDP concede libero accesso al
controllo a basso livello della grafica, cosı̀ da garantire piena gestione dell’output al programmatore, qualora lo desideri; curata anche la sezione audio, che
permette di creare musiche ed effetti sonori, o addirittura riprodurre file Wave.
Conseguenza diretta della connettività è la necessità di sicurezza: condividere informazioni con altri dispositivi è rischioso al pari di un computer che
naviga su internet. Cosı̀ vediamo implementati in MIDP il già citato profilo
HTTPS, oltre a SSL e WTLS, protocolli per lo scambio di dati protetti da
crittografia largamente usati in rete, che permettono quindi ai browser dei dispositivi di instaurare connessioni protette con siti che contengono informazioni
confidenziali, quale può essere il sito dell’home banking.
Come per CLDC, anche per MIDP sono a disposizione dei Kit di compatibilità rilasciati direttamente da Sun che permettono di testare l’effettivo
funzionamento delle implementazioni del profilo MIDP secondo lo standard
dettato da Java.
4.2.3
Package opzionali
A completamento di configurazione e profilo, la J2ME mette a disposizione
una serie di packages aggiuntivi, ciascuno riguardante un range di funzioni
molto ridotto e definito, riferito nello specifico alla tecnologia per il quale è
implementato.
L’uso dei package opzionali è normalmente legato a tecnologie aggiuntive,
non indispensabili per l’installazione di una JRE, ma che comunque aumentano
le capacità della stessa. Un esempio è la comunicazione: vi sono package specifici che mettono a disposizione metodi per l’utilizzo del protocollo Bluetooth,
23
microJena
o della comunicazione in Wi-Fi, che ovviamente sono implementati soltanto
sui dispositivi che hanno la relativa tecnologia installata e a disposizione.
Figura 4.2: CLDC
4.3
La J2ME oggi: l’MSA
Come già anticipato, la direzione verso cui punta Sun per il futuro della J2ME
è cambiata. Quanto detto finora resta sicuramente valido, e si adatta perfettamente alle piattaforme Java che devono essere eseguite all’interno di dispositivi
embedded; in questo caso l’opportunità di realizzare una JRE su misura permette di ottimizzare le applicazioni e ridurre i costi, limitando le capacità
di elaborazione al solo dominio di applicazione del dispositivo. Inoltre i vari
package sono disponibili tuttora ognuno all’interno della propria release, per
chiunque volesse ancora installare nel proprio dispositivo una versione ad-hoc
della runtime environment.
Sun ha introdotto un nuovo standard, l’MSA, ovvero Mobile Set Architecture, che trova anch’esso fondamento nella coppia CLDC MIDP. Il concetto
dell’MSA si avvicina molto al concetto di libreria Java per i personal computer,
in quanto prevede e definisce un’unica macchina virtuale, secondo una precisa
gerarchia di package; un programmatore non dovrà più porsi il problema di
quali package siano installati sul dispositivo e quali manchino: sarà sufficiente
sapere che il dispositivo supporta l’MSA, e di conseguenza fare riferimento ad
un unico standard per lo sviluppo delle applicazioni. Esistono poche eccezioni
alla rigidità di questa specifica. La prima è data dall’opportunità di implementare l’MSA Subset, ovvero un sottoinsieme delle librerie incluse nell’MSA,
studiato per dispositivi di basso profilo; viene garantita la retrocompatibilità,
24
4.3 microJena
quindi un software che richieda solo un insieme di metodi limitato al subset
potrà comunque operare su un dispositivo che implementa il set completo, e
la specifica non ammette vie di mezzo o adattamenti del set: un dispositivo,
per attenersi alla definizione di MSA Subset, deve implementare tutte e sole le
librerie del Subset, cosı̀ come per il set completo è imposta l’implementazione
di tutte le librerie appartenenti all’MSA. Seconda e ultima eccezione è data
da due package, la cui implementazione è legata all’hardware disponibile: le
funzioni Bluetooth e le funzioni Location, per i dispositivi dotati di GPS.
Figura 4.3: MSA
25
Capitolo 5
Obiettivi e scelte progettuali
La prima scelta progettuale operata è stata necessariamente la piattaforma
di programmazione; fondamentale ai fini della definizione dell’architettura del
software è anzitutto determinare proprio l’ambiente di sviluppo, e lavorare
in conseguenza delle caratteristiche del linguaggio scelto. La scelta è stata
ovvia: come già visto nel capito 4, quando si parla di software per dispositivi
portatili, al giorno d’oggi si parla di Java, per la precisione della piattaforma
Java Micro Edition. Non esiste nulla di paragonabile a livello di compatibilità,
portabilità del software, flessibilità e diffusione: si tratta ormai di uno standard
de facto e, riguardo alle proprietà elencate, presenta un’efficacia paragonabile
alla versione per personal computer.
Il requisito perché µJena possa funzionare, da questo punto di vista, è la
presenza sul dispositivo del supporto alla configurazione CLDC, versione 1.1.
Sono pochi i dispositivi che installano la precedente versione 1.0, e in effetti
la differenza principale è il supporto alle operazioni in virgola mobile; non
è da escludere in futuro l’opportunità di rilasciare una versione limitata che
estrometta le funzioni che richiedano tali operazioni. Per quanto riguarda il
profilo, µJena non si occupa di interfaccia grafica, né altre funzioni al di fuori
della pura gestione dei dati; ne consegue che ciò che conta effettivamente è
la sola configurazione. La decisione, per la versione rilasciata, è di compilare
il codice per il profilo MIDP 2.0, non perché sia effettivamente necessario,
quanto per allineare il software alle specifiche MSA, nel particolare limitandosi
al Subset definito (vedi paragrafo 4.3). In questo caso rilasciare una versione
compatibile con profili precedenti, in particolare il profilo MIDP in versione
1.0, richiederebbe semplicemente una ricompilazione con impostazioni ad hoc.
27
microJena
Una scelta meno ovvia è stata invece quella di prendere una libreria preesistente quale Jena di HP; i motivi che hanno spinto verso questa strada sono
molteplici, e principalmente volti a facilitare l’utilizzo di µJena , nonché una
sua eventuale diffusione negli applicativi destinati a nascere. Si può dire che
Jena sia, al pari della J2ME, uno standard de facto nel suo ambiente: le qualità
già elencate e la diffusione nel mondo dei software basati sul web semantico la
rendono un esempio perfetto e un punto di riferimento. La decisione è stata di
riproporre in µJena la medesima organizzazione e gerarchia delle classi, e soprattutto le stesse interfacce dei metodi, in modo da perseguire due particolari
scopi: annullare le barriere d’ingresso e mantenere una certa retrocompatibilità
del codice.
Il primo punto è semplice: se si mantiene la stessa organizzazione, e più
ancora la stessa sintassi di classe e comandi, a qualsiasi programmatore che
sappia utilizzare Jena sarebbe sufficiente applicare le stesse conoscenze, e utilizzare la nuova libreria come se non ci fosse alcuna differenza; ovviamente
questa caratteristica resta limitata al sottoinsieme di funzionalità mantenute
della libreria madre. La retrocompatibilità è invece la possibilità di applicare
un codice scritto per lavorare con Jena su piattaforma tradizionale alla nuova
libreria: riuscendo a mantenere per quanto possibile la medesima sintassi, basterebbe cambiare i riferimenti in testa al file sorgente per sfruttare le capacità
di elaborazione di µJena in sostituzione di quelle native. Qualora la compatibilità non fosse rispettata al cento per cento, l’idea è di limitare al minimo gli
interventi diretti che si renderebbero necessari da parte dell’utente a modifica
e adattamento del codice sorgente.
Una volta scelto Jena come riferimento e studiato a fondo la sua architettura sono apparse chiare le prime modifiche di massima da operare. Anzitutto,
il primo taglio sostanzioso è stato operato a livello del reasoning: gli algoritmi
che implementano i servizi di ragionamento sono molto complessi ed esosi a
livello di risorse richieste; non è pensabile ad oggi realizzare un software per
telefoni cellulari in grado di implementare un vero e proprio reasoning in tempi
accettabili. Un’altra modifica sostanziale è il supporto dei linguaggi: occorre
precisare che se Jena è in grado di affrontare, gestire e codificare conoscenze
organizzate in ontologie OWL piuttosto che altri vari formati (si veda il paragrafo 3.4), µJena ha come unico scopo la gestione del solo linguaggio OWL, e
quindi esclude qualsiasi altra sintassi o codifica; rappresenta un’eccezione, per
28
ovvie ragioni, la codifica RDF, sulla quale l’intera organizzazione di OWL è
costruita.
29
Capitolo 6
Architettura del software
6.1
Organizzazione generale
La stesura dei prossimi capitoli è volta ad esaminare il codice in dettaglio, ed è
pensata per gli sviluppatori o chiunque abbia intenzione di accedere al codice
sorgente per migliorarlo, estenderlo, o adattarlo alle proprie necessità.
Prendendo spunto dall’implementazione di Jena, la libreria si compone di
quattro sezioni fondamentali:
• il livello grafo-tripla è il motore effettivo che lavora con i dati, che
si occupa di organizzarli in memoria, e che risponde a basso livello a
interrogazioni dai livelli più alti
• il “demone” reificatore è un vero e proprio motore che agisce spesso
all’oscuro dell’utente e, a seconda delle configurazioni, è in grado di agire
a livello tripla secondo varie specifiche
• il livello RDF introduce la prima vera e propria ontologia, con la prima
distinzione dei nodi in risorse, proprietà e individui
• l’ultimo livello, OWL, è il livello al quale la libreria è stata studiata
per lavorare; appellandosi di volta in volta ai livelli sottostanti e mai
agendo direttamente sui dati, implementa tutte le funzioni necessarie
alla gestione dell’ontologia
Nell’immagine 6.1 si vede l’organizzazione dei quattro componenti fondamentali, mentre le frecce indicano quale sia il flusso delle comunicazioni principali tra livelli contigui, oltre ad evidenziare come il motore a basso livello
31
microJena
Figura 6.1: i quattro strati dell’architettura
sia effettivamente l’unico ad avere diretto accesso ai dati in memoria. La
particolare disposizione e le particolari comunicazioni tra i due strati a basso
livello verranno trattati nei paragrafi seguenti.
6.2
Le classi Factory
L’approccio alla creazione degli oggetti in µJena è particolare. Si tende ad
escludere al cento per cento l’accesso dell’utente ai costruttori.
La consistenza del modello è molto fragile a livello di classi e oggetti Java:
potrebbe essere sufficiente che manchi ad una risorsa il riferimento del modello
cui appartiene per falsare il risultato di alcune interrogazioni o per provocare la
duplicazione dei dati in memoria. Per questo motivo la costruzione e l’istanza
degli oggetti devono essere curati a dovere, ma nel contempo il codice deve
essere in grado di gestire casi particolari che possono servire, per esempio, a
costruire unioni e intersezioni tra modelli; è richiesto infatti, in questi casi, che
per alcuni istanti i dati e le risorse assumano forme particolari, che risulterebbero inconsistenti associate ad un modello. La struttura che permette di
mantenere i dati concreti sempre e comunque è costituita dalle classi denominate factory. Si tratta di classi statiche, che contengono una collezione di
metodi con il compito di astrarre al programmatore la creazione degli oggetti.
Se l’utente sfrutta tutte e sole le risorse messe a disposizione da tali classi,
lasciando il controllo e la gestione delle relazioni tra oggetti e dati al codice
32
6.3 microJena
sottostante, la libreria garantisce che tutto funzioni a dovere; se viceversa l’utente deciderà di accedere direttamente ai metodi costruttori degli oggetti, il
minimo errore potrebbe creare problemi al codice nella gestione del modello.
Un altro strumento messo a disposizione, studiato per lavorare in coppia
con le classi factory, e tuttavia più comodo per l’utente, è realizzato dai metodi
create dei vari modelli presenti in µJena ; tali metodi realizzano un ulteriore
livello di astrazione, in quanto mettono a disposizione dell’utente un punto
di accesso per chiedere al modello stesso la creazione di una qualsiasi risorsa,
che ovviamente gli apparterrà, delegando al codice i compiti di creazione e
salvataggio dei dati.
Infine la classe factory costituisce un nodo comune per la creazione di risorse; questo strumento può risultare comodo allo sviluppatore, in quanto,
se non c’è ragione per la quale ha senso cambiare le modalità con cui l’utente
richiede la creazione della generica risorsa, può darsi che determinati interventi
sull’architettura vadano a modificare le strutture dati a basso livello. Questo
principio implica che l’interfaccia del metodo della factory non abbia necessità
di essere cambiata, mentre il costruttore, o comunque l’istanza di alcuni dati chiave, possano dover essere modificati: in questo caso sarebbe sufficiente
cambiare il codice del nodo comune piuttosto che intervenire in tutto il codice
ovunque serva istanziare una nuova risorsa.
6.3
Integrazioni alla J2ME
Per portare a termine l’implementazione si sono dovute implementare classi
presenti nella piattaforma Standard Edition, non supportate dalla versione
mobile. Si tratta per lo più di classi appartenenti al package java.util.
Tendenzialmente il problema ha riguardato costrutti interni al programma.
Tuttavia, qualche volta tali strutture compaiono in interfacce di
metodi pubblici; è dunque importante che il programmatore sappia cosa sta usando in realtà:
chiunque infatti abbia bisogno, per esempio,
di un Iterator lavorando con Jena non deve importare il canonico java.util.Iterator della J2SE, in quanto non esiste, ma deve fare riferimento a
it.polimi.dei.contextaddict.microjena.util.Iterator.
Come per i metodi si è mantenuta la compatibilità con Jena, tali strut-
33
microJena
ture dati rispettano le interfacce Java della Standard Edition, cosı̀ da dare
continuità alla portabilità del codice.
Nel dettaglio, le strutture ridefinite sono:
• Iterator: semplicissima implementazione che propone i metodi next()
e hasNext()
• List: sfruttando la classe Vector, presente nella J2ME, viene fornita
questa interfaccia che permette una gestione dei dati più strutturata
• Set: fondamentalmente, una List che non ammette elementi duplicati
• Map: riproduce il concetto di funzione, ovvero consiste in un set di
coppie di oggetti, messi in relazione funzionale; ad ogni primo elemento
di ogni coppia viene associato uno e un solo elemento
Va aggiunto che nella J2ME tali istanze sono in realtà interfacce: ciascuna
ha a disposizione diverse implementazioni, a seconda dello scopo cui servono,
per esempio dotate o meno di una tabella di hash. In µJena si trovano invece
le classi, per la verità molto semplici e con implementazioni ridotte al minimo
indispensabile, studiate per coprire tutti e soli i domini di esecuzione interni a
µJena stessa; l’idea è che l’evoluzione dei dispositivi, cui si affianca l’evoluzione
della J2ME, composta da un insieme sempre più completo di classi, in un futuro
prossimo veda implementate tali strutture dati. Quelle fornite con µJena , a
supporto e integrazione della piattaforma affinché sia effettivamente in grado di
implementare l’intero framework, vedranno esaurito il loro compito e potranno
essere sostituite, di nuovo con un rapidissimo cambio di riferimenti, nel codice
originale.
6.4
Il livello Grafo-Tripla
Il package it.polimi.elet.contextaddict.microjena.graph contiene tutte
le classi che realizzano il livello vero e proprio che si occupa di organizzazione
e archiviazione delle triple.
L’elemento principale, che rappresenta le entità, è il nodo, costituito dalla classe Node.java, mentre a comporre la conoscenza vera e propria sono le
triple, semplicissime strutture dati che si compongono di una terna di nodi,
implementate in Triple.java.
34
6.4 microJena
La tripla è il fondamento della conoscenza; rappresenta il frammento minimo di nozione, ovvero una terna soggetto-predicato-oggetto, ciascuno dei quali
rappresentato da un nodo. Qualsiasi nozione all’interno della base di conoscenza viene scomposta e rappresentata da una tripla o, più spesso, da un’insieme
di triple, la cui combinazione di asserzioni a basso livello va ad assumere un
significato ad alto livello, quale può essere una classe, un individuo e cosı̀ via.
6.4.1
Il Nodo
Le classi Node.java e derivate implementano la completa gestione del nodo
all’interno del grafo; tali classi prevedono le diverse tipologie che un nodo può
assumere, e mantiengono a memoria tutte le informazioni che sono necessarie
riguardo al nodo stesso.
Sono diverse le tipologie di nodo che è possibile istanziare; la prima e fondamentale divisione è quella tra Node Concrete e Node Fluid. Intuitivamente,
i nodi concreti rappresentano istanze vere e proprie di entità, quali possono
essere risorse o letterali; i Node Fluid sono invece nodi “eterei”, ovvero che
non rappresentano risorse o entità vere e proprie, ma vengono utilizzati come
appoggio per la realizzazione di semplici interrogazioni o addirittura complesse
query.
Figura 6.2: UML del nodo
I nodi concreti si dividono in:
1. Node URI: sono i nodi che rappresentano qualsiasi risorsa associata ad
un Universal Resource Locator;
2. Node Blank: vengono utilizzati per quelle risorse prive di URI; nella
pratica, sono utili per istanziare risorse ausiliarie, o come appoggio nella
realizzazione di strutture ad alto livello, come si vedrà in seguito per
restrizioni o liste RDF (vedi 6.6.2).
35
microJena
3. Node Literal: sono i nodi che riferiscono valori a dominio concreto; interi,
stringhe, o qualsiasi valore possa essere necessario utilizzare come oggetto
di una tripla.
Figura 6.3: UML dei nodi concreti
L’unica istanza di Node Fluid mantenuta nella libreria è il Node ANY,
utilizzato nelle query per indicare che si accetta qualunque nodo in risposta.
Un altro nodo presente in Jena invece è il Node Variable, utile alle query
complesse che sono estranee a µJena .
Figura 6.4: UML dei nodi “fluidi”
Dal punto di vista del programmatore, l’unico nodo che dovrebbe essere
usato è il Node, il nodo vero e proprio; si tratta di una classe astratta che
contiene tutto quanto è utile all’utente. Qualsiasi funzione o metodo è già
presente in Node, e sarà poi compito delle sottoimplementazioni dello stesso
eseguire il codice corretto.
Creazione del nodo.
L’interfaccia di Node include metodi statici
per istanziare qualsiasi tipo di nodo, che figurano come Node.createURI o
Node.createLiteral. I suddetti metodi sono inoltre in grado di intervenire
nel caso si tenti di duplicare un nodo già esistente: se si cerca di creare un
36
6.4 microJena
nodo con un URI già presente in memoria, un apposito algoritmo lo recupera
e restituisce un nuovo puntatore al nodo già esistente.
Metodi. La classe Node non prevede molte operazioni da poter eseguire
sul nodo, soprattutto perché il nodo nella sua struttura è paragonabile ad un
atomo: l’unica informazione che porta con sé è il proprio ID, che sia un URI
o anonimo, il tipo di nodo, o la stringa che rappresenta il Literal. Sono a
disposizione metodi di test, quali Node.isURI() o Node.isLiteral() e cosı̀
via, oltre a tutte le interrogazioni riguardo l’URI o il Literal contenuti.
Interrogazioni. Esistono due tipi di controllo eseguibili sul nodo, ovvero
il classico Node.equals, e un più particolare Node.matches. Per il metodo
equals viene mantenuta la linea di qualsiasi classe Java, ovvero il test risponde
“true” quando due istanze diverse di Node sono equivalenti, in questo caso
se hanno lo stesso URI, lo stesso ID o la stessa stringa per quanto riguarda
i Literal. Il metodo matches invece è ideato ad hoc per le ontologie, ed è
da considerarsi un’estensione del metodo equals appena visto, in quanto dà
esito affermativo in tutti i casi in cui lo prevede equals, oltre a quando viene
eseguito il test con un NodeANY; serve in tutte le query in cui si voglia indicare
al software che qualunque nodo è accettato. Per esempio, la richiesta di tutte
le triple del tipo node1-node2-Node.ANY darà come risposta tutte le triple
aventi come soggetto e predicato i nodi specificati, ma come oggetto verrà
accettato qualunque nodo.
6.4.2
La Tripla
Come già anticipato, la tripla è la base della conoscenza; rappresenta una
combinazione di tre nodi, eventualmente ripetuti, che svolgono la funzione di
un soggetto, un predicato e un oggetto. La classe Triple.java è molto semplice.
Prevede un costruttore che riceve soggetto, predicato e oggetto, i metodi di
interrogazione alle tre istanze, e il già citato dualismo tra i metodi equals
e matches, che si rifanno né più né meno ai metodi rispettivi dei tre nodi
soggetto, predicato e oggetto.
6.4.3
Gli Assiomi
Definita la tripla, è immediato definire l’assioma: rappresentato dalla classe
Axiom.java, non introduce alcuna novità a livello di implementazione o codice.
37
microJena
Si limita a rappresentare una tripla che ha la particolarità di non essere propriamente parte del modello, ma un vero e proprio postulato del linguaggio RDF
o OWL, utile per lo più perché le interrogazioni possano accedere a nozioni
scontate, portando dunque a termine passaggi ovvi che tuttavia richiedono dal
punto di vista dell’algoritmo la presenza esplicita di tali assiomi.
La scelta di implementare tali assiomi in una sottoclasse di tripla nasce dalla
necessità di poter eseguire a livello di codice un test sulle triple, in quanto il
codice tratta gli assiomi in maniera diversa dalle triple semplici.
L’accesso all’archivio dei dati prevede di default che nessuna operazione
sia in grado di modificare o rimuovere un assioma istanziato in precedenza; i
metodi di rimozione standard, in particolare, sono accoppiati ad un metodo
omonimo, dotato di una sorta di privilegio di accesso maggiore, che quando
viene esplicitamente abilitato dal codice rende il metodo stesso in grado di
intervenire a basso livello sugli assiomi come fossero normali triple. I metodi
citati sono dichiarati pubblici, soprattutto per la necessità di renderli visibili
tra i diversi package con cui la libreria lavora. Solo come conseguenza a tale
necessità risultano visibili all’utente; tuttavia nessuna classe esterna alla libreria stessa dovrebbe mai interpellare tali metodi in quanto nessuna operazione
standard ha necessità di operare sugli assiomi: a causa di un intervento diretto
a modifica degli stessi potrebbe venir meno la consistenza del modello.
6.4.4
Il Grafo
L’elemento che opera la vera e propria archiviazione delle triple e che quindi
realizza la vera e propria organizzazione della conoscenza in memoria, è il
grafo; contiene al suo interno tutte le triple appartenenti al modello e fornisce
le interfacce utili a crearne, aggiungerne, cancellarne e interrogarne.
Di nuovo viene operato un controllo sulle operazioni eseguite e quindi, se
si cerca di istanziare una seconda volta una tripla già presente, l’algoritmo
interviene e restituisce la tripla già esistente, senza duplicarne la struttura in
memoria; è possibile interrogare il grafo chiedendo una lista di tutte le triple
che rispettino un determinato match, o anche chiedere soltanto se esiste in
memoria almeno una tripla che lo soddisfi.
Il grafo è l’unica classe java in grado di intervenire sull’archivio di nodi e
triple; i permessi relativi a metodi e variabili interne sono organizzati in modo
38
6.4 microJena
che chiunque voglia modificare i dati debba appellarsi ai metodi del grafo,
senza aver in nessun modo diretto accesso all’archivio dei dati.
6.4.5
Principali differenze con Jena del motore di archiviazione
Gli assiomi. La struttura che Jena sfrutta per gestire gli assiomi è piuttosto
complessa: troppo, per gli scopi del nostro lavoro. Per questo motivo è stata
implementata una diversa gestione degli assiomi che ovviamente porta vantaggi
e svantaggi.
La chiave della modifica sta nella modalità con cui gli assiomi vengono
istanziati e controllati: Jena vigila sulla base di conoscenze cercando di ridurre
il più possibile il numero di triple in memoria: di fatto, gli assiomi archiviati
sono sempre il minimo indispensabile a definire i rapporti tra le sole risorse
effettivamente memorizzate. Questo fatto porta ad un modello ovviamente più
ordinato, ma come svantaggio prevede l’implementazione di un controllo persistente su ogni assioma che sia in grado di rimuoverlo non appena venga meno la
sua necessità, ma anche di riaggiungerlo non appena torni indispensabile. Per
esempio, non appena viene eliminata l’ultima Restriction dal modello vengono
anche eliminati gli assiomi sulle restrizioni, oppure, come altro esempio, se
una classe si trova priva di individui viene fatta pulizia degli assiomi specifici
relativi alla classe stessa.
In µJena non è previsto nessun controllo particolare: gli assiomi vengono
creati e vengono creati tutti. La conseguenza è un eccesso sul numero di
triple effettivamente utili presenti nel grafo. Una valutazione di tale eccesso è
semplice: OWL prevede 24 assiomi generici, due per ogni tipologia di risorsa
istanziata, e ciò significa che un modello con istanziate sole classi avrà in
memoria 22 assiomi inutili, ma un modello che usi anche solo la metà delle
risorse descrittive fondamentali porta a poco più di una decina di elementi
in eccesso, cifra che rimane costante sia che il grafo si componga di 100 o di
10.000 triple. Altra fonte di eccesso sono per esempio le classi: una classe
specifica necessita di tre assiomi istanziati, ma solamente finché non è presente
almeno un individuo. Come già detto, Jena si preoccuperebbe di cancellare gli
assiomi se fosse il caso, per aggiungerli nuovamente non appena si presenti un
nuovo individuo. Di nuovo, l’eccesso è valutato in 3 triple, per ciascuna classe
39
microJena
priva di individui: cifra più che accettabile in favore di un’implementazione
più lineare e veloce.
L’archiviazione. Jena archivia i dati con modalità differente. In realtà
Jena è in grado di gestire il proprio archivio con diverse strategie. L’utente
ha sempre a che fare con l’interfaccia Graph, il grafo, ma, a seconda di come
viene istanziata, si può a lavorare con diverse implementazioni. Si tratta di una
politica frequente in Jena: si definisce una e una sola interfaccia per elemento e
successivamente, a seconda delle capacità che vengono richieste, viene attivata
l’implementazione più adatta al caso. Ciò influisce direttamente non solo sulle
prestazioni, sull’attitudine di ogni implementazione a gestire modelli più o
meno estesi o sulla memoria di archiviazione richiesta, ma anche sulle capacità
effettive dell’elemento: non è detto per esempio che due diverse istanze di
un grafo rispondano allo stesso modo ad una query, in quanto la profondità
del ragionamento, la capacità di coniugare diversi servizi in un’unica query, o
di ricostruire frammenti del grafo non espliciti, dipende dall’implementazione
scelta; quindi, sceglierne una eccessivamente semplice, potrebbe portare a servizi di ragionamento meno “intelligenti di altri”. La politica seguita in µJena è
invece quella di fornire una e una sola implementazione per ciascun elemento;
la scelta ovviamente è caduta su un compromesso tra la completezza delle
operazioni svolte e la semplicità del codice al fine solito di sfruttare il minor
numero di risorse possibili.
Il reasoner. Il reasoner rappresenta il taglio netto operato su Jena: le
attività di reasoning richiedono un’elevata capacità di elaborazione e una discreta quantità di memoria di lavoro. Tutto ciò che µJena è in grado di fornire
a questo livello è una buona serie di semplici interrogazioni sulla conoscenza
gestita dall’archivio, ma niente che effettivamente possa cadere sotto il nome
di query. Ovviamente ciò implica che non venga gestito il linguaggio SPARQL.
Con l’evolversi dell’hardware portatile si vedono aumentare le disponibilità
di connettività wireless a velocità sempre più elevate e costi sempre minori;
questi fattori determinano un primo possibile step di miglioramento per µJena :
l’interfaccia per il DIG-Reasoning. Si tratta di una tipologia di funzionamento
già adottata da buona parte dei software dedicati al reasoning e consiste nel
delegare il lavoro vero e proprio ad un software remoto che comunica via rete
i risultati delle query.
40
6.5 microJena
6.5
Il Reificatore
La sezione del codice che si occupa della reificazione delle triple è stata definita “demone” e, come si vedrà più avanti, opera in maniera molto simile
ai software che prendono la stessa definizione. Il reificatore, rappresentato
dall’interfaccia Reifier.java e relative implementazioni, ha diverse modalità di
utilizzo, ma quella più utilizzata agisce proprio in background, intercettando
tutto il lavoro che viene richiesto circa le triple che lo competono.
6.5.1
Rappresentazione in memoria della tripla reificata
Quando uno statement viene reificato la sua struttura viene stravolta. Ipotizziamo di voler reificare lo statement di URI guide:statement: guide:subject
@guide:predicate guide:object. La reificazione traduce lo statement in un
insieme di quattro triple:
1. guide:statement @rdf:type rdf:Statement
2. guide:statement @rdf:subject guide:subject
3. guide:statement @rdf:predicate guide:predicate
4. guide:statement @rdf:object guide:object
A livello di storage, solo questa quaterna di triple istanzia la reificazione
vera e propria sulla tripla di URI guide:statement. La mancanza di uno solo
dei quattro statement, cosı̀ come definire un secondo soggetto, predicato o
oggetto, farebbe venire meno la reificazione della tripla, lasciando nel modello
un numero qualsiasi di statement apparentemente senza significato.
6.5.2
Le modalità di utilizzo
I parametri di impostazione del reificatore sono fondamentalmente due:
“concealing” e “intercepting”.
Concealing. Quando il reificatore è in modalità concealing nasconde le
triple che definiscono le reificazioni al grafo; questo fatto significa che ad una
semplice interrogazione sulle triple il software esclude dalla risposta tali triple.
D’altra parte, al momento di serializzare la base di conoscenze in un file, tutte
41
microJena
le triple vengono salvate: si tratta dunque di un intervento che agisce soltanto
a runtime.
Ecco un esempio di reificazione in modalità concealing: ipotizziamo di
voler reificare la tripla definita in precedenza e includerla in uno statement;
avremmo:
<guide:someSubject @guide:somePredicate guide:statement>
Nessun altra tripla sarebbe visibile all’utente a runtime.
Se invece la modalità concealing fosse disattivata, l’interrogazione su tutte
le triple del grafo risponderebbe:
1. <guide:statement @rdf:type rdf:Statement>
2. <guide:statement @rdf:subject guide:subject>
3. <guide:statement @rdf:predicate guide:predicate>
4. <guide:statement @rdf:object guide:object>
5. <guide:someSubject @guide:somePredicate guide:statement>
Tutte le triple sarebbero dunque visibili.
Intercepting. Quest’altro parametro abilita o meno l’esecuzione del reificatore in qualità di demone. In realtà il reificatore è sempre a disposizione
come normale oggetto Java e mette a disposizione metodi per la creazione,
rimozione di reificazioni e funzioni per interrogarlo se una tripla sia o meno
stata reificata all’interno del modello. Nel caso però si attivi la modalità intercepting, allora il reificatore vigilerà su qualsiasi tripla lo riguardi, sia che
sia stato chiamato esplicitamente o meno dal programmatore: ogni tentativo
di creazione o rimozione di una delle triple della stessa tipologia di quelle
all’esempio precedente vengono prima processate. In particolare, quando il
reificatore verifica che una tripla aggiunta o rimossa va a completare l’insieme
dei quattro statement, li rimuove dal grafo, tenendo traccia al proprio interno
della reificazione stessa; se invece l’aggiunta o la rimozione di una tripla va
a rovinare i quattro statement, duplicando una definizione o lasciando una
mancanza, il reificatore cancella il riferimento al proprio interno e reinserisce
nel grafo le triple restanti.
Modalità predefinite. Nella libreria ci sono tre modalità predefinite a
disposizione dell’utente memorizzate nella classe ReificationStyle.java. La mo42
6.5 microJena
dalità standard, che viene abilitata di default qualora non venga specificato,
prevede un reificatore che intercetta le triple che lo competono, ma non le
nasconde al grafo; interviene in caso di necessità, ma lascia alle sue spalle un
grafo completo, anche se meno immediato da interpretare. La modalità convenient, alla lettera “comoda”, abilita entrambe le modalità, quindi si frappone
tra utente e archivio dati, garantendo un modello “pulito” e la massima consistenza dei dati. Ultima, la modalità minimal; prevede un reificatore che
operi al minimo delle proprie capacità: interviene solo quando esplicitamente
chiamato in causa e non si cura di fornire al grafo le triple in suo possesso.
6.5.3
Flusso dei dati
Affiché il reificatore possa funzionare a dovere, deve poter vigilare su ogni
flusso dati che transita dal core grafo-tripla. In effetti, ogni volta che il core
a basso livello ha necessità di salvare o intervenire su un qualsiasi numero di
triple in archivio, interpella il reificatore; è sempre quest’ultimo che si occupa
di valutare la situazione, anzitutto in merito alla modalità operativa con cui
è stato istanziato e, successivamente, a seconda della tipologia di tripla che
viene trattata.
Il reificatore, esaminata la situazione, decide se l’operazione è di propria
competenza o meno. Se deduce che la tripla non lo riguarda, rimanda il lavoro
da compiere al livello sottostante. In caso contrario, svolge tutte le operazioni
necessarie, e solleva successivamente il core sottostante da qualsiasi ulteriore
compito; si ricorda che per intervenire sui dati il reificatore deve comunque
interpellare i servizi di archiviazione messi a disposizione dal core a basso
livello che, come messo in evidenza dalla figura 6.1, è l’unica entità in grado
di modificare l’archivio.
A sostegno di questa politica, è necessaria una considerazione che spesso
trae in inganno chi lavora con le ontologie: la tripla reificata non è mai parte
del grafo se non è altrimenti specificato: quando il reificatore gestisce dati al
proprio interno non va mai a lavorare sull’archivio vero e proprio, ma su triple
ausiliarie utili a definire gli statement reificati.
Un semplice esempio sarà utile a spiegare meglio il comportamento
descritto.
Supponiamo
che
all’interno
della
base
di
conoscenze
sia
presen43
microJena
te
una
risorsa
che
esempio:marioRossi
sta
persona
e
faccia
che
riferimento
sussistano
ad
due
una
persona
statement
di
URI
riguardo
que-
<esempio:marioRossi @esempio:haNome ‘‘Mario’’>
e
<esempio:marioRossi @esempio:haCognome ‘‘Rossi’’>; nulla vieta che,
per qualche motivo, all’interno della nostra ontologia, esista un’entità relativa
ad una seconda persona che abbia a disposizione informazioni sbagliate:
introdotto il predicato esempio:saChe, potremmo reificare lo statement
<esempio:marioRossi @esempio:haNome ‘‘Luca’’>,
assegnandoli
come
URI esempio:infoErrata.
Ecco come risulterebbe la base di conoscenze appena descritta:
ARCHIVIO DATI
<esempio:marioRossi @esempio:haNome ‘‘Mario’’>
<esempio:marioRossi @esempio:haCognome ‘‘Rossi’’>
<esempio:persona2 @esempio:saChe esempio:infoErrata>
REIFICATORE
<esempio:infoErrata @rdf:type rdf:Statement>
<esempio:infoErrata @rdf:subject esempio:marioRossi>
<esempio:infoErrata @rdf:predicate esempio:haNome>
<esempio:infoErrata @rdf:object ‘‘Luca’’>
è importante notare che lo statement
<esempio:marioRossi @esempio:haNome ‘‘Luca’’>
non fa parte del modello, anzi si tratta di un’informazione sbagliata alla quale
è possibile risalire grazie ai dati ausiliari presenti nel reificatore e, qualora quest’ultimo non li nascondesse al grafo come descritto nella modalità concealing,
li troveremmo anche nel modello stesso. In conclusione, i dati veri e propri che
rappresentano la base di conoscenze sono esclusivamente archiviati e gestiti
dal grafo; il ruolo del reificatore è realizzare un supporto per triple ausiliarie,
utili a descrivere nodi che reificano altri statement e che in effetti vengono
serializzate quando è richiesto di trasmettere il modello in un flusso di dati.
44
6.6 microJena
6.5.4
Principali differenze con Jena del reificatore
Questa sezione del codice non presenta vere e proprie differenze con Jena;
l’architettura seguita è sostanzialmente la stessa, ciò che cambia è l’implementazione a basso livello di metodi e funzioni, che sono state semplificate a favore
di una gestione dati più semplice e di un tempo di elaborazione minore.
Effettivamente questa sezione non presenta nel codice originale frammenti
opzionali, né parti che si possano eliminare senza tralasciare la garanzia di
concretezza del modello.
6.6
Il livello RDF
Il livello RDF è il primo passo concreto verso l’utente: realizza le prime interfacce ad alto livello utili a creare una vera e propria API che mascheri il lavoro
a basso livello del core di archiviazione, oltre ad intervenire, come si vedrà nei
prossimi capitoli, con i primi controlli di consistenza sulla creazione di triple.
6.6.1
Il package Enhanched
Enhanched alla lettera significa “migliorato”, “potenziato”. Si può definire un meta-package, implementato appositamente per realizzare un anello di
congiunzione tra il sottostante motore di archiviazione e i successivi livelli di
interfaccia utente. Si compone di due classi fondamentali: un nodo enhanced
(EnhNode.java) e un grafo enhanced (EnhGraph.java).
Il nodo è un’entità fine a se stessa e ha ragione di esistere in quanto dotato
di un riferimento che lo identifica univocamente; non vi è differenza alcuna tra
un nodo preso come entità singola o un nodo recuperato come parte della tripla
di un grafo. Ad alto livello è necessario vedere l’entità singola come qualcosa di
maggiormente caratterizzato; si può dire che l’EnhNode sia l’istanza di un nodo
in un modello. Questo significa che diversi grafi possono condividere lo stesso
nodo e ciascuno utilizzarlo più volte all’interno del proprio archivio, sempre
considerando il nodo un’entità esterna ed estranea. Passando a livello più alto
il paradigma viene modificato come segue: più modelli possono condividere
lo stesso nodo, ma ogni modello lo deve incapsulare all’interno di un proprio
EnhNode che sarà poi utilizzato per creare gli statement.
45
microJena
Lo stesso avviene per il grafo: l’EnhGraph non è altro che l’incapsulamento
di un grafo, che di nuovo può essere condiviso tra diversi modelli, e rappresenta
l’astrazione dell’archivio dei dati, dato che, come sempre, non viene dato libero
accesso alle strutture dati che organizzano la conoscenza, ma vengono messi
a disposizione metodi appositi che ancora una volta interpellano i servizi di
archiviazione a basso livello.
6.6.2
Le entità
Viene introdotta per la prima volta una caratterizzazione delle entità: sebbene
ogni istanza non sia altro che un nodo incapsulato in una struttura dati di più
alto livello, non esiste più soltanto il nodo fine a se stesso, ma vi è la differenza
tra la risorsa generica, il Literal e la proprietà.
La Risorsa. Gestita dalla classe Resource.java, non introduce novità; si
tratta della entità generica, contenente al suo interno le informazioni proprie
del nodo che rappresenta, ma sempre mediante l’EnhNode che lo istanzia nel
modello in cui si lavora.
La Proprietà. La proprietà è la prima caratterizzazione che incontriamo e,
per la prima volta, viene definita una differenza tra le diverse tipologie di entità.
Sebbene la proprietà sia in effetti una risorsa, non si può assolutamente dire
il contrario: nella creazione degli statement è infatti necessario che la risorsa
definita predicato della tripla sia stata istanziata e definita come proprietà;
questo non significa che non possa essere poi utilizzata anche come soggetto o
oggetto di altri statement, anzi è pratica comune che ciò avvenga.
Il literal. Un valore letterale è l’entità che viene usata per istanziare i
Node Literal e rappresenta i valori a dominio concreto; al pari della proprietà,
introduce dei vincoli sull’istanza della conoscenza in quanto tali valori non
rappresentano entità definite e distinguibili, ed infatti non sono delle risorse,
ma solo una sorta di etichette o valori attribuibili alle risorse stesse: in questo
caso il vincolo è che, nell’istanza dello statement, un literal possa trovare posto
solo come entità oggetto.
I Container. Si tratta effettivamente di contenitori; sono strutture appositamente definite, descritte mediante un’apposita sintassi e permettono di
assegnare un URI ad un gruppo di risorse. Si possono definire Bag, generici
contenitori, Alt, contenitori che descrivono la necessità di compiere una scelta,
46
6.6 microJena
all’interno dell’insieme di risorse definito, e infine Seq, particolari Bag che
prevedono un ordinamento degli elementi contenuti.
Le liste. Denominate RDFList, sono la struttura definita in RDF per
organizzare i dati in una vera e propria lista dinamica del tutto simile alla comune struttura dati utilizzata nei linguaggi di programmazione. Ogni elemento
della lista è caratterizzato da un puntatore alla risorsa che compone l’elemento
stesso e da un puntatore all’elemento successivo della lista, eventualmente un
puntatore a NULL, che indica il termine della lista; NULL è in questo caso
rappresentato da rdf:nil.
Figura 6.5: il layer RDF
6.6.3
Gli Statement
A livello pratico non c’è differenza tra la tripla e lo Statement. Il fatto che
portino un nome diverso è legato “storicamente” alle precedenti versioni di
Jena e, per quanto riguarda il progetto, è dovuto di nuovo alla necessità di
mantenere la compatibilità delle interfacce.
Si può fare un paragone con i già citati EnhNode: in effetti, mentre la
tripla è una struttura dati che lega tre nodi, uno Statement esiste solo legato
ad un modello e, anche se si tratta sempre di una struttura dati, non lega
47
microJena
tre semplici nodi, ma tre EnhNode che forzatamente devono appartenere al
modello. Schematizzando le diverse organizzazioni, una tripla potrebbe essere
vista organizzata come nella figura 6.6
Di contro, lo Statement è organizzato come nella figura 6.7
Figura 6.6: La tripla
Non è un caso che lo statement sia stato rappresentato associato al modello
che lo contiene, mentre la tripla viene vista come entità a se stante, libera da
qualsiasi vincolo (vedi 6.6 e 6.7).
Figura 6.7: Uno statement
6.6.4
L’astrazione introdotta da RDF
Per la prima volta con il livello RDF avviene una vera e propria astrazione
delle triple del grafo. La nuova interfaccia permette all’utente di formulare
48
6.6 microJena
richieste specifiche, come la creazione di una proprietà o di un letterale, non
più preoccupandosi di come questo venga serializzato in archivio. Esempio
pratico,:la creazione della proprietà esempio:proprietà sul generico modello
“m” viene richiamata dalla riga di codice:
m.createProperty(‘‘esempio:proprietà’’);
A livello inferiore, sarebbe dovuto essere l’utente a specificare al grafo come
tale proprietà sarebbe dovuta essere serializzata, ovvero:
<esempio:proprietà @rdf:type rdf:property>.
Inoltre si introducono casi in cui le strutture sono troppo complesse perché
sia sufficiente uno statement a descriverli in memoria: un’ulteriore astrazione si
verifica in quanto il livello RDF è in grado di raccogliere gli statement necessari,
costruire la risorsa che tali statement descrivono e fornire all’utente un’unica
interfaccia ad alto livello. Questo succede in RDF per le liste e i container,
mentre si vedrà (nel paragrafo 6.7) che per il livello OWL diventa una prassi
comune praticamente ad ogni tipo di risorsa.
Un esempio sarà utile a fare chiarezza. Ipotizzando di avere a disposizione due risorse generiche che saranno indicate come esempio:risorsa1 e
esempio:risorsa2, e di voler creare una lista che le raggruppi nell’ordine in
cui sono state definite. Siano A0001 e A0002 due generici ID anonimi. Per
descrivere interamente soltanto la struttura dati, escludendo le risorse, sono
necessari
4 statement:
<A0001 @rdf:first esempio:risorsa1>
<A0001 @rdf:rest A0002>
<A0002 @rdf:first esempio:risorsa2>
<A0002 @rdf:rest rdf:nil>
e 4 assiomi:
<A0001 @rdf:type rdf:list>
<A0001 @rdf:type rdfs:resource>
<A0002 @rdf:type rdf:list>
<A0002 @rdf:type rdfs:resource>
49
microJena
Compito del livello RDF è serializzare l’intero costrutto appena descritto
in risposta ad un’unica richiesta da parte dell’utente ovvero la codifica di una
lista:
m.createList(new Resource[ ] {risorsa1, risorsa2});
6.6.5
L’assenza di una struttura dati
Un grosso taglio operato su Jena è l’organizzazione dei dati ad alto livello:
semplicemente, i dati sono stati eliminati.
Non esiste un’istanza persistente in memoria delle risorse RDF, e non esisterà nel livello OWL; tutto ciò che resta archiviato sono le triple. Le interfacce
RDF mettono a disposizione dell’utente un linguaggio ad alto livello per gestire le triple, ma è importante notare come tutta la conoscenza sia infine
ridotta, o meglio tradotta, in una serie di statement; quando una risorsa viene
creata, la libreria istanzia un oggetto Java ad alto livello che racchiude tutte
le informazioni necessarie, che resta ovviamente a disposizione dell’utente per
tutte le operazioni che vorrà eseguire; terminato l’utilizzo, resterà l’impronta
nella cache di triple di tutte le informazioni a basso livello, ma effettivamente
l’intefaccia dati utente decade non appena non risulti più indispensabile. Allo
stesso modo, il livello RDF risponde alle interrogazioni controllando a sua volta
nel grafo qualora esista la giusta combinazione di triple: in caso affermativo,
viene incapsulata nell’apposita interfaccia ad alto livello e proposta all’utente
come tale.
In figura 6.8 è possibile vedere le operazioni-tipo eseguite da due ipotetici
thread, uno di creazione e uno di interrogazione.
Inoltre, un’astrazione simile vale per le triple: mentre la tripla è una struttura dati persistente, che rappresenta effettivamente la conoscenza, lo Statement è un’interfaccia di alto livello fornita all’utente che incapsula una tripla di
basso livello; terminato l’utilizzo da parte dell’utente, la struttura Statement
decade e a memoria resta solo l’istanza della tripla. Quando un utente avrà di
nuovo bisogno di operare su una triple, essa verrà nuovamente rappresentata
mediante uno Statement predisposto al lavoro ad alto livello, riproponendo la
stessa strategia sfruttata per le risorse.
50
6.6 microJena
Figura 6.8: come costrure un’interrogazione
6.6.6
Principali differenze con Jena del livello RDF
Persistenza dei dati. Come già illustrato, la grossa differenza vista a questo
livello è la strategia di archiviazione dei dati. In µJena non esiste, a livello
di risorse, una vera e propria impronta del modello, ma soltanto la rappresentazione a basso livello, ovvero la serializzazione in triple, della conoscenza.
L’obiettivo è quello di ridurre al minimo la richiesta di memoria di lavoro,
anche se questo va ad influenzare le prestazioni generali quando si oltrepassa
una certa dimensione di modello.
Polimorfismo. Quello che in Jena passa sotto il nome di polimorfismo è
un servizio fornito all’utente che mette a disposizione una buona quantità di
metodi in grado di convertire le risorse di tipo in tipo, rispettando opportune condizioni. La scelta di escludere questi servizi deriva da diversi fattori.
Anzitutto dalle gerarchie di classi, che nella J2ME variano, rendendo banali
operazioni di cast dinamico piuttosto complesse e macchinose. In secondo
luogo, la mancanza di una struttura dati persistente in memoria è un fattore
chiave: Jena offre all’utente un utilizzo dinamico dei dati, nel senso che permette di lavorare su determinate risorse, anche qualora non sussistano tutte le
condizioni perché tali risorse siano effettivamente parte del modello. Come già
51
microJena
detto, µJena non tiene risorse a memoria, ma solo le triple che le descrivono;
la mancanza di anche una sola tripla necessaria alla descrizione non permette
di lavorare su una risorsa, in quanto non è concessa la creazione della risorsa
stessa. La strategia di Jena prevede la memorizzazione di dati relativi alle
varie forme che l’utente ha assegnato ad una risorsa e la scelta di eliminare la
funzionalità ha portato a risparmio di memoria e del tempo di elaborazione
dedicato a controllo e istanza delle varie interfacce.
Reasoning. Di nuovo, in Jena esistono diverse implementazioni del modello vero e proprio e diverse organizzazioni dei servizi di ragionamento. A
seconda di quale tipologia di modello è effettivamente istanziata, varia la completezza delle risposte alle query. Come per il reasoning nel grafo, anche il
livello RDF è implementato in un’unica versione, con un’ottimizzazione delle
prestazioni orientata sulla semplicità e il minimo spazio in memoria, studiata
per dare il meglio in modelli relativamente piccoli.
6.7
Il livello OWL
Ultimo e definitivo livello di implementazione è il package che implementa
OWL. Qui sono contenute tutte le interfacce e le implementazioni dei costrutti
OWL, che rendono l’utente in grado di operare pienamente sulla base di conoscenza. Va detto anzitutto che si tratta di un livello completo e fine a se
stesso: la completa gestione dell’ontologia, cosı̀ come creazione, salvataggio e
acquisizione da file o flusso di rete, sono operazioni interamente contenute nel
livello, quindi l’utente ha a disposizione tutto quanto necessario, senza dover
accedere ai sottostanti; dove sono indispensabili metodi sottostanti, è il software stesso ad incaricarsi di interrogare i livelli corretti, rendendo l’operazione
totalmente trasparente all’utente.
Nella figura 6.9 si nota come in realtà OWL contenga tutto quanto specificato in RDF, mantenendo peraltro assolutamente invariate alcune strutture
come il Literal, salvo poi ridefinire ed estendere il concetto di risorsa in una
lunga serie di specializzazioni che saranno affrontate in seguito.
Da notare che si tratta di un grafico UML che fa riferimento alle interfacce
e che quindi prevede l’ereditarietà multipla delle OntProperty; ovviamente ciò
non vale per l’implementazione.
52
6.7 microJena
Figura 6.9: UML del layer OWL
Risulta chiaro dall’UML come OWL in realtà sia completamente dipendente da RDF, in quanto comprende tutti gli elementi già definiti; anche se
OWL sarebbe perfettamente in grado di utilizzare le già definite Resource e
Property, nelle nuove interfacce sono compresi una serie di metodi più avanzati,
oltre ad essere le nuove definizioni un passaggio obbligato per poter utilizzare le
numerose specializzazioni dell’oggetto risorsa che vengono definite. Per quanto
riguarda il Literal e il ReifiedStatement non è stato fatto alcun intervento; le
strutture dati RDFList e Container sono rimaste anch’esse invariate, tuttavia è
ovvio pensare che giunti a questo livello non si occupino di organizzare Literal
o semplici Resource, ma vengano anche utilizzate per gestire le OntResource e
le varie specializzazioni che sono definite nel package.
6.7.1
La OntResource
L’istanza OntResource è generica e di fatto non porta novità a livello concettuale alla già definita Resource di RDF. Quello che viene introdotto è una serie
di metodi di gestione della struttura sottostante. In figura si vede come viene
principalmente suddivisa la risorsa OWL.
Come si vede in figura, sono sei le sottodivisioni della risorsa OWL; alcune
sono a loro volta divise in varie specializzazioni, le classi e le proprietà, altre
53
microJena
Figura 6.10: UML della risorsa di OWL
sono invece già foglie dell’albero: si tratta di AnnotationProperty, Ontology,
DataRange e Individual.
Annotation Property. È una risorsa particolare; si comporta in linea di
massima come una OntProperty, ma viene divisa da quest’ultima per marcare
la netta differenza concettuale che separa i due costrutti: se le OntProperty sono il cardine di un’ontologia, il mezzo che mette in relazione le risorse,
ciò che rende effettivamente una macchina in grado di interpretare una base
di conoscenze, le AnnotationProperty sono delle vere e proprie etichette, un
mezzo per aggiungere commenti human-readable di comodo utili all’utente per
rendere l’ontologia più amichevole all’occhio umano.
Ontology. Rappresenta un’ontologia, non come struttura dati o modello
su cui lavorare, ma come risorsa, ovvero come un oggetto dotato di URI, che
all’interno della base di conoscenze può assumere il ruolo di soggetto o oggetto
di statement; per esempio si può esprimere il fatto che un determinato modello dipenda da una determinata ontologia o importi la conoscenza contenuta
in una base caratterizzata da un certo URI, senza che tale conoscenza sia
effettivamente contenuta nel modello.
DataRange. Fornisce all’utente uno strumento per creare una collezione
di Literal; è un costrutto che contiene dati a livello concreto, ed è utile per
esempio a definire il range di una determinata proprietà, qualora sia necessario
54
6.7 microJena
limitarlo ad una collezione di dati concreti. Nelle ontologie definite in OWL
Full concettualmente cade la differenza tra DataRange e classe. Sintatticamente, un DataRange viene descritto come una lista di Literal: la differenza
con le RDFList sta fondamentalmente nell’interfaccia utente che garantisce la
concretezza dei dati, per esempio evitando che per errore venga inclusa in un
DataRange una risorsa che non sia un Literal.
Individual.
classe.
Rappresenta un individuo specifico appartenente ad una
Non ha particolari implementazioni all’interno, ma più che altro
caratterizza la risorsa di modo che possa essere gestita a dovere dal software.
6.7.2
La OntClass
OWL permette di dichiarare una risorsa di tipo classe in diversi modi: si può
istanziare una classe fine a se stessa, cosı̀ come si possono definire le regole
perché si possa dedurre una classe a partire da risorse già presenti a modello.
Figura 6.11: UML della classe OWL
Le classi semplici. La prima possibilità è intuitivamente la più semplice:
si traduce nel solo Statement
<namespace:classURI @rdf:type owl:Class>
mentre per definire un individuo appartenente alla classe si definisce uno
Statement analogo:
<namespace:individualURI @rdf:type namespace:classURI>.
Le EnumeratedClass. Si tratta di classi definite con una strategia analoga ai DataRange: non avendo a disposizione criteri ben definiti per descrivere
una classe, la si esplicita semplicemente come una lista di individui.
Le classi Booleane. La seconda opzione è quella di descrivere la classe
come una BooleanClass: significa sfruttare gli operatori fondamentali dell’algebra di Boole per definire una classe combinando opportunamente classi già
55
microJena
esistenti: l’operatore AND è rappresentato dalla IntersectionClass, l’OR dalla
UnionClass, e il NOT dalla ComplementClass. Come operatori si possono usare tutte le definizioni di classi, anche le booleane; questo permette di definire
espressioni più complesse, come ad esempio l’intersezione tra una classe semplice A, e una booleana che rappresenti l’unione tra B e C realizzerebbe la classe
[A AND (B OR C)]. Unica differenza tra gli operatori, è che il complemento
accetta un unico termine, mentre l’unione e l’intersezione accettano una lista
di classi.
Figura 6.12: UML delle classi booleane
Le restrizioni. Mentre nella descrizione del linguaggio OWL la restrizione
è un concetto teorico, e si applica a determinate proprietà, la strategia di
implementazione ideale è considerarle come vere e proprie classi; per applicare
una restrizione ad una classe sarà sufficiente dichiararne una sottoclasse.
Figura 6.13: UML delle restrizioni
56
6.7 microJena
La sintassi delle restrizioni ne prevede la codifica in tre Statement; per
una restrizione ns:restriction sulla proprietà ns:property si avrebbero in
comune:
<ns:restriction @rdf:type owl:restriction>
<ns:restriction @owl:onProperty ns:property>
e successivamente, a seconda del tipo di restrizione, per specificare il valore
“10”:
• <ns:restriction @owl.hasValue ‘‘10’’@xsd:integer>
• <ns:restriction @owl.someValuesFrom ‘‘10’’@xsd:integer>
• <ns:restriction @owl.allValuesFrom ‘‘10’’@xsd:integer>
• <ns:restriction @owl.cardinality ‘‘10’’@xsd:integer>
• <ns:restriction @owl.minCardinality ‘‘10’’@xsd:integer>
• <ns:restriction @owl.maxCadinality ‘‘10’’@xsd:integer>
Infine, volendo applicare la restrizione alla classe ns:class, dovremmo
specificare: <ns:class @rdfs:subClassOf ns:restriction>
La gerarchia delle classi è cosı̀ organizzata: supponendo di voler realizzare la
restrizione appena descritta, scegliendo la CardinalityRestriction, si avrebbero
• la classe ns:class che descrive tutti gli individui che le appartengono
• la classe (restrizione) ns:restriction, che descriverebbe una nuova classe, di tutti gli individui, qualunque sia la classe originale
cui appartengono, che hanno cardinalità “10” riguardo la proprietà
ns:property
• definendo ns:class sottoclasse di ns:restriction si va a vincolare il contenuto della classe, in quanto la si costringe a ereditare la caratteristica
della restrizione, ovvero la cardinalità “10” sulla proprietà ns:property
57
microJena
6.7.3
Le OntProperty
Anche le proprietà sono caratterizzate da un’ampia specializzazione. A livello
di implementazione non ci sono differenze sostanziali tra le diverse tipologie; a
seconda della scelta, ci possono essere controlli, come per esempio il fatto che
una ObjectProperty abbia come oggetto una risorsa, e mai un literal. Per il
resto, la grossa differenza è a livello concettuale: avere una proprietà istanziata
come TransitiveProperty serve ai servizi di ragionamento e ai metodi che realizzano le interrogazioni per sapere come trattarla, ed eventualmente dedurre
dalla particolare tipologia di proprietà frammenti di conoscenza impliciti.
In aggiunta a quanto definito in RDF, è ora permesso definire con precisione
dominio e codominio delle proprietà, ovvero precisare, e dunque vincolare, le
categorie di risorse che possono assumere ruolo di soggetto o oggetto negli
statement il cui predicato è la proprietà definita.
Figura 6.14: UML delle propriet in OWL
6.7.4
Le relazione tra Risorse
Un’aggiunta rispetto al livello RDF è costituita da una serie di relazioni tra
le diverse risorse; si tratta in effetti di costrutti formati per lo più da una sola
tripla, che definiscono delle relazioni che sfruttano predicati predefiniti. La
lista completa per le OntResource è:
• owl:differentFrom
• owl:sameAs
58
6.7 microJena
• owl:versionInfo
Per quanto riguarda le OntProperty, si aggiungono:
• owl:equivaltProperty
• owl:inverseOf
In effetti nulla vieta nei livelli precedenti di aggiungere triple che definiscano
tali relazioni, ma è solo nel layer OWL che assumono un significato preciso:
non sono più triple banali, in quanto reasoner e interrogazioni le riconoscono
e sono in grado di trarne importanti informazioni.
6.7.5
Principali differenze con Jena del livello OWL
Le ontologie. Il package che realizza questo layer in Jena comprende diverse
tipologie di ontologie, oltre a OWL, quali per esempio DAML+OIL o RDFS.
Di fatto, µJena limita lo sviluppo al solo linguaggio OWL, seppur conservando
i tre profili Lite, DL, e Full, tagliando completamente le funzionalità al di fuori
delle suddette specifiche; di conseguenza, un primo ovvio taglio sulle risorse
disponibili è stato fatto eliminando tutta la struttura di restrizioni qualificate.
Unicità del modello. Come per i layer precedenti, esiste una sola implementazione del modello di conoscenza con un’unica strategia di archiviazione
ed organizzazione delle risorse.
Input e Output. µJena implementa una interfaccia di input e output
limitata, rispetto a Jena: la differenza sostanziale risiede nella disponibilità
di linguaggi di codifica a disposizione. µJena mette a disposizione la sola
serializzazione nel formato chiamato N-TRIPLE; il motivo è semplice: tale
sintassi è la più lineare disponibile e prevede la codifica esplicita di ciascuna
tripla del modello in un file, escluse le triple che rappresentano gli assiomi, e
quindi come tali sono note al software. Una codifica in XML risulta piuttosto
onerosa da realizzare in output, cosı̀ come da interpretare in input; tuttavia
la scelta è stata mirata a consentire all’utente di aggirare il problema: dato
che il linguaggio N-TRIPLE è riconosciuto e supportato da Jena, qualora fosse
necessario importare una base di conoscenze codificata in XML sarebbe sufficiente il supporto di Jena per la traduzione in N-TRIPLE, che renderebbe di
fatto utilizzabile l’ontologia sui dispositivi portatili.
59
Capitolo 7
Analisi delle prestazioni
L’intera struttura di µJena è nata ed è stata sviluppata con un’unica filosofia:
ridurre al massimo. Soprattutto è stato curato l’aspetto della memoria necessaria, un dato totalmente vincolante e impossibile da aggirare; di contro, una
velocità eccessivamente scarsa può rendere la libreria difficile da utilizzare, ma
pur sempre funzionante, sebbene costi parecchio tempo di esecuzione.
La politica seguita è stata quella di rendere l’architettura il più semplice
possibile, e questo fatto ha influenzato la distribuzione delle prestazioni di
µJena , collassando la resa verso il basso. Avendo evitato qualunque compromesso tra l’overhead in memoria e l’efficienza dei servizi di archiviazione
e ricerca, la libreria migliora la sua efficienza quanto più il modello su cui si
opera è piccolo.
Il risultato della riduzione per quanto concerne lo spazio in memoria è
consistente: µJena misura in tutto 384KB di spazio su disco, circa un quarto
dei vecchi Floppy Disk, mentre Jena occupa 12 MB, più il reasoner che ne
richiede circa altri 4. Il risultato è che µJena richiede soltanto il 2,5% di spazio
in memoria richiesto dalla versione completa per poter operare.
61
microJena
7.1
Confronto diretto con Jena
I seguenti grafici riportano tutti in ascissa la dimensione del grafo espressa in
numero di triple, assiomi compresi, e in ordinata il tempo necessario. Il primo
grafico (figura 7.1) mostra le prestazioni nella popolazione e interrogazione del
modello, partendo dalla creazione di un’ontologia vuota, e via via aggiungendo
risorse:
Figura 7.1: microJena vs Jena
Il secondo grafico in figura 7.2 mette in evidenza il rapporto di prestazioni
tra Jena e µJena : come si può vedere, µJena dà il meglio nei piccoli modelli,
pagando la sua semplicità man mano che le dimensioni aumentano.
Andando ad esaminare il comportamento asintotico delle prestazioni per
modelli di dimensioni veramente grandi, tuttavia, si nota che il rapporto tra
le prestazioni di µJena e quelle di Jena diventa lineare, assestandosi a circa un
quinto, a pari supporto hardware; considerando che le risorse a disposizione
sono molto ridotte, rispetto a quelle su cui fa affidamento Jena, aver realizzato
una libreria J2ME che al peggio richiede 5 volte il tempo di elaborazione, si
può considerare un risultato soddisfacente.
62
7.2 microJena
Figura 7.2: Rapporto tra le prestazioni
7.2
Tempi di elaborazione su telefono cellulare
Se i test precedenti vedevano entrambe le librerie Jena e µJena a confronto
sullo stesso hardware, quindi un personal computer, i successivi si riferiscono
a µJena effettivamente operativa su un telefono cellulare.
I prossimi grafici mostrano il tempo di esecuzione di µJena per portare a
termine singole istruzioni elencate in legenda; su ascissa è espressa la dimensione del modello sul quale viene testata la singola operazione, in ordinata
il tempo di esecuzione in millisecondi. Non ha senso operare questi test in
parallelo con Jena, in quanto l’influenza della struttura dati differente è incolmabile: infatti si va a calcolare il tempo che µJena impiega a interrogare il
modello e costruire le risposte, mentre Jena ha già a disposizione le risorse in
memoria e non fa altro che girarle all’utente. Obiettivo dei due grafici seguenti
è mostrare quanto per la maggior parte delle richieste µJena sia in grado di
garantire tempi di elaborazione ben inferiori al secondo. Il primo grafico (figura
7.3) mostra l’andamento di 5 funzioni chiave: una creazione, una rimozione,
due interrogazioni di diverso tipo e un’interrogazione su tutti gli statement che
rispettino un determinato pattern.
Il secondo grafico (figura 7.4) mostra invece le due operazioni che risultano
più onerose a µJena da portare a termine, ovvero elaborare la lista delle classi
63
microJena
Figura 7.3: Prestazioni sulle funzioni più comuni
e degli individui; il grafico riporta anche le curve del grafico precedente, come
termine di paragone.
64
7.3 microJena
Figura 7.4: Prestazioni su tutte le funzioni
7.3
Interpretazione dei risultati
Si nota come i test sintetici operati direttamente su dispositivo portatile non
siano del tutto chiari e consistenti. Il motivo principale è la capacità di elaborazione dell’hardware. Anzitutto va detto che includere nel software un tool
che calcoli il tempo di elaborazione preciso al millisecondo è un’operazione
onerosa che incide fino al 10% sulle prestazioni stesse. Inoltre si nota come
a tratti le curve subiscano dei salti poco verosimili; questa discontinuità dei
risultati è da attribuire alla politica di gestione dei thread della J2ME, che non
sempre riesce a garantire una buona emulazione del parallelismo di esecuzione
tra µJena e il tool che calcola i tempi di elaborazione.
65
Capitolo 8
Conclusioni
Il risultato ottenuto è un software funzionante con caratteristiche che ben si
adattano ai dispositivi portatili, e tuttavia dotato di un insieme di operazioni
supportate che lo rendono ben sfruttabile.
Analizzando uno per uno gli obiettivi che stavano alla base del lavoro, si
possono trarre importanti conclusioni.
Spazio in memoria. Il primo grande successo è la dimensione ridotta
della libreria: come già anticipato, Jena pesa 12 MegaByte, più 4 MegaByte
di reasoner; µJena conta soltanto 384 KiloByte di spazio su disco: il rapporto
totale è un quarantesimo della memoria richiesta dalla libreria madre. Un’analisi del mercato ci porta a trovare sempre più dispositivi dotati di lettore di
memoria flash in grado di concentrare fino a migliaia di MegaByte in pochi
centimetri, e soprattutto in pochi euro. Tuttavia si tratta per ora ancora soltanto di dispositivi di fascia almeno medio-alta del mercato; installare µJena in
una memoria rimovibile significherebbe perderne le funzionalità non appena si
cambia supporto: l’opportunità di installarla sulla piccola memoria on-board
del cellulare ha la comodità di avere tutte le funzionalità sempre a disposizione.
Velocità di esecuzione. Il lavoro, più che massimizzare le prestazioni,
è stato stravolgere l’architettura di Jena. Il motivo è che non esiste un software di riferimento: non si hanno ancora a disposizione strumenti per stabilire
quale fascia di utilizzo possa avere µJena in futuro; il dato determinante, che
influisce maggiormente sulle prestazioni, è la dimensione del modello e per ora
si possono fare solo previsioni su quali saranno le dimensioni tipiche utilizzate
sui dispositivi portatili.
L’architettura di µJena , come si è visto nel paragrafo sulle prestazioni,
67
microJena
riesce ad essere più efficiente fino alla dimensione critica di circa quattromila
triple: al di sotto di questo limite µJena si dimostra più rapida nella gestione
concreta dei dati, mantenendo tempi di risposta alla maggior parte delle interrogazioni sostenibili; per ora si tratta di un successo, di una dimensione che
facilmente coprirà tutti i domini di utilizzo della libreria. Tuttavia, un altro
punto di forza è che µJena non contiene alcun compromesso nella struttura
del codice: tutto è collassato al minimo, offrendo una filosofia opposta a quella
di Jena, e in sostanza un riferimento: considerando µJena come punto di partenza, e Jena come punto di arrivo, qualunque si rivelerà il dominio principale
di utilizzo sui dispositivi portatili, si avranno già le basi per poter sviluppare
un’architettura che sia la giusta via di mezzo e che possa sfruttare quelle che
dimostreranno di essere nello specifico le strategie di organizzazione dei due
software.
Retrocompatibilità. Si tratta probabilmente del più grande punto forte
di µJena : il codice scritto per Jena risulta totalmente retrocompatibile. Questo vale, sia chiaro, per le sole funzioni mantenute in essere della libreria madre,
ma con un’affermazione più forte si può confermare che tale caratteristica vale
per tutte e sole le funzioni implementate.
Questa qualità elimina le barriere all’ingresso per chi si affaccia all’utilizzo
di µJena : non serve studiare il linguaggio, le classi, i metodi, ma semplicemente applicare la medesima sintassi di Jena; per il programmatore abituato
a lavorare con le ontologie, passare a lavorare con µJena richiede uno sforzo
minimo e, anzi, apre la porta verso il mercato del software J2ME.
Un punto che invece non era ritenuto fondamentale ma che, vista la caratteristica appena affrontata, a maggior ragione si rivela valido, è la retrocompatibilità in senso opposto: qualunque riga di codice, qualunque istruzione
sia nata per µJena è totalmente portabile in Jena stessa. Trattandosi di un
insieme di funzioni interamente contenuto in quelle della libreria madre, vi è
totale garanzia che il trasferimento di algoritmi nati per il settore mobile siano
compatibili ed eseguibili su un personal computer.
68
Appendici
69
Appendice A
Indicazioni per gli sviluppatori
Dopo aver avuto una visione di come la libreria è stata sviluppata e su quali
fondamenta essa si basa, sono necessarie delle indicazioni riguardanti il futuro
di questo progetto. Ovviamente il lavoro svolto si può considerare solo il primo
passo verso la realizzazione di un prodotto che mira a portare sui dispositivi
mobili un tappeto di funzionalità volte a supportare lo sviluppo del WebSemantico. Pur essendo funzionante, e con caratteristiche che la rendono unica,
durante lo stesso lavoro sono sorte delle ipotesi circa possibili miglioramenti
per rendere più completo il framework creato.
A.1
Evoluzione delle prestazioni
Si può considerare la prima release funzionante di µJena un software pioniere,
a suo modo innovativo nel suo genere; la prima versione realizzata comprende
un’architettura volta a stravolgere l’organizzazione di Jena, portando il dominio di utilizzo in cui è in grado di dare il meglio di se molto verso il basso.
Questo ha portato ad avere un primo termine di paragone tra quella che è l’implementazione per personal computer e quello che è il minimo indispensabile
per gestire un’ontologia.
Il vantaggio dell’architettura di µJena , come si vede dai grafici (vedi figure
7.1 e 7.2), si estende per tutti i modelli di dimensioni non maggiori di 4000
triple: un’ontologia di tutto rispetto. Inoltre l’andamento logaritmico della
curva ci permette di spingerci oltre senza pagare eccessivamente in termini di
tempo: gestire un modello di dimensione doppia, 8000 triple, costa in termini
di tempo meno del doppio della precedente ontologia da 4000 statement.
71
microJena
In linea teorica, sarebbe possibile intervenire sul modello affinché la curva
delle prestazioni di µJena si appiattisca sempre più, fino ad arrivare pari a Jena
stessa; quello che per ora manca è un dominio di utilizzo: non esiste nessun
software che possa sfruttare la libreria, in quanto la libreria stessa è la prima
a permettere tali operazioni su piattaforma J2ME.
La dimensione di 4000 triple copre di gran lunga il dominio di operazioni
che si può prospettare verranno sviluppate su un telefono cellulare, ma bisogna tenere conto dell’inarrestabile evoluzione dei supporti: sarà sicuramente
necessario del tempo prima che effettivamente qualche software possa essere
distribuito ed effettivamente utilizzare µJena ; solo allora sarà possibile testare
la potenza di calcolo dell’hardware, che nel frattempo avrà fatto grandi passi
in avanti dal punto di vista delle prestazioni; oggi dobbiamo fare i conti con
semplici previsioni. Già al giorno d’oggi sono sempre più i telefoni cellulari
dotati di memorie flash rimovibili: dovesse rivelarsi questo lo standard, si
vedrebbe aumentare l’idea di memoria ( pochi megabyte disponibili fino poco
tempo fa ) a supporti dell’ordine di grandezza del gigabyte e del costo di
pochi euro. Verrebbe a mancare uno dei principali punti alla base dello studio
dell’architettura: veder cadere i limiti di memoria potrebbe portare la libreria
verso un’evoluzione pronta a sacrificare diversi megabyte per la causa della
velocità di elaborazione, grazie ad una più strutturata organizzazione dei dati
in memoria, per esempio all’interno di una cache persistente di risorse.
Si nota dai grafici come ci siano delle operazioni che mettono in crisi il
software: si tratta di operazioni che portano con sé una complessità intrinseca,
e non eliminabile se non stravolgendo l’architettura; un’operazione che costerebbe sicuramente in termini di spazio in memoria, e che farebbe leggermente
tendere la curva di µJena verso quella di Jena. Se dovesse rivelarsi però che
operazioni come listIndividuals o listClasses debbano essere interpellate
di frequente, sarebbe un passo obbligato intervenire, magari implementando
una piccola cache, o ad ogni modo, come linea guida generale, apportare modifiche mirate a migliorare la risposta di particolari operazioni ad oggi molto
costose.
72
A.2 microJena
A.2
Possibili aggiunte e migliorie
Come già anticipato, allo stato attuale, non esiste ancora un dominio concreto
di utilizzo; per ora ci si pone in una fase di sperimentazione e sviluppo. Questo fatto, come ci si può ben immaginare, influirà sui requisiti dei software che
verranno sviluppati in futuro nell’ambito del Websemantico e, di conseguenza,
le librerie sulle quali poggiano i software dovranno evolversi secondo le nuove
necessità che sorgeranno. Sicuramente il lavoro che è stato svolto crea una
piattaforma che rende disponibili tutti i costrutti necessari per gestire un’ontologia o le risorse al suo interno; nuove necessità però potrebbero sorgere e
indicare una via per eventuali sviluppi.
D’altra parte, avendo già un punto di riferimento quale Jena, si possono
effettuare delle ipotesi molto concrete per estendere la libreria; tutto ciò senza
dimenticare lo stato dei dispositivi attuali: le capacità di elaborazione dello
standard dei telefoni cellulari hanno reso complicata la creazione del nostro
software; di conseguenza, prima di allargare le funzionalità della libreria, bisogna valutare le risorse che sono a disposizione. Detto ciò, il primo completamento da effettuare potrebbe essere il supporto in lettura e scrittura per
OWL in forma canonica: in questo momento è disponibile solo il servizio di
input/output attraverso la visualizzazione detta N-TRIPLE (vedi C.1) poiché
un algoritmo per generare e codificare la forma XML risulta molto dispendioso
e pesante per i dispositivi.
Altre espansioni alla libreria da sviluppare derivano direttamente da ciò
che è stato eliminato o modificato dal framework di riferimento Jena. Un
esempio è il servizio di reasoning: piccole deduzioni logiche e ragionamenti
base potrebbero risultare, almeno in parte, realizzabili; comunque è importante
non dimenticare delle possibilità che ci sono offerte attraverso il DIG-Reasoning
(vedi 6.4.5) e di conseguenza valutare concretamente se il valore aggiunto che
potrebbe generarsi da un certo tipo di lavoro sia effettivamente utile.
Inoltre un aspetto che non è stato ereditato è la possibilità di creare differenti strutture dati a seconda del tipo di modello da voler istanziare: la scelta è
stata per lo più di semplificare e creare un solo tipo di modello ontologico, ma
una possibile soluzione può essere la generazione diversi schemi a seconda, per
esempio, del numero di triple che sono presenti nel modello. Un’evoluzione in
questo senso può far sorgere miglioramenti a livello di prestazioni e la creazione
73
microJena
di diversi algoritmi di ricerca che snelliscano in modo rilevante l’interrogazione
del modello.
Queste soluzioni, che sono solo alcuni esempi, sono da contestualizzare a
seconda delle prestazioni dei dispositivi mobili, telefoni cellulari come caso
pessimo in questo momento, e dall’evoluzione che il contesto del WebSemantico porterà con sé: una scelta che non tenga presente queste considerazioni
difficilmente risulterà utile e concretamente applicabile.
74
Appendice B
Manuale utente
µJena è sostanzialmente una libreria JAVA che mette a disposizione gli
strumenti per lo sviluppo di ontologie OWL su dispositivi mobili.
La libreria si ispira per struttura gerarchica e modalità di utilizzo quasi
completamente al famoso framework Jena. Per chi ha già utilizzato o utilizza
Jena l’uso della nostra libreria risulterà immediatamente semplice e intuitivo,
e addirittura, se l’utente è uno sviluppatore di software, potrà trovare una
compatibilità quasi completa con il lavoro già svolto con Jena.
Riassumendo il nostro software offre la possibilità di creare, leggere, stampare e modificare ontologie OWL, tutto in linea con le possibilità e le interfacce
usate nei cellulari che hanno inserita la J2ME. Il dominio nel quale questo prodotto è stato definito è soprattutto OWL, quindi, pur ammettendo l’utilizzo
di costrutti RDF e modalità di presentazione delle ontologie diverse da quella
standard di OWL (ad esempio N-TRIPLE), non assicuriamo un funzionamento
totale per quanto riguarda richiami a elementi diversi da quelli che possiamo
trovare in OWL. Ovviamente tutto ciò può rivelarsi futile alla luce di futuri
sviluppi e aggiornamenti.
B.1
Requisiti minimi
Per eseguire la libreria µJena è sufficiente un dispositivo con installata la configurazione CLDC 1.1 (vedi capitolo 4.2.1). È indifferente quale sia il profilo a
disposizione in quanto l’intero codice esclude qualsiasi interfaccia grafica.
75
microJena
Ad ogni modo µJena si attiene alle specifiche dell’MSA (vedi capitolo
4.3), in particolare è sufficiente il Subset; in questo modo viene garantita la
portabilità tra dispositivi eterogenei.
La memoria necessaria per l’installazione è di 384 KB, mentre è prematura
una stima sulla memoria di lavoro consigliata, in quanto non è ancora ben
definito un dominio di utilizzo del software.
B.2
Installazione e configurazione
Per poter utilizzare la nostra libreria nelle proprie applicazioni è semplicemente
necessario inserire il nostro file JAR (microjena.jar) nelle librerie che vengono
utilizzate dal proprio programma.
Se si utilizza NetBeans come ambiente di sviluppo, per esempio, è sufficiente
entrare nella schermata di configurazione del progetto, raggiungere la sezione
librerie, e aggiungere il nostro file .jar come mostrato nella figura.
Figura B.1: primo passo
76
B.3 microJena
Figura B.2: secondo passo
In questo modo siete pronti ad utilizzare gli strumenti che abbiamo messo
a disposizione per maneggiare le ontologie OWL.
Per coloro che vogliono convertire il loro lavoro fatto con Jena in un software compatibile con l’ambiente mobile (sempre che l’applicazione scritta sia
predisposta per la J2ME) basta che l’utente cambi gli import delle librerie
da com.hp.hpl.jena in it.polimi.elet.contextaddict; il tutto dovrebbe
risultare funzionante.
L’unica nota riguarda gli Iterator: purtroppo la J2ME non fornisce iteratori e quindi li abbiamo implementati in questa stessa libreria; per chi usa nel
proprio ambiente di sviluppo software già una configurazione “mobile” (es. Wireless ToolKit) non ci risultano problemi poiché gli iteratori vengono recuperati
direttamente dalla nostra libreria; chi sviluppa invece senza una configurazione
per la J2ME potrebbe riscontrare incompatibilità tra le chiamate agli iteratori. La soluzione è di eliminare dalle import la classe java.util.iterator e i
problemi dovrebbero essere risolti.
B.3
Creare un’ontologia
Per agevolare la comprensione, si utilizzeranno in questa sezione esempi pratici
nati esclusivamente a scopo didattico.
Prima di iniziare a creare un’ontologia bisogna decidere in quale linguaggio
essa deve essere definita. Come già accennato il software è stato creato per
77
microJena
OWL, però un passo importante è una corretta scelta tra le forme di OWL da
utilizzare (Lite, DL, FULL): questa decisione ovviamente potrebbe vincolare
l’utilizzo di determinati costrutti.
Il primo passo concreto è la creazione di un Modello: deve essere istanziato
a seconda del linguaggio scelto precedentemente, nell’esempio useremo OWL
DL; é importante la creazione del modello poiché quasi tutte le operazione da
compiere vengono effettuate dall’istanza di esso.
OntModel m;
m = ModelFactory.createOntologyModel(ProfileRegistry.OWL DL LANG);
Per agevolare la composizione dell’ontologia è importante scegliere e
settare un NameSpace per il modello creato, ciò permetterà di dare alla
propria ontologia un URI ben definito. In questo modo in capo all’ontologia
avrò la definizione del namespace scelto http://myOntology.com/calcio.owl#:
String ns = ‘‘http://myOntology.com/calcio.owl#’’;
m.setNsPrefix(‘‘myOn’’, ns);
La creazione della classe necessita un URI identificativo (utilizzando il
namespace che è già stato settato) se si vuole creare una classe ben definita, in
caso contrario esiste la possibilità di creare anche classi anonime che saranno
identificate tramite un codice numerico sequenziale.
OntClass c1 = m.createClass(ns + ‘‘Campionato’’);
Alla stessa classe si possono aggiungere sottoclassi o super classi a secondo
di come vanno definiti gli elementi dell’ontologia. Per esempio aggiungiamo
la sottoclasse di Campionato ‘‘PrimaSerie’’; oppure si può creare la classe
‘‘SecondaSerie’’ e settare come propria sopra-classe “Campionato”.
OntClass c2 = m.createClass(ns + ‘‘PrimaSerie’’);
c1.addSubClass(c2);
OntClass c3 = m.createClass(ns + ‘‘SecondaSerie’’);
c3.addSuperClass(c2);
78
B.3 microJena
Inoltre si può imporre la disgiunzione o l’equivalenza tra diverse classi, nell’
esempio imponiamo la disgiunzione tra la classe PrimaSerie e SecondaSerie
c2.addDisjointWith(c3);
Inoltre è consentito impostare la gerarchia attraverso il comando “set”:
questo cancella tutte le relazioni dello stesso grado impostate e la setta come
unica. In questo caso l’unica Sopra-classe di SecondaSerie (c3) è Campionato.
La stessa operazione è possibile farla con le sotto-classi, le disgiunzioni e le
uguaglianze.
c3.addSuperClass(m.createClass(ns+‘‘ClasseProvvisoria1’’));
c3.addSuperClass(m.createClass(ns+‘‘ClasseProvvisoria2’’));
c3.setSuperClass(c1);
Successivamente è possibile creare le proprietà che gestiscono delle relazioni
tra le varie classi. Creiamo una proprietà HaIscritti.
OntProperty p1 = m.createOntProperty(ns + ‘‘HaIscritti’’);
e come per le classi, si possono imporre le relazioni gerarchiche tra le
proprietà. Si possono aggiungere infatti sotto-proprietà o sopra-proprietà.
Sempre per quanto riguarda le proprietà, si può impostare ovviamente
il dominio e il codominio.
suddivisione tra le proprietà.
In questo caso si viene incontro alla prima
Se il codominio è una classe definita dal
nostro modello abbiamo delle ObjectProperty: impostiamo come dominio
di HaIscritti la classe Campionato e come codominio, dopo averla creata, la
classe ‘‘Squadra’’.
p1.addDomain(c1);
OntClass c4 = m.createClass(ns+‘‘Squadra’’);
p1.addRange(c4);
Se il codominio di una proprietà è un dominio concreto (per esempio
79
microJena
parole o numeri) allora la proprietà è di tipo Datatype. Creiamo la proprietà
Datatype ‘‘FondataNellAnno’’ con dominio Squadra e codominio il dominio
concreto degli interi.
DatatypeProperty p3 = m.createDatatypeProperty(ns+‘‘FondataNellAnno’’);
p3.addDomain(c4);
p3.addRange(XSD.integer);
Per quanto riguarda le ObjectProperty si può impostare la relazione di
“inverso” tra una proprietà e l’altra (dominio e codominio invertiti). Per
esempio è possibile creare la proprietà ‘‘Iscritta AlTorneo’’ che è definita
come la proprietà inversa di HaIscritti.
ObjectProperty p2 = m.createObjectProperty(ns+‘‘IscrittaAlTorneo’’);
p2.addInverseOf(p1);
Un’altra importante operazione che si può compiere è creare delle classi
attraverso le restrizioni sulle proprietà. Si vuole definire la classe Squadra
come l’insieme composto dagli elementi che rispondono alla qualità di
avere almeno undici giocatori.
Quindi si crea la classe ‘‘Giocatore’’ e
la proprietà ‘‘CompostaDa’’ con dominio Squadra e codominio Giocatore,
successivamente si crea la restrizione sulla proprietà CompostaDa con un
minimo di relazioni uguale a undici. Come ultimo si imposta la sussunzione
tra la restrizione creata e la classe Squadra.
OntProperty p4 = m.createObjectProperty(ns+‘‘CompostaDa’’);
OntClass c5 = m.createClass(ns+‘‘Giocatore’’);
p4.addDomain(c4);
p4.addRange(c5);
MinCardinalityRestriction r1 = m.createMinCardinalityRestriction(null,
p4, 11);
c4.addSubClass(r1);
Affinchè le restrizioni siano più chiare aggiungo un esempio con una
relazione diversa.
80
Si definisce che è necessario per una squadra vincente
B.3 microJena
(‘‘SquadraVincente’’) che abbia vinto almeno un campionato di prima
serie.
OntClass c6 = m.createClass(ns+‘‘SquadraVincente’’);
c4.addSubClass(c6);
ObjectProperty p5 = m.createObjectProperty(ns+‘‘HaVinto’’);
p5.addDomain(c4);
p5.addRange(c1);
SomeValuesFromRestriction r2 = m.createSomeValuesFromRestriction(null,
p5, c2);
r2.addEquivalentClass(c6);
Un elemento importante definito dai costrutti di OWL è l’individuo. Per
ogni risorsa si può definire uno o più individui, ovvero l’estensione della
classe per come le abbiamo generate. Si può creare, per esempio, l’individuo
‘‘PremierLeague’’ come istanza della classe PrimaSerie; inoltre si possono
generare quante istanze si desidera.
Nulla ci impedisce di creare anche
l’individuo ‘‘serieATIM’’ sempre per la stessa classe.
Individual i1 = m.createIndividual(ns+‘‘premierLeague’’,c2);
Individual i2 = m.createIndividual(ns+‘‘serieATIM’’,c2);
Agli individui si possono associare le relazioni definite dalle proprietà.
Dopo aver creato l’individuo ManchesterUtd come istanza di SquadraVincente
si può impostare che il ManchesterUtd abbia vinto il proprio campionato
(Premier League)
i3.addProperty(p5,i1);
Inoltre è possibile creare classi come risultato da operazioni booleane tra
di esse, ma nel nostro modello non sono presenti. Per concludere il modello, si dovrebbero creare molti più individui, come per esempio i calciatori, e
impostare le disgiunzioni tra le classi.
81
microJena
B.4
Input e output
Le operazioni consentite di lettura e scrittura si basano costantemente sull’istanza del modello che abbiamo creato. Se vogliamo visualizzare l’ontologia
prodotta si può ricorrere alla chiamata del metodo “write” presente nel modello
(m.write(System.out, ‘‘N-TRIPLE’’)); tale metodo permette di scegliere
l’output sul quale si vuole l’ontologia (file o stream) e il linguaggio con la quale
deve essere visualizzata (nell’esempio N-TRIPLE).
Per importare invece un modello già creato è possibile utilizzare una chiamata che fa riferimento al modello e, simmetricamente a come funziona l’output, necessita dello stream in ingresso e del linguaggio con il quale questo è
stato definito per funzionare.
82
Appendice C
Rappresentazione delle
ontologie OWL
C.1
N-TRIPLE
<calcio:HaVinto> <rdfs:domain> <calcio:Squadra> .
<calcio:HaVinto> <rdf:type> <owl:ObjectProperty> .
<calcio:HaVinto> <rdfs:range> <calcio:Campionato> .
<calcio:serieA TIM> <rdf:type> <calcio:PrimaSerie> .
<calcio:manchesterUtd> <rdf:type> <calcio:SquadraVincente> .
<calcio:manchesterUtd> <calcio:HaVinto> <calcio:PremierLeague> .
<calcio:SquadraVincente> <rdfs:subClassOf> :X5fXX3aXA1 .
<calcio:SquadraVincente> <rdfs:subClassOf> <calcio:Squadra> .
<calcio:SquadraVincente> <rdf:type> <owl:Class> .
<calcio:Squadra> <rdf:type> <owl:Class> .
<calcio:Squadra> <owl:disjointWith> <calcio:Giocatore> .
<calcio:Squadra> <owl:disjointWith> <calcio:Campionato> .
<calcio:Squadra> <rdfs:subClassOf> :X5fXX3aXA2 .
<calcio:Squadra> <rdfs:subClassOf> <owl:Thing> .
<calcio:Giocatore> <rdf:type> <owl:Class> .
<calcio:Giocatore> <owl:disjointWith> <calcio:Squadra> .
<calcio:Giocatore> <owl:disjointWith> <calcio:Campionato> .
<calcio:SerieB TIM> <rdf:type> <calcio:SecondaSerie> .
<calcio:Campionato> <owl:disjointWith> <calcio:Squadra> .
<calcio:Campionato> <owl:disjointWith> <calcio:Giocatore> .
<calcio:Campionato> <rdf:type> <owl:Class> .
:X5fXX3aXA1 <rdf:type> <owl:Restriction> .
:X5fXX3aXA1 <owl:onProperty> <calcio:HaVinto> .
:X5fXX3aXA1 <owl:someValuesFrom> <calcio:PrimaSerie> .
83
microJena
<calcio:PrimaSerie> <rdf:type> <owl:Class> .
<calcio:PrimaSerie> <owl:disjointWith> <calcio:SecondaSerie> .
<calcio:PrimaSerie> <rdfs:subClassOf> <calcio:Campionato> .
<calcio:HaIscritti> <owl:inverseOf> <calcio:IscrittaAlTorneo> .
<calcio:HaIscritti> <rdfs:range> <calcio:Squadra> .
<calcio:HaIscritti> <rdfs:domain> <calcio:Campionato> .
<calcio:HaIscritti> <rdf:type> <owl:ObjectProperty> .
<http://www.myontologies.com/calcio.owl> <rdf:type> <owl:Ontology> .
<calcio:Kaka> <rdf:type> <calcio:Giocatore> .
<calcio:CompostaDa> <rdf:type> <owl:ObjectProperty> .
<calcio:CompostaDa> <rdfs:domain> <calcio:Squadra> .
<calcio:CompostaDa> <rdfs:range> <calcio:Giocatore> .
<calcio:HaCognome> <rdfs:domain> <calcio:Giocatore> .
<calcio:HaCognome> <rdf:type> <owl:DatatypeProperty> .
<calcio:HaCognome> <rdfs:range> <xsd:string> .
<calcio:FondataNellAnno> <rdfs:domain> <calcio:Squadra> .
<calcio:FondataNellAnno> <rdf:type> <owl:DatatypeProperty> .
<calcio:FondataNellAnno> <rdfs:range> <xsd:int> .
:X5fXX3aXA2 <rdf:type> <owl:Restriction> .
:X5fXX3aXA2 <owl:onProperty> <calcio:CompostaDa> .
:X5fXX3aXA2 <owl:minCardinality> ‘‘11’’^^<xsd:int> .
<calcio:IscrittaAlTorneo> <rdfs:domain> <calcio:Squadra> .
<calcio:IscrittaAlTorneo> <rdf:type> <owl:ObjectProperty> .
<calcio:IscrittaAlTorneo> <owl:inverseOf> <calcio:HaIscritti> .
<calcio:IscrittaAlTorneo> <rdfs:range> <calcio:Campionato> .
<calcio:PremierLeague> <rdf:type> <calcio:PrimaSerie> .
<calcio:SecondaSerie> <rdfs:subClassOf> <calcio:Campionato> .
<calcio:SecondaSerie> <owl:disjointWith> <calcio:PrimaSerie> .
<calcio:SecondaSerie> <rdf:type> <owl:Class> .
84
C.2 microJena
C.2
Versione grafica
Tratta dal software GrOWL http://home.dei.polimi.it/arrigoni/GrOWL/
Figura C.1: Rappresentazione grafica dell’ontologia
85
microJena
C.3
86
Forma XML
C.3 microJena
87
Appendice D
Licenza
Il software µJena è coperto dalla licenza GNU General Public License, comunemente nota
come GPL.
Di seguito è riportato un breve disclaimer della licenza stessa, mentre il testo completo
è reperibile alla pagina http://www.gnu.org/licenses/gpl.html
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ‘‘AS IS’’ AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
89
BIBLIOGRAFIA
Bibliografia
[1] W3C. OWL Web Ontology Language. http://www.w3.org/TR/owl-features/, 2004.
[2] W3C. RDF Vocabulary Description Language. http://www.w3.org/TR/rdf-schema/,
2004.
[3] Jena. Jena - A Semantic Web Framework for Java. http://jena.sourceforge.net/ .
[4] W3C. Semantic Web. http://www.w3.org/2001/sw/, 2001.
91