Generazione e controllo sul modello

D2R permette di gestire anche la parte del modello. In pratica, essendo D2R Server orientato al LinkedData prevede di default la generazione di classi e proprietà istanziate. In questo modo, anche in assenza del modello, il server è in grado di avere dei riferimenti minimi alle definizioni di classi e proprietà riferite.

Ciò fa sì che in assenza di configurazioni particolari tutte le classi riferite con d2rq:class e le proprietà riferite con d2rq:property vengano generate e inserite nell’eventuale file di dump come rdfs:Class e rdfs:Property.

Nel caso di esempio, effettuando il dump, oltre alle istanze vengono generate classi e proprietà che di fatto sono già definite nel file specifiche.owl:

...

foaf:Person a rdfs:Class .

foaf:currentProject a rdf:Property .

...

Si noti che nel file di modello usato in realtà sono definite come owl:Class e owl:ObjectProperty. In questo modo il server D2R può generare direttamente anche una navigazione dalle istanze alle classi e le proprietà con lo stesso mapping (senza bisogno di avere il file di modello vero e proprio specifiche.owl).

In molti casi questo comportamento non è desiderabile, in quanto genera meta-informazioni non necessarie che sporcano le istanze e si sovrappongono (non in maniera errata comunque) con il modello vero e proprio.

Nella configurazione di D2R è possibile specificare di non generare nessun meta-dato, ossia di non creare le classi e property di modello riferite nel mapping. Per far questo basta definire una map:Configuration in cui si mette a false il flag d2rq:serveVocabulary:

map:Configuration a d2rq:Configuration;

d2rq:serveVocabulary false;

.

Di default il flag è true.

Per ulteriori dettagli su come usare Configuration si veda la documentazione ufficiale \[5\].

Aggiunta di meta-proprietà al modello: d2rq:AdditionalProperty

Nel caso si voglia lasciare che D2R rigeneri anche il modello, è possibile comunque agire e customizzare il modello stesso, aggiungendo delle meta-proprietà alle classi e alle property in modo da customizzare il modello a piacimento (in termini di annotazione, label, comment e tipizzazione).

Per caratterizzare classi e proprety associando opportuni attributi è possibile usare l’elemento d2rq:AdditionalProperty e poi richiamare l’AdditionalProperty o da un ClassMap o da un PropertyBridge.

Per esempio, se volessimo specificare che la classe spec-m:RequisitoNonFunzionale è non solo una rdfs:Class (meta-classe aggiunta di default) ma anche una owl:Class e che la sua label è “requisito non funzionale” potremmo aggiungere due AdditionalProperty come segue:

map:OWLClassTypeCasting a d2rq:AdditionalProperty;

d2rq:propertyName rdf:type;

d2rq:propertyValue owl:Class;

.

map:OWLReqNFunzClassLabel a d2rq:AdditionalProperty;

d2rq:propertyName rdfs:label;

d2rq:propertyValue "Requisito non funzionale";

.

Per poi richiamarlo nel ClassMap associato a questa classe tramite l’uso di d2rq:additionalClassDefinitionProperty:

map:Requisito_nfun a d2rq:ClassMap;

d2rq:dataStorage map:databaseReq;

d2rq:condition "Requisiti\$.Tipo \<\> 'fun'" ;

d2rq:uriPattern "requisito-@@Requisiti\$.Tipo@@\_@@Requisiti\$.Codice@@";

d2rq:class spec-m:RequisitoNonFunzionale;

d2rq:additionalClassDefinitionProperty map:OWLClassTypeCasting;

d2rq:additionalClassDefinitionProperty map:OWLReqNFunzClassLabel;

.

Effettuando un dump di questo mapping otterremmo quindi fra le istanze anche la definizione della classe di modello spec-m:RequisitoNonFunzionale come segue:

spec-m:RequisitoNonFunzionale

owl:Class , rdfs:Class ;

rdfs:label "Requisito non funzionale" .

che per l’appunto non è una istanza generata a partire dai dati presenti sul DB ma è una definizione di classe del modello generata da D2R con l’aggiunta di due AdditionalProperty (owl:Class e rdfs:Label).

Allo stesso modo, è possibile agire sulle property, per specificare per esempio il tipo di property (Datatype o Objectype) ed eventuali domain e range.

Nell’esempio vengono definite tre AdditionalProperty: una per specificare il tipo (owl:ObjectProperty), una per specificare il dominio e una per il range:

map:RequisitodiPropertyCasting a d2rq:AdditionalProperty;

d2rq:propertyName rdf:type;

d2rq:propertyValue owl:ObjectProperty;

.

map:RequisitodiPropertyDomain a d2rq:AdditionalProperty;

d2rq:propertyName rdfs:range;

d2rq:propertyValue spec-m:ProgettoSoftware;

.

map:RequisitodiPropertyRange a d2rq:AdditionalProperty;

d2rq:propertyName rdfs:domain;

d2rq:propertyValue spec-m:RequisitoNonFunzionale;

.

A questo punto le tre AdditionalProperty devono essere associate alla proprietà relativa e per fare questo si usa d2rq:additionalPropertyDefinitionProperty all’interno della definizione del PropertyBridge:

