µ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
Documenti analoghi
SEMANTIC WEB
relazioni
à tipicamente gerarchie di tipo padre/figlio
à la ricerca di un termine ha successo solo se si