Owlready : un module Python pour manipuler les ontologies OWL

Posté par  (site web personnel) . Édité par ZeroHeure, Pierre Jarillon, Davy Defaud et palm123. Modéré par bubar🦥. Licence CC By‑SA.
36
3
sept.
2017
Python

Les ontologies formelles sont un moyen de modéliser des connaissances. Elles sont de plus en plus utilisées en intelligence artificielle. Cependant, bien qu’elles partagent de nombreux aspects avec les modèles objet, elles restent peu connues des programmeurs.

Owlready est un module sous licence LGPL permettant de faire de la programmation orientée ontologie en Python, c’est‐à‐dire de manipuler les entités d’une ontologie formelle comme s’il s’agissait d’objets Python classiques. La version 2 - 0.4 intègre un quadstore RDF optimisé et une syntaxe de haut niveau pour manipuler les ontologies, qui a fait l’objet d’un article récent de la revue Artificial Intelligence In Medicine (AIM).

Dans la suite de cet article de la série « que peut‐on faire dans le Libre quand on est maître de conférence ? », les ontologies seront rapidement présentées, puis je décrirai Owlready et la programmation orientée ontologie. Enfin, j’en profiterai pour donner mon point de vue personnel sur le libre accès aux articles scientifiques.

Sommaire

Qu’est‐ce qu’une ontologie formelle ?

Les ontologies formelles sont un moyen de modéliser des connaissances. Par certains côtés, les ontologies ressemblent beaucoup aux modèles objets : on y retrouve les notions de classes, de propriétés et d’instances (appelées individus).

Les ontologies ont deux finalités principales :

  1. le raisonnement automatique : les ontologies définissent des concepts (telles que des classes) de manière logique et formelle. En utilisant un raisonneur, il est donc possible d’effectuer des déductions logiques. En particulier, le raisonneur peut « reclasser » les classes et les instances, c’est‐à‐dire calculer l’arbre d’héritage des classes et la (ou les) classe(s) de chaque instance, à partir de leurs propriétés ;
  2. les données liées (linked data) : toutes les ontologies partagent le même espace de nommage. Elles permettent donc de lier entre elles toutes les données existantes. En particulier, la définition d’une classe n’est pas nécessairement contenue dans un seul fichier : une ontologie peut très bien compléter la définition d’une classe issue d’une autre ontologie.

Par rapport aux modèles objet habituels, les ontologies possèdent une expressivité supérieure : elles permettent d’exprimer des contraintes logiques sur les classes, en s’appuyant sur les logiques de description. On peut par exemple créer la classe des « licences » et la classe des « systèmes d’exploitation ». La classe des « licences libres » est une sous‐classe de la classe « licence » (héritage). Nous pouvons ensuite définir la classe des « systèmes d’exploitation libres » comme équivalente à « un systèmes d’exploitation qui a une licence libre ». Tout système d’exploitation ayant (au moins) une licence libre pourra alors être automatiquement reclassé comme « système d’exploitation libre ».

La grande majorité des ontologies utilisent le langage OWL (Web Ontology Language, actuellement en version 2.0). Ce langage peut s’enregistrer en plusieurs formats, le plus employé étant RDF/XML. RDF sérialise l’ontologie sous forme de triplets (sujet, prédicat, objet), par exemple (individu, type, classe) pour renseigner la classe d’un individu ou (individu, propriété, valeur) pour renseigner ses attributs. Les contraintes logiques mentionnées ci‐dessus sont décomposées en plusieurs triplets RDF.

De nombreux outils existent pour traiter les ontologies OWL. Le plus connu est l’éditeur Protégé, qui permet de créer et d’éditer une ontologie en OWL.

En Python, le principal module existant est RDFLIB. Mais RDFLIB présente deux défauts :

  1. RDFLIB fonctionne au niveau RDF mais pas au niveau OWL. Il permet donc de gérer des triplets et des ressources (c’est‐à‐dire des objets), mais il n’est pas adapté pour gérer les classes et les contraintes logiques. Il n’intègre pas non plus de raisonneur ;
  2. en pratique, les performances de RDFLIB ne permettent pas de manipuler de grosses ontologies (plusieurs centaines de mégaoctets ou plusieurs millions de triplets).