map:Requisitorequisitodi

rdf:type d2rq:PropertyBridge ;

d2rq:belongsToClassMap

map:Requisitofun, map:Requisitonfun ;

d2rq:uriPattern "progetto-@@Requisiti\$.IdProgetto@@" ;

d2rq:property spec-m:requisito_di ;

d2rq:additionalPropertyDefinitionProperty map:RequisitodiPropertyCasting;

d2rq:additionalPropertyDefinitionProperty map:RequisitodiPropertyDomain;

d2rq:additionalPropertyDefinitionProperty map:RequisitodiPropertyRange;

.

Il risultato di queste proprietà aggiuntive è una definizione della proprietà nel dump come segue:

spec-m:requisito_di

a rdf:Property , owl:ObjectProperty ;

rdfs:domain spec-m:RequisitoNonFunzionale ;

rdfs:range spec-m:ProgettoSoftware .

Uso del server online

Una volta creato un file di mapping (anche se non definitivo) il modo più semplice di testarlo è avviare il server e navigare le istanze via Web tramite LinkedData.

Il server può essere avviato come servizio Windows (o Linux), deployato come webapp in un servlet container o avviato da riga di comando. Per ulteriori dettagli sulle modalità di avvio del server e sulla sua configurazione si faccia riferimento alla documentazione ufficiale \[6\].

Per quato attiene a questo articolo, ci limiteremo a mostrare come avviare il server da linea di comando.

Avviare il server da linea di comando

Aprire il prompt dei comandi e posizionarsi alla root di D2RServer (quella scaricata da SVN o scompattata da ZIP versionato). Poi digitare:

\> d2r-server custommapping\D2RUnionMappingProge_Req.n3

Figura 1 - Avvio del server da linea di comando.
Figura 1 - Avvio del server da linea di comando.

