In questo secondo articolo della serie andremo ad analizzare alcune tecnologie per accedere, recuperare e gestire le informazioni modellate su ontologie OWL/RDF. L‘analisi comprende per questo articolo il linguaggio standard per l‘interrogazione SPARQL e l‘uso di API di programmazione mentre lasceremo al numero successivo l‘inferenza tramite reasoner e l‘accesso tramite piattaforme middleware semantiche.
Introduzione
Immaginiamo di tornare bambini di dieci anni e di avere per le mani una bella enciclopedia specializzata sugli animali preistorici (adoravo i dinosauri!). Possiamo sfogliare rapidamente l’indice e guardarne le figure per capire quali argomenti affronta, ma possiamo anche leggerne in maniera approfondita il contenuto e estrapolarne le informazioni utili per la nostra ricerca di quinta elementare.
La stesse possibilità le avremmo vent’anni dopo con una ontologia. Visualizzarne la tassonomia e navigarla tramite i tool generici visti nel numero precedente di questa serie corrisponde alla prima possibilità (indice e figure… lettura superficiale) mentre interrogarla, recuperare le informazioni e aggregarle in base alle nostre necessità coincide esattamente con la seconda eventualità… magari sempre per fare la stessa ricerca di quinta elementare!
Uno dei macro-vantaggi derivanti dall’uso di ontologie sta nella semplicità di pubblicazione delle informazioni su web (semplici file XML) facilmente fruibili da utenti o applicazioni/servizi che ne possono poi estrapolare i dati secondo la loro logica di business. Esistono quindi vari modi per accedere e recuperare informazioni da ontologie OWL/RDF. Lo standard W3C per esempio prevede un linguaggio chiamato SPARQL che, un po’ come SQL per i database, permette interrogazione e recupero di informazioni da ontologie tramite query tipo SELECT – FROM – WHERE. Un’altra possibilità è lavorare direttamente sull’ontologia usando API di programmazione ossia librerie come le OWL-API o JENA (specifiche per un certo linguaggio) che permettono di manipolare, interrogare ed eventualmente salvare l’ontologia modificata. Esiste poi un livello più alto, che potremmo definire “dei servizi”, in cui l’accesso, il recupero e l’aggregazione delle informazioni avviene sfruttando l’inferenza logica con un reasoner + regole semantiche o ancora tramite una piattaforma middleware semantica estendibile come OpenAnzo che prevede l’archiviazione delle informazioni, la gestione degli accessi, il versioning e la possibilità di utilizzare un ESB per garantire l’interoperabilità fra applicazioni semantiche diverse. Di queste ultimo “livello” ci occuperemo nel prossimo numero.
Concetti base delle ontologie OWL
Prima di esaminare nel dettaglio alcune delle tecnologie per il recupero di informazioni semantiche, può essere utile ricordare brevemente quali siano i costrutti e i concetti base utilizzati per modellare ontologie rispetto lo standard W3C OWL.
Classi
Rappresentano insiemi di oggetti (istanze) accomunati da un certa concettualizzazione. Hanno un nome, una label delle di proprietà che le caratterizzano e sono organizzate in strutture gerarchiche chiamate tassonomie. Le classi sfruttano il principio dell’ereditarietà (un po’ come in Java) e possono essere fra loro “equivalenti” nel caso tutte le istanze di una siano anche le istanze dell’altra o “disgiunte” nel caso non vi siano istanze in comune. Di fatto le classi sono gli elementi principali per descrivere i concetti e definire il vero e proprio modello di una ontologia e possono essere viste come i nodi di un grafo orientato.
Proprietà
Sono relazioni binarie definite a partire da una classe dominio. A seconda del codominio possono essere di tipo DataType o Object. Le prime legano una classe a un valore di tipo datatype (stringa, URL, numerico etc…) mentre le seconde legano una classe a un’altra e rappresentano di fatto gli archi di un grafo orientato. Anche le proprietà possono essere organizzate in maniera tassonomica e possono essere di vario tipo a seconda del tipo di relazione che modellano: functional, simmetriche, transitive etc…
Istanze (individuals)
Sono gli elementi degli insiemi definiti dalle classi. In una ontologia i valori veri e propri su cui solitamente effettuare delle query sono appunto istanze. Le ontologie OWL ammettono istanze di classi diverse (purchè non siano classi disgiunte) in modo da ereditare l’unione delle proprietà delle classi.
Restrizioni
Le restrizioni sono vincoli che è possibile esplicitare sulle proprietà di una certa classe e servono per caratterizzarne ulteriormente le relazioni e restringere i possibili valori di una proprietà. È possibile per esempio definire restrizioni come hasValue per fissare un valore di una proprietà, someValueFrom per asserire che almeno un valore deve essere di un certo tipo (classe) o allValuesFrom per asserire tutti i valori devono essere di un certo tipo.
SQL per le ontologie? SPARQL
SPARQL [SPARQL] è il linguaggio standard W3C per interrogare grafi RDF rispetto triple pattern matching. Una tripla RDF infatti è sempre qualche cosa del tipo:
soggetto | predicato | oggetto |
id1234 | anno | 1994 |
I triple pattern usati da SPARQL sono quindi triple del tipo:
?titolo | cd:autore | ?autore |
dove al posto di soggetto, predicato e oggetto è possibile sostituire una variabile (denotata dal punto interrogativo). Nell’esempio viene ricercato un qualunque titolo che abbia come autore un qualunque autore.
Nota: è possibile anche esplicitare una tripla di sole variabili. Per esempio: ?subject ?predicate ?object denota una qualunque tripla.
La sintassi di una query SPARQL è derivata direttamente da quella per l’interrogazione dei database SQL anche se la semantica differisce in molte parti. Per comprendere meglio il funzionamento del linguaggio iniziamo subito ad esaminare i costrutti principali tramite degli esempi.
SELECT
Consideriamo la seguente query SPARQL:
PREFIX foaf: <http://xmlns.com/foaf/0.1/> PREFIX dc: <http://purl.org/dc/elements/1.1/> PREFIX : <http://dbpedia.org/resource/> PREFIX dbpedia2: <http://dbpedia.org/property/> PREFIX dbpedia: <http://dbpedia.org/> PREFIX dbo: <http://dbpedia.org/ontology/> SELECT DISTINCT ?name ?birth ?death FROM <http://dbpedia.org> WHERE { ?person dbpedia2:birthPlace <http://dbpedia.org/resource/Bologna> . ?person dbo:birthdate ?birth . ?person foaf:name ?name . ?person dbo:deathdate ?death FILTER (?birth > "1900-01-01"^^xsd:date) . }
Per prima cosa la query definisce dei prefissi (PREFIX), che non sono altro che delle scorciatoie per fare riferimento ai diversi namespace utilizzati nella query (le ontologie di riferimento). Nell’esempio, fra le varie ontologie dichiarate, si notino FOAF [FOAF] per la descrizione delle persone e DBpedia [DBPED] che potremmo definire come la versione ontologica di Wikipedia.
La query vera e propria inizia con la parola chiave “SELECT” proprio come in SQL.
Nell’esempio viene richiesto di trovare nome, data di nascita e di morte di tutte le persone (storicamente famose) nate a Bologna dopo il 1900 rispetto all’ontologia DBPedia.org.
Scomponiamo allora la query:
SELECT DISTINCT ?name ?birth ?death
La clausola SELECT indica che si desidera selezionare tutte le triple RDF con valori distinti (la parola chiave DISTINCT specifica che non si vogliono risultati ripetuti) in cui il resultset dovrà riportare i valori delle tre variabili name, birth e death.
La valorizzazione delle variabili (che si indicano sempre con un “?” prefisso) rispetto ai vincoli (pattern triple) espressi nella clausola WHERE, si chiama “binding delle variabili”.
FROM <http://dbpedia.org>
La clausola FROM indica il/i dataset (detto anche RDF graph) di riferimento di default su cui effettuare la query. Questa informazione può essere resa implicita prima di lanciare la query dall’endpoint SPARQL o esplicitata ad ogni query tramite la clausola FROM appunto. In questo caso l’ontologia viene caricata dall’URL http://dbpedia.org
WHERE { ?person dbpedia2:birthPlace <http://dbpedia.org/resource/Bologna> . ?person dbo:birthdate ?birth . ?person foaf:name ?name . ?person dbo:deathdate ?death FILTER (?birth > "1900-01-01"^^xsd:date) . }
Infine la clausola WHERE, proprio come una normale query SQL, definisce i criteri di ricerca (detto graph pattern) e i criteri di binding delle variabili. Nell’esempio viene usata una variabile ?person per scorrere tutte le persone e fare il binding delle tre variabili birth, name e death in base al vincolo che il valore della proprietà birthPlace sia “Bologna” (denotata dalla risorsa descritta in DBpedia con l’URI http://dbpedia.org/resource/Bologna). Il pool finale dei risultati viene poi ulteriormente filtrato tramite la parola chiave “FILTER” in base alla condizione posta sulla data di nascita (successiva al 01-01-1900).
Il risultato della query è una lista di triple (ottenibile in vari formati come XML, testo normale o JSON) con le tre variabili valorizzate (binding) per ogni risorsa trovata che rispettava il vincolo e successivamente epurata dal filtro.
="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://www.w3.org/2001/sw/DataAccess/rf1/result2.xsd"> Angelo Schiavio ="http://www.w3.org/2001/XMLSchema#date">1905-10-15 ="http://www.w3.org/2001/XMLSchema#date">1990-04-17 Pier Paolo Pasolini ="http://www.w3.org/2001/XMLSchema#date">1922-03-05 ="http://www.w3.org/2001/XMLSchema#date">1975-11-02 . . .
che in formato più leggibile corrisponde alla seguente tabella:
name | birth | death |
Angelo Schiavio | 1905-10-15 | 1990-04-17 |
Pier Paolo Pasolini | 1922-03-05 | 1975-11-02 |
… | … | … |
UNION
Consideriamo ora un altro esempio per mostrare come sia possibile ottenere risultati come unione di più graph pattern. Supponiamo di avere il seguente RDF graph (espresso in formato Turtle [TURTLE]):
@prefix foaf: <http://xmlns.com/foaf/0.1/> . @prefix vcard: <http://www.w3.org/2001/vcard-rdf/3.0#> . _:a foaf:name "Matt Jones" . _:b foaf:name "Sarah Jones" . _:c vcard:FN "Becky Smith" . _:d vcard:FN "John Smith" .
Il dataset dell’esempio elenca 4 persone con i rispettivi nomi usando però due vocabolari diversi: foaf:name rispetto a FOAF e vcard:FN (Formatted Name) rispetto a VCARD-RDF.
Per poter elencare tutti i nomi usando entrambi i termini è necessario richiedere l’unione di due graph patter e per farlo basta semplicemente usare la parola chiave UNION nel seguente modo:
PREFIX foaf: <http://xmlns.com/foaf/0.1/> PREFIX vCard: <http://www.w3.org/2001/vcard-rdf/3.0#> SELECT ?name WHERE { { [] foaf:name ?name } UNION { [] vCard:FN ?name } }
Il risultato della query sarà:
name |
Matt Jones |
Sarah Jones |
Becky Smith |
John Smith |
La UNION è di fatto una congiunzione fra i due graph pattern delimitati dalle parentesi graffe. Ovviamente è possibile effettuare union su due o più graph pattern anche più complessi.
Si noti l’uso di “[]” per denotare la wildcard sul subject
OPTION
È possibile definire dei graph pattern opzionali ossia il cui binding non ha effetti sulla presenza o meno di una certa tripla. Si consideri per esempio il seguente dataset RDF:
@prefix foaf: <http://xmlns.com/foaf/0.1/> . @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . _:a rdf:type foaf:Person . _:a foaf:name "Alice" . _:a foaf:mbox <mailto:alice@example.com> . _:a foaf:mbox <mailto:alice@work.example> . _:b rdf:type foaf:Person . _:b foaf:name "Bob"
Come si nota Alice ha ben due indirizzi e-mail mentre Bob non ne ha nessuno. Per poter allora includere l’informazione solo nel caso sia presente, senza che essa discrimini sul pull finale dei risultati, si utilizza la parola chiave OPTION.
PREFIX foaf: <http://xmlns.com/foaf/0.1/> SELECT ?name ?mbox WHERE { ?x foaf:name ?name . OPTIONAL { ?x foaf:mbox ?mbox } }
e il risultato sarà:
name | mbox |
Alice | mailto:alice@example.com |
Alice | mailto:alice@work.example |
Bob |
Se non avessimo usato OPTION avremmo ottenuto solamente le due righe per Alice!
GRAPH
Una delle caratteristiche più potenti di SPARQL è quella di permettere di effettuare query su grafi multipli per poi aggregare i dati in base alla logica delle query e al binding delle variabili.
Abbiamo già visto che tramite la parola chiave FROM è possibile specificare un RDF Graph di default su cui la query opererà.
Supponiamo ora di avere due RDF graph diversi (diversi file e diversi URI). Il primo è il foaf di Bob:
# Named graph: http://example.org/foaf/bobFoaf @prefix foaf: <http://xmlns.com/foaf/0.1/> . @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . _:z foaf:mbox <mailto:bob@work.example> . _:z rdfs:seeAlso <http://example.org/foaf/bobFoaf> . _:z foaf:nick "Robert" . <http://example.org/foaf/bobFoaf> rdf:type foaf:PersonalProfileDocument .
Il secondo è il foaf di Alice:
# Named graph: http://example.org/foaf/aliceFoaf @prefix foaf: <http://xmlns.com/foaf/0.1/> . @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . _:a foaf:name "Alice" . _:a foaf:mbox <mailto:alice@work.example> . _:a foaf:knows _:b . _:b foaf:name "Bob" . _:b foaf:mbox <mailto:bob@work.example> . _:b foaf:nick "Bobby" . _:b rdfs:seeAlso <http://example.org/foaf/bobFoaf> . <http://example.org/foaf/bobFoaf> rdf:type foaf:PersonalProfileDocument .
Con la seguente query possiamo reperire le informazioni che ci interessano senza sapere a priori dove si trovino:
PREFIX foaf: <http://xmlns.com/foaf/0.1/> SELECT ?src ?bobNick FROM NAMED <http://example.org/foaf/aliceFoaf> FROM NAMED <http://example.org/foaf/bobFoaf> WHERE { GRAPH ?src { ?x foaf:mbox <mailto:bob@work.example> . ?x foaf:nick ?bobNick } }
Per prima cosa notiamo l’uso della clausola “FROM NAMED” che permette di specificare dei named graph da cui attingere nella query. Con la parola chiave GRAPH poi è possibile specificare su quale dei named graph effettuare la query o anche usare una variabile per farlo su tutti.
Il risultato della query è il seguente:
src | bobNick |
http://example.org/foaf/bobFoaf | Robert |
http://example.org/foaf/aliceFoaf | Bobby |
Nel caso si voglia specificare direttamente i named graph da usare si potrà farlo usando anche i prefissi:
PREFIX graphs: <http://example.org/graphs/> PREFIX ex: <http://example.org/example/> SELECT * FROM <http://example.org/example/> FROM NAMED graphs:g1 FROM NAMED graphs:g2 WHERE { ?s ex:p ?o GRAPH graphs:g1 { ?s ex:p1 ?o } GRAPH graphs:g2 { ?s ex:p2 ?o } }
L’asterisco dopo la SELECT indica che in output si vogliono tutte le variabili usate nella query mentre la riga non preceduta da GRAPH verrà verificata rispetto al grafo di default specificato nella clausola FROM.
CONSTRUCT
SPARQL permette non solo di effettuare delle quey che restituiscono triple valorizzate ma anche di costruire nuovi grafi RDF a partire da un template e dal binding risultante dalle query. Per far questo si usa la clausola COSTRUCT che, come prima cosa, richiede di definire il template delle triple RDF da generare. Anche in questo caso conviene partire da un esempio pratico:
PREFIX vCard: <http://www.w3.org/2001/vcard-rdf/3.0#> PREFIX foaf: <http://xmlns.com/foaf/0.1/> CONSTRUCT { ?X vCard:FN ?name . ?X vCard:URL ?url . ?X vCard:TITLE ?title . } FROM <http://www.w3.org/People/Berners-Lee/card> WHERE { OPTIONAL { ?X foaf:name ?name . FILTER isLiteral(?name) . } OPTIONAL { ?X foaf:homepage ?url . FILTER isURI(?url) . } OPTIONAL { ?X foaf:title ?title . FILTER isLiteral(?title) . } }
All’interno delle parentesi graffe della clausola CONSTRUCT viene definito il template da utilizzare per generare l’RDF e, come si può notare, viene legato alle stesse variabili usate nella query. Una parte del risultato generato in XML è il seguente:
<rdf:RDF xmlns_rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns_foaf="http://xmlns.com/foaf/0.1/" xmlns_vCard="http://www.w3.org/2001/vcard-rdf/3.0#"> Wendy Hall Dave Beckett Lee Feigenbaum Danny Ayers Sir Timothy Berners-Lee ...
Ossia per ogni istanza contenuta nel grafo http://www.w3.org/People/Berners-Lee/card costruisce una descrizione RDF con nome, URL e titolo se almeno uno di queste proprietà ha valore.
Nota: Tramite CONSTRUCT è possibile ricostruire un intero grafo ed eventualmente fare l’unione di più grafi. In questo esempio si genera una copia del grafo http://example.org/aGraph:
CONSTRUCT { ?s ?p ?o } WHERE { GRAPH <http://example.org/aGraph> { ?s ?p ?o } . }
ASK
SPARQL mette permette anche di effettuare delle domande rispetto al contenuto dell’ontologia tramite la parola chiave ASK. La risposta a una ASK è sempre del tipo true/false.
Potremmo per esempio chiederci se è più lungo il Nilo rispetto al Rio delle Amazzoni (annoso dilemma ancora non risolto) e per farlo potremmo usare una ASK sempre su DBpedia nel seguente modo:
PREFIX prop: <http://dbpedia.org/property/> ASK { <http://dbpedia.org/resource/Amazon_River> prop:length ?amazon . <http://dbpedia.org/resource/Nile> prop:length ?nile . FILTER(?nile > ?amazon) . }
In questo caso la domanda è costituita da due triple pattern e da un filtro. Il primo pattern lega la variabile “amazon” al valore della lunghezza del fiume riportato nell’ontologia. Il secondo fa lo stesso per il Nilo e infine il filtro richiede la maggior lunghezza del Nilo rispetto al Rio delle Amazzoni. La risposta (opinabile…) è la seguente:
xmlns_xsi="http://www.w3.org/2001/XMLSchema-instance" xsi_schemaLocation="http://www.w3.org/2001/sw/DataAccess/rf1/result2.xsd"> true
Risposta che trova una conferma su wikipedia al seguente link:
http://it.wikipedia.org/wiki/Lista_dei_fiumi_più_lunghi_del_mondo#cite_note-0
DESCRIBE
La parola chiave DESCRIBE permette invece di richiedere informazione rispetto a un particolare concetto presente nell’ontologia. La risposta è a discrezione dell’endpoint SPARQL il quale può ritornare un RDF che desccriva al meglio il concetto richiesto.
DESCRIBE <http://dbpedia.org/resource/Ferrari>
Con questa query per esempio richiediamo tutte le informazioni disponibili su dbpedia inerenti alla Ferrari. Di seguito riporto una parte dell’RDF ritornato dall’endpoint SPARQL di DBPedia:
... rdf_resource="http://www.ferrariworld.com/FWorld/fw/index.jsp"/> La Ferrari SpA è una casa automobilistica italiana. È stata fondata da Enzo Ferrari e produce autovetture sportive d'alta fascia e da gara. Gestisce, inoltre, la Scuderia Ferrari, una delle più celebri e titolate squadre sportive impegnate nelle competizioni automobilistiche. La sede dell'azienda è a Maranello, in provincia di Modena. Luca Cordero di Montezemolo, ex presidente di Confindustria e presidente del Gruppo Fiat, ne è il presidente. Il simbolo, il "cavallino rampante", è quello dell'aviatore romagnolo della prima guerra mondiale Francesco Baracca (1888-1918) ceduto personalmente dalla madre nel 1923 come portafortuna a un Enzo Ferrari pilota automobilistico e presente sia nel marchio della Ferrari sia in quello della Scuderia Ferrari. Nell'anno fiscale 2008 Ferrari SpA ha venduto 5026 vetture per un fatturato di 1,419 miliardi di euro. rdf_resource="http://dbpedia.org/resource/Ferrari"/> rdf_resource="http://dbpedia.org/resource/Ferrari"/> ... rdf_resource="http://dbpedia.org/resource/Fiat"/> Luca di Montezemolo, </small><br> Piero Ferrari, <br> Amedeo Felisa, <br> Giancarlo Coppa , rdf_resource="http://dbpedia.org/resource/Piero_Ferrari"/> ...
Si nota che la risposta non è altro che una lista di tdescription RDF correlate con la risorsa
http://dbpedia.org/resource/Ferrari
SPARQL Endpoint
Ok… tutto molto bello, ma a questo punto ci si dovrebbe chiedere: come faccio praticamente a fare le mie query per sapere tutto sull’ Archaeopteryx (guai a voi se usate Wikipedia)? È presto detto. Su internet sono disponibili due tipologie di servizi per query SPARQL (endpoint):
- generici: per effettuare query su qualunque RDF graph accessibile via web
- specifici: cablati per effettuare query su un particolare dataset.
Tutti comunque presentano una form con la possibilità di inserire la query e eventualmente specificare il tipo di formato di output (testo, HTML, XML, JSON [JSON] e RDF). La differenza principale però sta nel fatto che mentre i primi richiedono di specificare (via FROM o tramite un altro campo) il dataset di default i secondi hanno un dataset preimpostato e spesso sono ottimizzati per la particolare ontologia sottostante.
Un esempio di endpoint SPARQL piuttosto interessante è sicuramente OpenLink Virtuoso SPARQL [VIRTUO] (figura 1).
Figura 1 – OpenLink Virtuoso SPARQL
Altri endpoint generici sono: Redland Rasqal RDF Query e ARQ Sparqler.
Un esempio di endpoint specializzato può essere quello di DBPedia (figura 2):
Figura 2 – Un esempio di endpoint specializzato.
API per le ontologie
Uno dei modi più comuni di recuperare informazioni e manipolare ontologie è quello di farlo in maniera programmatica. Sviluppando in Java, per esempio, è possibile accedere e manipolare una ontologia OWL/RDF a due livelli di astrazione. Il primo è il livello XML in cui un file OWL viene visto come un qualunque file XML: in questo caso basterà utilizzare delle normalissime librerie che permettano di gestire il DOM del file come per esempio Xerces [XERCES].
Il secondo livello è quello del modello ontologico di OWL/RDF. Questo modo di accedere è ovviamente il migliore e il più efficiente in quanto le API per OWL solitamente mettono a disposizione un modello più o meno completo per programmare in termini di classi, istanze e relazioni.
Per Java le principali API per ontologie sono quelle riportate di seguito
JENA
È forse il più famoso e utilizzato framework open source Java per gestire in maniera programmatica RDF e OWL. Sviluppato da HP Labs Semantic Web Programme fornisce delle API complete per leggere e scrivere RDF in vari formati, OWL e SPQRL engine [JENA].
OWL-API
È un framework open source Java sviluppato nell’ambito del progetto WonderWeb [OWLAPI] e attualmente mantenuto e sviluppato dall’Università di Manchester. Fornisce un’interfaccia completa e compatibile con le ultime specifiche OWL 2 [OWL2] del W3C oltre che con RDF; vi è poi la possibilità di definire regole SWRL [SWRL].
Protege OWL-API
È una libreria Java open-source OWL e RDF(s) sviluppata originariamente da Holger Knublauch per il plugin OWL [POAPI] di Protege e attualmente mantenuto dallo staff di Protege della Stanford University. Il modello che implementa è molto intuitivo e particolarmente ottimizzato per la creazione di interfacce grafiche. È fortemente integrabile con JENA (in quanto ne condivide alcune classi) e permette la gestione di regole SWRL e reasoning.
Poiche’ più o meno tutte le librerie mettono a disposizione modelli simili e usano pattern comuni basterà prenderne in considerazione una sola per avere una panoramica di come queste API funzionino. A ragione della sua maggiore diffusione e della chiarezza di modello, baserò i miei esempi sul framework JENA.
Conclusioni
Per questo numero ci fermiamo qui, un po’ bruscamente, ma è necessario per non mettere troppa carne al fuoco. Riprenderemo il discorso nel prossimo numero, quando vedremo nel dettaglio alcuni esempi basati appunto sul Framework Jena e affronteremo poi l’inferenza tramite reasoner e l’accesso tramite piattaforme middleware semantiche.
Riferimenti
[FOAF] Friend Of A Friends
[SPARQL] Standard W3C SPARQL
[DBPED] DBpedia
[TURTLE] Turtle: Terse RDF Triple Language
http://www.w3.org/TeamSubmission/turtle/
[JSON] Formato JSON
[VIRTUO] Virtuoso
http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VOSSparqlProtocol
[XERCES] Xerces, Java Parser
http://xerces.apache.org/xerces-j/
[JENA] A Semantic Web Framework for Java
[OWLAPI] OWL API homepage
http://owlapi.sourceforge.net/
[OWL2] OWL2 Web Ontology Language Profiles
http://www.w3.org/TR/owl2-profiles/
[SWRL] Semantic Web Rule Language
http://www.w3.org/Submission/SWRL/
[POAPI] Protege-OWL
http://protege.stanford.edu/plugins/owl/api/
[DOAP] Description of a Project Ontology
http://trac.usefulinc.com/doap
[HORN] Clausole di Horn
http://it.wikipedia.org/wiki/Clausola_di_Horn
[OANZO] Progetto Open Anzo
http://www.openanzo.org/index.html
[BOCA] Boca Project
http://ibm-slrp.sourceforge.net/