Owlready et la programmation orientée ontologie

Trois approches existent pour intégrer une ontologie formelle dans un programme :

 Les API

Les API, comme OWLAPI en Java, permettent d’accéder aux ontologies à l’aide de classes correspondant aux éléments d’OWL. Par exemple, avec Java + OWLAPI, pour obtenir la propriété « prop » de l’objet « obj », qui est de type « float », on écrira :

OWLDataProperty prop = owlDataFactory.getOWLDataProperty(IRI.create("onto.owl#prop"));
float valeur = ((Float) obj.getPropertyValue(prop)).floatValue();

 Les langages de requêtes

Les langages de requêtes s’inspirent de SQL et l’adaptent à RDF. Le plus courant est SPARQL. Si l’on reprend l’exemple précédent en SPARQL, cela donnera :

SELECT ?valeur WHERE { ?obj :prop ?valeur . }

Ensuite, il faut exécuter la requête dans le langage de programmation, par exemple en Python avec RDFLIB, nous aurons :

valeur = graph.query("SELECT ?valeur WHERE { ?obj :prop ?valeur . }")

La programmation orientée ontologie

La programmation orientée ontologie permet de manipuler les classes et les individus de l’ontologie comme s’il s’agissait de classes et d’instances du langage de programmation. Si l’on reprend l’exemple précédent avec Python + Owlready, il suffira d’écrire :

valeur = obj.prop

On comprend donc rapidement que cette troisième approche est de loin la plus facile à utiliser, c’est donc celle que j’ai choisie pour Owlready. Owlready est un module pour Python 3 sous licence LGPL v3+, qui permet la programmation orientée ontologie. La version 2 d’Owlready intègre :

  • le raisonneur HermiT (N. B. : celui‐ci étant programmé en Java, il faut une machine virtuelle Java pour utiliser le raisonneur) ;
  • un quadstore RDF optimisé utilisant SQLite3. Un quadstore est une base de triplets RDF, auquel on ajoute un quatrième élément qui permet d’identifier de quelle ontologie provient le triplet. Ce quadstore peut être stocké en mémoire ou bien dans un fichier. De plus, le quadstore est compatible avec RDFLIB ;
  • des analyseurs pour les formats de fichiers RDF/XML, OWL/XML et NTriples.

Au final, Owlready cherche à obtenir le meilleur de trois mondes :

  1. la programmation orienté objet, pour l’encapsulation (c’est‐à‐dire la capacité à rassembler les données et les traitements associés : les méthodes) ;
  2. les ontologies formelles, pour l’expressivité (les contraintes logiques et les capacités de raisonnement automatique associées) ;
  3. les bases de données relationnelles, pour les performances (la capacité de stockage et la rapidité d’accès).

L’architecture, la syntaxe et les algorithmes utilisés dans Owlready ont été publiés dans un article récent de la revue Artificial Intelligence In Medicine, que l’on peut trouver sur mon site perso (je reviendrai plus bas sur la délicate question du libre accès aux articles scientifiques).

Notons qu’Owlready peut aussi être utilisé en lieu et place d’un ORM (Object Relational Mapper). Un ORM est une surcouche objet à une base de données (généralement SQL) et permet la persistance des objets, comme par exemple SQLAlchemy ou SQLObject en Python. Les tests montrent qu’Owlready conduit à un niveau de performance équivalent voire supérieur.

Exemple avec Owlready

Nous allons reprendre l’exemple précédent sur les licences libres et les systèmes d’exploitation, et le créer avec Owlready. La première ligne importe le module, la seconde crée une ontologie, la troisième (bloc with) indique que tout ce qui sera créé dans ce bloc (classes, propriétés, individus, etc.) sera défini dans l’ontologie « onto ». Ensuite nous définissons les classes, en héritant de Thing, qui est la classe la plus générale en OWL.

from owlready2 import *

