Blog ENI : Toute la veille numérique !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
💥 Les 22 & 23 novembre : Accès 100% GRATUIT
à la Bibliothèque Numérique ENI. Je m'inscris !

Travailler avec les triplets RDF et les mondes

Introduction

Dans ce chapitre, nous verrons comment accéder directement au quadstore RDF, et comment créer plusieurs « mondes » isolés possédant chacun leur quadstore.

Les triplets RDF

RDF (Resource Description Framework) est un modèle de graphe pour décrire de manière formelle des ressources et des métadonnées. En particulier, toute ontologie OWL peut être exprimée sous la forme d’un graphe RDF. Il se compose d’un ensemble de triplets de la forme : sujet, prédicat, objet. Le prédicat correspond à une propriété au sens OWL. Une ontologie est donc stockée dans le quadstore sous la forme d’un ensemble de triplets RDF. Dans l’ontologie des bactéries, deux exemples de triplets décrivant l’individu bactérie_inconnue sont :

(http://lesfleursdunormal.fr/static/_downloads/bacterie.owl#bactérie_inconnue, http://www.w3.org/1999/02/22-rdf-syntax-ns#type, http://lesfleursdunormal.fr/static/_downloads/bacterie.owl#Bactérie)

(http://lesfleursdunormal.fr/static/_downloads/bacterie.owl#bactérie_inconnue, http://lesfleursdunormal.fr/static/_downloads/bacterie.owl#gram _positif, true)

Le premier triplet indique la classe à laquelle appartient l’individu, via le prédicat type de RDF, et le second indique le statut Gram de la bactérie.

D’autres constructeurs OWL plus complexes, comme les restrictions portant sur les classes, peuvent être décrits à l’aide de plusieurs triplets et de nœuds anonymes dans le graphe. Par exemple...

Manipuler les triplets RDF avec RDFlib

1. Accéder aux triplets RDF

RDFlib est un module Python qui permet de manipuler des graphes et des triplets RDF. Les ontologies OWL étant stockées dans un graphe RDF, nous pouvons utiliser RDFlib pour manipuler celui-ci. Cependant, contrairement à Owlready, RDFlib ne prend pas en compte la sémantique spécifique à OWL et ne permet donc pas de bénéficier de l’expressivité d’OWL, ni d’effectuer des raisonnements automatiques.

Owlready utilise un quadstore différent de celui de RDFlib, néanmoins, il peut être rendu compatible grâce à la méthode as_rdflib_graph() de la manière suivante :

>>> from rdflib import *  
>>> graph = default_world.as_rdflib_graph() 

L’objet graph produit est alors un quadstore compatible RDFlib.

Les graphes RDFlib sont composés de trois éléments : les entités (identifiées par une URI, et créées avec la fonction URIRef()), les nœuds anonymes (blank nodes, créés avec la fonction BNode()) et les données (nombres entiers ou réels, chaînes de caractères... regroupés sous le nom de litéraux, et créés avec la fonction Literal()). La méthode triples(sujet, predicat, objet) du graphe RDF permet de parcourir un sous-ensemble...

Effectuer des requêtes SPARQL

SPARQL (SPARQL Protocol and RDF Query Language) est un langage de requêtes permettant de faire des recherches dans un graphe RDF. Ce langage est un peu le pendant du langage SQL (Structured Query Language) des bases de données relationnelles, mais pour les bases de graphe RDF.

RDFlib inclut un moteur SPARQL, qui peut être utilisé avec Owlready.

1. Recherche avec SPARQL

SPARQL permet de faire des recherches plus complexes que la méthode search() d’Owlready, cependant, pour les recherches simples, il est préférable d’utiliser search() car les performances sont meilleures.

La méthode query() de l’objet graph RDFlib permet d’effectuer une requête SPARQL, et retourne le résultat au format RDFlib (c’est-à-dire sous forme d’URIRef, de BNode et de Literal). La clause WHERE de la requête contient un ou plusieurs triplets RDF, qui peuvent contenir des entités (identifiées par leur IRI), mais aussi des variables, dont le nom est préfixé par « ? ». Dans l’exemple suivant, nous recherchons toutes les entités ?b étant de la classe Bactérie, où ?b est une variable :

>>> graph = default_world.as_rdflib_graph()  
>>> list(graph.query("""  
... SELECT ?b WHERE {  
...     ?b  
...     <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>  
...     <http://lesfleursdunormal.fr/static/_downloads/bacterie.owl#Bactérie> . 
... } """))  
[(rdflib.term.URIRef('http://lesfleursdunormal.fr/static/ \ 
                    _downloads/bacterie.owl#bactérie_inconnue'),)] 

La méthode query_owlready() fonctionne de la même manière, mais retourne le résultat au format Owlready (c’est-à-dire sous forme d’objet Owlready ou de types de données Python) :

>>> list(graph.query_owlready("""  
... SELECT ?b WHERE {  
...     ?b  
...    ...

Accéder aux triplets RDF via Owlready

Owlready dispose également de méthodes pour accéder directement au quadstore RDF. Ces méthodes sont plus complexes et moins standards que l’emploi de RDFlib, en revanche elles sont plus rapides.

Afin de réduire le volume du quadstore, Owlready remplace les IRI des entités par des « IRI abrégés » appelées storid (store ID). Ce sont des codes arbitraires sous forme de nombres entiers strictement positifs. Les méthodes _abbreviate() et _unabbreviate() permettent respectivement d’abréger et de désabréger une IRI. Si cette dernière n’a pas encore reçu d’abréviation, un nouveau code est automatiquement créé par _abbreviate() et enregistré dans le quadstore.

Dans l’exemple suivant, l’IRI de la classe Staphylocoque correspond au storid 324 (Note : la valeur exacte du storid peut varier d’un quadstore à l’autre, selon l’ordre de création des entités dans l’ontologie) :

>>> default_world._abbreviate(onto.Staphylocoque.iri)  
324  
>>> default_world._unabbreviate(324)  
'http://lesfleursdunormal.fr/static/_downloads/bacterie.owl#Staphylocoque' 

L’attribut storid des entités permet également de récupérer leur storid :

>>> onto.Staphylocoque.storid  
324 

La méthode _get_by_storid() permet l’opération inverse, c’est-à-dire obtenir une entité à partir de son storid :

>>> default_world._get_by_storid(324)  
bacterie.Staphylocoque 

Les nœuds anonymes sont également représentés dans le quadstore par des identifiants storid, mais ceux-ci sont des nombres entiers strictement négatifs.

Le quadstore d’Owlready stocke les relations entre deux entités à l’aide de triplets RDF de la forme classique (sujet, prédicat, objet). En revanche, les relations entre une entité et une donnée sont stockées...

Interroger directement la base de données SQLite3

Le quadstore Owlready est implémenté sous forme d’une base de données SQLite3. Celle-ci contient trois tables principales :

  • resources, qui fait correspondre les IRI aux storids,

  • objs, qui contient les quadruplets des relations entre deux entités,

  • datas, qui contient les quadruplets des relations entre une entité et une donnée.

Enfin, la vue « quads » est une pseudo-table en lecture seule qui contient à la fois les enregistrements de la table objs et de la table datas (pour objs, d = NULL).

Les tableaux suivants montrent le schéma de ces tables :

Table resources

storid TEXT

iri TEXT

Table objs

rowid INTEGER

c INTEGER

s TEXT

p TEXT

o TEXT

Table datas

rowid INTEGER

c INTEGER

s TEXT

p TEXT

o BLOB

d TEXT

Vue quads

rowid INTEGER

c INTEGER

s TEXT

p TEXT

o BLOB

d TEXT

Les champs sont les suivants :

  • storid : un identifiant dans le quadstore.

  • iri : l’IRI associé à l’identifiant storid.

  • rowid : l’identifiant du triplet RDF.

  • c : l’identifiant de l’ontologie : 1 pour la première, 2 pour la seconde...

  • s : le sujet du triplet : un identifiant storid.

  • p : le prédicat (ou propriété) du triplet : un identifiant storid.

  • o : l’objet du triplet : un identifiant storid (pour la table objs et quads) ou une valeur entière, réelle ou encore une chaîne de caractères...

Créer plusieurs mondes isolés

Owlready permet de créer plusieurs « mondes » isolés, parfois appelés « univers du discours ». Cela permet notamment de charger plusieurs fois la même ontologie, de manière indépendante, c’est-à-dire sans que les modifications effectuées sur une copie n’affectent l’autre. Cela peut également être utile pour charger simultanément plusieurs versions incompatibles d’une même ontologie.

Par défaut, Owlready ne crée qu’un seul monde, appelé default_world. La classe World permet de créer un nouveau monde, indépendant de default_world

>>> from owlready2 import *  
>>> mon_monde = World() 

Chaque monde est stocké dans un quadstore différent. Chacun peut être stocké en mémoire vive et/ou sur le disque dans un fichier distinct, via la méthode set_backend() (voir chapitre Accéder aux ontologies en Python, section Ontologie volumineuse et cache disque). D’une manière générale, toutes les méthodes que nous avons appliquées à default_world peuvent être sur les mondes. De plus, plusieurs fonctions globales sont en fait des raccourcis vers des méthodes de default_world. Lorsque l’on utilise plusieurs mondes, il faut donc appeler...