A questo punto, basta collegarsi via browser all’indirizzo configurato (nel nostro esempio http://localhost:2020) per accedere alla homepage del server appena avviato.

Figura 2 - Homepage del servizio configurato.
Figura 2 - Homepage del servizio configurato.

Navigazione LinkedData integrata

Partendo dalla homepage di D2RServer è possibile iniziare subito la navigazione attraverso i concetti mappati e le istanze generate con le relative proprietà e relazioni. Nella prima riga sotto il titolo si possono vedere i link ai ClassMap generati e quindi alle istanze delle varie classi mappate.

Figura 3 - Il menu con i link ai ClassMap generati.
Figura 3 - Il menu con i link ai ClassMap generati.

Cliccando per esempio su Progetti verrà visualizzata la lista delle istanze di progetto mappate

Figura 4 - Elenco delle istanze di progetto mappate.
Figura 4 - Elenco delle istanze di progetto mappate.

Cliccando uno di questi progetti, ha inizio la navigazione LinkedData (ossia dove ogni elemento dell’ontologia viene associato a runtime all’URL relativo del server).

Figura 5 - Ogni elemento dell’ontologia viene associato a runtime all’URL relativo del server.
Figura 5 - Ogni elemento dell’ontologia viene associato a runtime all’URL relativo del server.

La tabella lista tutti i valori per le proprietà definite dove, ogni valore di relazione verso un'altra istanza è a sua volta un link ad un'altra scheda di istanza.

Figura 6 - La tabella con la lista tutti i valori per le proprietà definite.
Figura 6 - La tabella con la lista tutti i valori per le proprietà definite.

Cliccando per esempio sul link a fianco alla property doap:mantainer otteniamo la scheda del responsabile di progetto “Marco Rossi”.

Cliccando invece su link a destra di una delle proprietà “is spec-m:requisito_di of”, vedremo il dettaglio del requisito selezionato per quel progetto.

Figura 7 - Dettaglio del requisito selezionato.
Figura 7 - Dettaglio del requisito selezionato.

Va notato come la navigazione è assolutamente trasparente al fatto che le due informazioni derivino da due sorgenti dati fra loro scollegate. L’utente ha quindi la percezione di una integrazione totale fra i concetti e le valorizzazioni dei dati.

Relazioni inverse

C’è un’altra nota importante relativa alle relazioni inverse: va infatti considerato che anche se da mapping non è stata valorizzata la relazione da progetto a requisito “harequisito”, la navigazione sfrutta la relazione inversa (da requisito a progetto =\> “requisitodi”) e la mostra anche dal Progetto ma nella forma passiva “is requisito_di of”. Chiaramente funzionerebbe meglio se la relazione si chiamasse solo “project”, che passivato diventerebbe “is project of”, ma, insomma, il discorso è abbastanza chiaro.

In questo modo, si vedono i requisiti connessi al progetto anche se la relazione è valorizzata a partire dal requisito. Si noti infatti che, aprendo invece un requisito, la stessa relazione è espressa non più in forma passiva ma diretta (spec-m:requisito_di).

SPARQL Endpoint integrato e interrogazione

Dalla homepage del server lanciato (http://localhost:2020), è possibile accedere all’interfaccia di interrogazione SPARQL dell’endpoint cliccando sul link in fondo “ his AJAX-based SPARQL Explorer” (http://localhost:2020/snorql).

Notiamo, a proposito di SPARQL EndPoint Service, che l’endpoint è accessibile anche come servizio REST all’url http://localhost:2020/sparql dove, passando gli opportuni parametri (protocollo standard di interrogazione via http \[6\]) è possibile interrogarlo da una applicazione o da un tool esterno via GET e POST (per esempio usando JENA, \[7\]).

Figura 8 - L’endopoint service è accessibile anche come servizio REST all’URL http://localhost:2020/sparql.
Figura 8 - L’endopoint service è accessibile anche come servizio REST all’URL http://localhost:2020/sparql.

Da questa pagina è possibile effettuare query SPARQL e visualizzare la lista dei risultati navigabili sempre in modalità Linked Data.

Figura 9 - Si possono effettuare query SPARQL, visualizzando poi l’elenco dei risultati navigabili.
Figura 9 - Si possono effettuare query SPARQL, visualizzando poi l’elenco dei risultati navigabili.

Cliccando sul link dell’URI di un riga dei risultati (p.e.: \<http://localhost:2020/resource/progetto-2\>) si innesca una ulteriore query di dettaglio che mostra tutte le proprietà uscenti e entranti dall’istanza.

Figura 10 - Ulteriore query di dettaglio.
Figura 10 - Ulteriore query di dettaglio.

Cliccando invece sulla piccola freccia blu associata ad ogni URI si accede alla navigazione LinkedData vista precedentemente.

È anche possibile specificare un formato differente per i risultati restituiti, cambiando il valore nel comboBox Results: i formati possibili sono le serializzazioni JSON o XML.

Federated Query

A differenza del dump che, come vedremo non ha problemi, le query federated che coinvolgono elementi di due sorgenti non sono possibili. Questo perché il sistema di trasformazione delle query SPARQL -\> SQL ancora non gestisce correttamente le query cross database. La feature però è ovviamente molto richiesta e si sta lavorando per cercare di farla funzionare correttamente nelle future versioni. Un esempio di query federated che non può funzionare live (ma sul dump invece funziona) è:

SELECT DISTINCT ?proglabel ?requisitolabel

WHERE {

?requisito spec-m:requisito_di ?progetto;

rdfs:label ?requisito_label.

?progetto rdfs:label ?prog_label .

} ORDER BY ?proglabel ?requisitolabel

La query, se effettuata live, dà un errore del tipo:

\[Microsoft\]\[Driver ODBC Excel\] Il modulo di gestione di database\ di Microsoft Office Access non è riuscito a trovare\ l'oggetto 'Progetti'. Assicurarsi che l'oggetto esista\ e che il nome e il percorso siano digitati correttamente.:\ SELECT DISTINCT "T2Requisiti\$"."Titolo", "T1Requisiti\$"."Codice",\ "T1Requisiti\$"."Tipo", "T1Requisiti\$"."IdProgetto",\ "T3Progetti"."Nome" FROM "Progetti" AS "T3Progetti",\ "Requisiti\$" AS "T1Requisiti\$", "Requisiti\$" AS "T2Requisiti\$"\ WHERE ("T1Requisiti\$"."Codice" = "T2Requisiti\$"."Codice"\ AND "T1Requisiti\$"."IdProgetto" = "T3Progetti"."ID"\ AND "T1Requisiti\$"."Tipo" = "T2Requisiti\$"."Tipo"\ AND (Requisiti\$.Tipo = 'fun'))

Conclusioni

In questa seconda parte della serie siamo entrati in aspetti più operativi, che ci hanno consentito di mettere le mani direttamente sulle potenzialità e sulle modalità operative con cui funziona D2R Server. Nel successivo articolo, concluderemo questa miniserie parlando di importazione di modelli, di Jena e presentando alcune note finali.

Riferimenti

  • \
  • [1\] Un tutorial abbastanza completo sull’uso di D2R Server con un DB MySQL

<http://sw.cs.technion.ac.il/d2rq/tutorial>

  • \
  • [2\] Guida per connettere una sorgente relazionale mappata tramite D2R con l’endpoint JOSEKI 2

<http://www4.wiwiss.fu-berlin.de/bizer/d2rmap/usecases/joseki/D2R4joseki2.pdf>

  • \
  • [3\] D2R/Update Server, un tutorial sull’uso di D2R Server per effettuare query con SPARQL Update e quindi andare in scrittura sul DB

<http://d2rqupdate.cs.technion.ac.il/tutorial>

  • \
  • [4 \] SPARQL 1.1 Update. W3C Working Draft

<http://www.w3.org/TR/2009/WD-sparql11-update-20091022/>

  • \
  • [5\] Configurazione del motore di mapping in DR2Server e avvio del server.
  • [http://d2rq.org/d2rq-language#configuration](http://d2rq.org/d2rq-language%23configuration)
  • \
  • [6\] Query Sparql

<http://www.w3.org/TR/rdf-sparql-protocol/#query-bindings-http>

  • \
  • [7\] The D2RQ Mapping Language

<http://d2rq.org/d2rq-language#sparql>