onto = get_ontology("http://test.org/onto.owl")

with onto:

    class Licence(Thing): pass
    class LicenceLibre(Licence): pass
    class LicenceProprietaire(Licence): pass

    licence_proprio = LicenceProprietaire("licence_proprio")

    gpl  = LicenceLibre("gpl")
    lgpl = LicenceLibre("lgpl")

    class SystemeDExploitation(Thing): pass

    class a_pour_licence(ObjectProperty):
        domain = [SystemeDExploitation]
        range  = [Licence]

    gnu_linux = SystemeDExploitation("gnu_linux")
    gnu_linux.a_pour_licence = [gpl]

    windows = SystemeDExploitation("windows")
    windows.a_pour_licence = [licence_proprio]

    class SystemeDExploitationLibre(Thing):
        equivalent_to = [ SystemeDExploitation & a_pour_licence.some(LicenceLibre) ]

La propriété a_pour_licence est créée comme une classe fille d’ObjectProperty et nous définissons son domaine et son range. Le range correspond au « type » de la propriété, c’est‐à‐dire au type de valeur qu’elle peut prendre. Le domaine correspond à la classe qui possède cette propriété : contrairement aux modèles objet habituels, les propriétés ne sont pas définies pour une classe donnée mais indépendamment. Cela permet à une ontologie d’ajouter des propriétés aux classes définies dans une autre ontologie.
Enfin, l’exemple crée la classe SystemeDExploitationLibre, qui est définie comme équivalente à SystemeDExploitation et « a_pour_licence SOME LicenceLibre » (au moins une licence libre, donc).

Nous pouvons ensuite exécuter le raisonneur et afficher le résultat :

sync_reasoner()

print(gnu_linux.__class__)
# => onto.SystemeDExploitationLibre

Nous constatons que l’individu « gnu_linux » a été reclassé.

Et si nous voulons faire le même raisonnement pour les systèmes d’exploitation non libres ? C’est plus compliqué ! Nous pouvons créer la classe des « systèmes d’exploitation non libres » ainsi (notez le « Not » par rapport à tout à l’heure) :

with onto:
    class SystemeDExploitationNonLibre(Thing):
    equivalent_to = [ SystemeDExploitation & Not(a_pour_licence.some(LicenceLibre)) ]

Mais si vous exécutez le raisonneur, vous constaterez que Windows n’est pas reclassé en SystemeDExploitationNonLibre ! En effet, les raisonneurs fonctionnent selon l’assomption du monde ouvert : tout ce qui n’est pas défini est considéré comme possible. Nous avons défini que Windows avait une licence propriétaire, cependant nous n’avons pas dit que Windows n’avait pas d’autres licences (oui, certains logiciels ont plusieurs licences). Le raisonneur a donc considéré qu’il n’était pas impossible que Windows possède une autre licence, et que celle‐ci soit libre.

Nous devons donc indiquer que Windows possède seulement pour licence la licence propriétaire, ce qui peut se faire en ajoutant une contrainte OWL :

    windows.is_a.append( a_pour_licence.only(OneOf([licence_proprio])) )

Ou plus simplement, avec Owlready, en utilisant la fonction close_world() qui crée automatiquement les contraintes nécessaires pour considérer un individu ou une classe en « monde fermé » (c’est‐à‐dire pour asserter que tout est connu à leur sujet) :

    close_world(windows)
    close_world(gnu_linux)

Enfin, nous devons également définir que les classes LicenceLibre et LicencePropriétaire sont disjointes, c’est‐à‐dire qu’il n’existe pas de classe fille héritant des deux (une licence ne peut pas être à la fois libre et propriétaire). Cela se fait ainsi :

    AllDisjoint([LicenceLibre, LicenceProprietaire])

Nous pouvons ensuite exécuter de nouveau le raisonneur et afficher le résultat :

sync_reasoner()

print(windows.__class__)
# => onto.SystemeDExploitationNonLibre

Voilà, c’était un exemple simple de raisonnement logique, avec quelques pièges classiques.

À propos de l’accès libre aux articles scientifiques

La question du libre accès à la connaissance étant à la base du logiciel libre, j’aimerais revenir sur l’accès aux articles scientifiques. Les revues scientifiques font intervenir plusieurs acteurs : les auteurs des articles, les relecteurs (reviewers, chargés de corriger et d’évaluer l’article), l’éditeur (publisher, qui édite la revue) et les lecteurs. Historiquement, les auteurs et les relecteurs sont bénévoles (ce sont souvent des chercheurs payés par l’état), et le lecteur paie l’éditeur pour accéder à l’article (en général, il s’agit d’un abonnement institutionnel : un laboratoire ou une université paie un éditeur pour que ses chercheurs aient accès à telle ou telle revue). Donc, pas d’accès libre.

Il y a une vingtaine d’années sont apparues des revues en accès libre, avec un modèle différent : ce sont les auteurs qui paient l’éditeur, et le lecteur accède gratuitement à la revue (en ligne). Ce modèle a notamment été lancé par PLOS, avec un certain succès. La qualité des revues se mesure notamment à leur facteur d’impact, c’est‐à‐dire le nombre de fois où les articles publiés sont cités dans les deux ans qui suivent la publication. L’idée derrière les revues en accès libre est la suivante : les articles étant librement accessibles, ils seront davantage lus et donc plus cités.

Mais ce n’est pas si simple : le nombre de citations ne suffit pas à faire la qualité… Dans une revue où l’auteur paie, l’éditeur a tout intérêt à faire en sorte qu’un maximum d’articles soit accepté, même si certains sont de mauvaise qualité, puisqu’il est payé à chaque article accepté. En fait, l’éditeur n’a qu’à dire « oui » et il est payé… On voit donc exploser le nombre de revues et d’éditeurs de ce type, avec un niveau de qualité souvent très faible. Et du coup les chercheurs sont régulièrement sollicités (pour ne pas dire « spammés ») par ce type d’éditeurs…

Les éditeurs « classiques » ont auss  réagi par rapport au libre accès. Toutes sortes « d’exceptions » ont été mises en place. Par exemple pour la revue Artificial Intelligence In Medicine (édité par Elsevier) où j’ai publié :

  1. les auteurs peuvent payer pour avoir leur article en libre accès (N. B. : hors de prix, mais certains projets de recherche, notamment européen, exigent que ce soit le cas) ;
  2. un lien est fourni aux auteurs qui permet de télécharger gratuitement l’article pendant 50 jours, et ce lien peut être diffusé à volonté ;
  3. après six mois d’embargo, une « version auteur » (même contenu que le vrai article, mais sans la mise en forme de l’éditeur) peut être mise à disposition librement sur des serveurs comme HAL (Hyper‐Archives en Ligne) ;
  4. les auteurs ont le droit de mettre une « version auteur » sur leur site personnel dès la parution de l’article, sous licence Creative Commons Attribution Non‐Commercial No Derivatives ».

Nous ne sommes donc pas loin d’un accès libre (surtout grâce au dernier point), à condition que les auteurs fassent l’effort de produire et mettre en ligne cette « version auteur ».

Aller plus loin

  • # j'ai pas tout saisi.

    Posté par  (site web personnel) . Évalué à 6.

    Salut,
    Le sujet de l'article est vraiment sympa, c'est quelque chose que je ne connais pas du tout. par contre après avoir lu et relu, j'ai cette sensation de lire quelque chose de génial mais de pas comprendre de quoi il s'agit vraiment. Du coup bravo pour l'article, qui va me conduire à quelques heures de recherche sur le web pour essayer d'en savoir plus.

    Par contre je sais pas si c'est moi qui suis à la ramasse sur un sujet connu ou pas.

    «Un peuple qui élit des corrompus, des rénégats, des imposteurs, des voleurs et des traîtres n’est pas victime! Il est complice» — G Orwell

    • [^] # Re: j'ai pas tout saisi.

      Posté par  (site web personnel) . Évalué à 4.

      Qu'est-ce que tu n'as pas compris?

      Pour avoir lu toute la doc sur Nepomuk, le desktop sémantique, et même avoir fait un plugin Firefox s'interfaçant avec Nepomuk (en 2010), je peux t'assurer que c'est très clair, par rapport à ce que j'ai dû ingurgiter comme doc.

      • [^] # Re: j'ai pas tout saisi.

        Posté par  . Évalué à 5.

        Moi aussi j'ai trouvé ça très bien exposé et facile à comprendre. Rattaché les explications à la POO m'a beaucoup aidé.

        Je te rejoins à propos des articles classiques sur RDF et OWL qui ne convainquent que les convaincus. Ils sont difficiles à lire et vendent très mal ce qu'ils présentent.

        Merci pour cette dépêche accessible au développeur habitué à la POO.

    • [^] # Re: j'ai pas tout saisi.

      Posté par  . Évalué à 3.

      Comme pour la POO donnée en exemple dans l'article. Il faut rencontrer des cas concrets et pratiquer pour vraiment comprendre.

    • [^] # Re: j'ai pas tout saisi.

      Posté par  (site web personnel) . Évalué à 8.

      Je confirme que ce n'est pas évident à saisir. J'ai moi aussi eu du mal au début… C'est un peu comme lorsqu'on commence la programmation objet alors qu'on a fait que de la programmation impérative sans objet avant : c'est une logique différente. J'ai essayé de faire de mon mieux pour illustrer ça clairement dans l'article, mais c'est sûrement perfectible.
      On considère souvent qu'il y a 2 manières de définir une classe : par intention et par extension. Par extension, c'est la méthode usuelle en POO : on indique pour chaque instance quelle est sa classe. Par intention, c'est la méthode privilégiée dans les ontologies : on donne une définition des propriétés de la classe, et ensuite la machine se débrouille pour attribuer les classes aux instances. Je ne sais pas si c'est plus clair dit comme ça ?

    • [^] # Re: j'ai pas tout saisi.

      Posté par  . Évalué à 4.

      La clé, c’est qu’on parle de raisonnement et pas de « programmation » au sens traditionnel.

      Il y a un genre de « sémantique » aussi chez les universitaires quand on parle de programmation, Sémantique des langages de programmation. Mais c’est différent, on parle de « c’est quoi un programme qui fait ce qu’on lui demande » ou « que fait un programme ». Il s’agit de spécifier, dans un langage « autre » comme un langage logique mathématique les propriétés du programme qu’on veut écrire, de vérifier que notre programme fait bien ce qu’on avait l’intention de lui faire faire.

      Ici c’est différent, on parle avant tout de donner des propriétés des données et des structures de données qui permettent de raisonner, de lui brancher un moteur de raisonnement logique type prolog qui permettent de vérifier, à terme, si notre jeu de données est propre. Par exemple en partant de la définition d’un logiciel libre, on peut détecter si un logiciel dans nos données est marqué à la fois comme libre et comme non redistribuable. Une telle erreur détectée par le moteur de raisonnement indique soit qu’on a un problème dans nos données soit qu’on a un problème dans notre ontologie.

      Pour faire le lien avec le monde des langage de programmation, on peut imaginer qu’une fonction buguée fasse un traitement sur les donnés qui renvoie parfois un logiciel à la fois libre et non redistribuable. On dit que cette fonction « casse l’invariant » dans la méthode B par exemple. L’invariant étant une proprété logique que douvent tout le temps (enfin « atomiquement » on va dire, au cours d’une opération on est autorisé à le casser) respecter les données. Pr exemple, qeu le nombre de ticket vendu doit ètre inférieur au nombre de place disponibles. Si tu lance le moteur d’inférence après un tel cas de figure, tu auras détecté un bug du programme (ou de l’ontologie encore une fois).

      J’ai l’impression que d’une certaine manière ici brancher une ontologie OWL sur un programme python est le moyen de brancher un tel invariant sur python, donc de définir certaines propriétés de la sémantique attendue du programme.

    • [^] # Re: j'ai pas tout saisi.

      Posté par  . Évalué à 4.

      Un MOOC sur France Université Numérique aborde le sujet : Web sémantique et Web de données

  • # Avec des exemples plus concrets

    Posté par  . Évalué à 2.

    Je n'avais effectivement pas bien compris, mais l'exemple de la doc Owlready + le fichier OWL d'exemple utilisé + une visualisation de l'exemple clarifient bien la chose.

    Merci pour l'article ! Ça me sera sans doute utile pour un projet perso :).

  • # Idée de projet inutile

    Posté par  . Évalué à 2.

    (parfaitement indispensable, sans doute)

    Réécrire la grammaire Python en OWL.

    grammaire

  • # Quelques retours sur le code

    Posté par  (site web personnel) . Évalué à 6.

    Bravo pour l'article, je ne connaissais pas du tout ce type de programmation, maintenant ma curiosité a été piquée ;-)

    Aurais-tu des exemples de d'application non triviaux dans lesquels ce type de programmation fonctionne bien ?

    Sinon j'ai parcouru rapidement le code et j'ai quelques conseils :

    • Ton module utilise java sous le capot. Il serait bien d'en parler dans le READEME (ce n'est vraiment pas une dépendance anodine) et même de permettre à l'utilisateur de configurer quel java utiliser (via variable d'env par exemple).

    • Il aurait été mieux de créer un répertoire owlready dans ton repo contenant le code python, l'avantage étant que la racine du repo est beaucoup moins fournie donc plus lisible, ainsi que le fait de pouvoir utiliser ton module sans avoir à l'installer en se étant dans le répertoire du projet.

    • Ton répertoire test n'utilise pas de framework de test, je te conseil pytest qui est absolument génial (tu créé un fichier commençant par test_, tu mets des fonctions commençant par test_ qui font des assert et tu lances le tout avec avec py.test, c'est brillant de simplicité et extrêmement puissant). L'avantage étant que tu auras des rapport sur tes tests beaucoup plus précis et que tu pourras être beaucoup plus expressif dans tes tests (fixtures, setup/teardown, modules tiers etc.)

    • De même je te conseils d'utiliser travis qui te permettra de faire de l'intégration continue (d'autant plus importante si tu cherches à avoir des contributeurs externes)

    • La PEP8 n'est pas respecté, vu que c'est le standard ça rend tout de suite le code moins lisible. Il y a des outils comme autopep8 qui te permettent de mettre en forme ta base de code automatiquement, et flake8 en linter pour faire de la PEP8 sans y penser ;-)

    • Les import * sont à proscrire (allez, à la rigueur on peut les utiliser dans le __init__.py quand celui-ci se contente de definir l'api exposée), ça rend le code beaucoup plus complexe quand on ne le connait pas, d'autant plus quand on le consulte en ligne et qu'on ne peut pas faire des greps dans le projet :'-(

    • Mettre plusieurs commandes sur une même lignes via les point-virgules rend les choses confus, d'autant plus avec une indentation à 2 espaces, exemple qui m'a fait saigner:

    class CallbackList(FirstList):
      __slots__ = ["_obj", "_callback"]
      def __init__(self, l, obj, callback):
        super().__init__(l)
        self._obj      = obj
        self._callback = callback
      def _set  (self, l):          super().__init__(l)
      def _append(self, x):         super().append(x)
      def _remove(self, x):         super().remove(x)
      def reinit(self, l):          old = list(self); super().__init__(l)       ; self._callback(self._obj, old)
      def append(self, x):          old = list(self); super().append(x)         ; self._callback(self._obj, old)
      def insert(self, i, x):       old = list(self); super().insert(i, x)      ; self._callback(self._obj, old)
      def extend(self, l):          old = list(self); super().extend(l)         ; self._callback(self._obj, old)
      def remove(self, x):          old = list(self); super().remove(x)         ; self._callback(self._obj, old)
      def __delitem__(self, i):     old = list(self); super().__delitem__(i)    ; self._callback(self._obj, old)
      def __setitem__(self, i, x):  old = list(self); super().__setitem__(i, x) ; self._callback(self._obj, old)
      def __delslice__(self, i):    old = list(self); super().__delslice__(i)   ; self._callback(self._obj, old)
      def __setslice__(self, i, x): old = list(self); super().__setslice__(i, x); self._callback(self._obj, old)
      def __iadd__(self, x):        old = list(self); super().__iadd__(x)       ; self._callback(self._obj, old); return self
      def __imul__(self, x):        old = list(self); super().__imul__(x)       ; self._callback(self._obj, old); return self
      def pop(self, i):             old = list(self); r = super().pop(i)        ; self._callback(self._obj, old); return r
    

    Je le répète, j'ai beaucoup apprécié ton article et j'espère que tu ne prendras pas mal ces remarques qui sont plus sur la forme que le fond ;-)

    • [^] # Re: Quelques retours sur le code

      Posté par  (site web personnel) . Évalué à 6.

      Pour des exemples non triviaux, il y a les médicaments (c'est pour ça à l'origine que j'ai développé Owlready). Je donne un cas d'utilisation à la fin de l'article dans AIM; cet exemple est aussi décrit dans cet article en français :

      https://hal-univ-paris13.archives-ouvertes.fr/hal-01168293/document

      Le problème est que les médicaments partagent des contre-indications, mais que celles-ci sont décrites de manière tellement variable qu'il est difficile de comprendre qui partage quoi (même pour un expert !). Par exemple tel médicament contre-indiqué avec les maladies inflammatoires intestinales ne pourra pas être prescrit chez un patient qui a la maladie de Crohn—parce qu'elle rentre dans la catégorie "maladies inflammatoires intestinales". Les catégories sont multiples, et se recoupent souvent. Tel autre médicament sera contre-indiqué dans les maladies hémorragiques constitutionnelle ou acquises. Mais comme "acquise" est le contraire de "constitutionnelle", ça veut tout simplement dire "contre-indiqué dans les maladies hémorragiques". Comment faire comprendre à un ordinateur que "acquis" et "constitutionnel" sont opposés ? Les ontologies le permettent.

      J'ai une manière particulière d'écrire mon code, je sais… heureusement à l'université ça ne pose pas problème vu que nombre de mes collègues programment peu, voire pas.
      Souvent j'essaie d'aligner ce qui va ensemble, par exemple je préfère :

      A; B
      A; B
      A; B
      … (un peu comme dans un tableau)

      plutôt que :
      A
      B
      A
      B
      A
      B

      où l'alternance des lignes A et B ne facilite pas la lecture !

      • [^] # Re: Quelques retours sur le code

        Posté par  . Évalué à 6.

        J'aime bien voir les ontologies comme des façons de voir / représenter le monde, en tout cas dans un domaine particulier. D'autres diraient des modèles.

        D'autres exemples d'ontologies OWL utilisées dans la vraie vie : les projets de recherche Olia, LexInfo et Lemon, pour le traitement des langues :
        - http://www.acoli.informatik.uni-frankfurt.de/resources/olia/
        - http://www.lexinfo.net/
        - http://lemon-model.net/

        Ces ontologies permettent notamment de classer, de qualifier, de décrire les mots et les éléments du langages. Ce qui permet entre autres de produire des dictionnaires qui peuvent être traités automatiquement, d'étiqueter des mots / groupes de mots dans des textes, ce qui a des applications en traduction automatique, en récupération automatique d'informations à partir de textes écrits dans des langues naturelles.

        Histoire d'avoir un truc concret à regarder, voici l'entrée de dictionnaire de l'adjectif bleu dans une version de DBnary d'il y a 3 ans (DBnary étant un dictionnaire produit à partir du Wiktionnaire - décidément, on va croire que j'en fais la pub ici, mais il faut dire que ça s'y prête). La représentation est Turtle, qui permet de représenter du RDF de façon assez lisible et compacte. Le mot est défini / décrit / classé à l'aide des ontologies lexinfo et lemon, notamment.

        fra:bleu__adj__1
            a                         lemon:Word ;
                dbnary:hyponym        fra:bleu_barbeau , [...], fra:bleu_de_fécule ;
                dbnary:partOfSpeech   "-adj-" ;
                lexinfo:partOfSpeech  lexinfo:adjective .
                dbnary:synonym        fra:azur ;
                dcterms:language      lexvo:fra ;
                lemon:language        "fr" ;
                lemon:canonicalForm   [ lemon:writtenRep       "bleu"@fr ;
                                        lexinfo:gender         lexinfo:masculine ;
                                        lexinfo:number         lexinfo:singular ;
                                        lexinfo:pronunciation  "blø"@fr-fonipa ] ;
                lemon:otherForm       [ lemon:writtenRep  "bleues"@fr ;
                                        lexinfo:gender    lexinfo:feminine ;
                                        lexinfo:number    lexinfo:plural ] ;
                lemon:otherForm       [ lemon:writtenRep  "bleus"@fr ;
                                        lexinfo:gender    lexinfo:masculine ;
                                        lexinfo:number    lexinfo:plural ] ;
                lemon:otherForm       [ lemon:writtenRep  "bleue"@fr ;
                                        lexinfo:gender    lexinfo:feminine ;
                                        lexinfo:number    lexinfo:singular ] ;
                lemon:sense           fra:__ws_1_bleu__adj__1 , [...], fra:__ws_6_bleu__adj__1 ,
                                      fra:__ws_3_bleu__adj__1 , fra:__ws_4_bleu__adj__1 ;
        

        Bien sûr, le nom bleu est un mot différent et il a sa propre entrée. Une propriété peut avoir plusieurs valeurs (objets, en fait) comme dit dans le journal, ici l'adjectif a plusieurs sens qui sont référencés dans ce dictionnaire. La propriété spéciale "a", en Turtle, indique le type de l'objet (ou plutôt du sujet, puisque l'objet, c'est ce par quoi on qualifie le sujet à l'aide d'une propriété, en RDF) . C'est un raccourci pour la propriété rdf:type, ou plutôt http://www.w3.org/1999/02/22-rdf-syntax-ns#type, parce qu'en fait, en RDF, beaucoup de choses sont des IRIs (Internationalized Resource Identifier, une généralisation de l'URI), et toutes les propriétés en sont.
        Les crochets dénotent des sujets qui sont anonymes dans la représentation Turtle, et contiennent des listes de couples (propriété, objet) qui définissent le sujet.

        La représentation n'est pas fermée, on peut rajouter d'autres couples (propriété, objet) au sujet fra:bleu__adj__1, et on peut même attacher des propriétés de différentes ontologies à un même objet, pourvu que les représentations ne soient pas trop incompatibles entre elles. C'est le cas dans l'exemple.

        J'espère que je me suis exprimé assez clairement.

    • [^] # Re: Quelques retours sur le code

      Posté par  . Évalué à 4. Dernière modification le 05 septembre 2017 à 16:03.

      Les exemples d'utilisation d'ontologies se trouvent aussi dans http://dbpedia.org/ ou http://wikidata.org/ (https://www.wikidata.org/wiki/Help:About_data semble intéressant)

      http://lov.okfn.org/ est une site qui tente de référencer les ontologies existantes (tu peux par exemple chercher le nom d'une propriété ou classe et voir quel ontologies la définissent)

      Le but du Web des données est d'avoir des sources de données liées entre elles (comme les pages web sont liées par les hyperliens), les ontologies elles même sont faites pour se croiser. Elles modélisent normalement un domaine de savoir bien défini. Ainsi le vocabulaire définissant un évènement peut emprunter la notion de participant qui est une personne à FoaF (Friend of a friend, un vocabulaire de liens sociaux). http://lov.okfn.org/dataset/lov/vocabs/event ici tu vois le incoming et outgoing links.

      Ainsi si une conférence publie ses évènements en RDF, elle pourra lier le conférencier a une uri, dont tu pourrais retrouver la trace dans la base de son université pour avoir d'autres caractéristiques.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.