Publicidad:
La Coctelera

un rato de sol

i will work harder, ja ja ja, no ahora en serio.

5 Enero 2009

Una capa de persistencia de datos semántica basada en OWL

Hoy en día la norma para desarrollar la capa de persistencia de una aplicación web consiste en desarrollar un esquema para algún sistema de base de datos relacional en el que almacenar los datos.
Esto supone básicamente darle golpes a tus objetos hasta convertirlos en conjuntos de enteros, cadenas, etc que después se vuelven a encajar en tablas, indicando relaciones entre esas tablas duplicando valores en columnas especiales de esas tablas. Estamos tan acostumbrados a hacerlo de esta manera que ni nos damos cuenta de la gran distancia que media entre nuestro modelo objetual, con el que trabajamos en nuestro código, y el nivel de abstracción mucho más bajo con el que almacenamos una representación persistente de esos datos.

Sin embargo, esto no tendría porque ser así. Cuando creamos y modelamos nuestro dominio de datos para la aplicación, no hacemos más que crear una ontología, una descripción de los recursos del dominio y sus relaciones, y en los últimos años se ha estandarizado un lenguaje para la descripción de ontologías por parte de la W3C: OWL.

OWL nace del mundo de la lógica descriptiva y permite describir las dos partes que componen una ontología:

  • Una TBox: o terminological box, donde describimos una terminología, los tipos de recursos y relaciones, por ejemplo, existen cosas llamadas personas, existe una relación entre una cosa y un número llamada tener edad, etc...
  • Una ABox: o assertional box, donde hacemos aserciones usando los términos de la TBox, por ejemplo: Juan es una persona, Juan tiene una edad de 15, etc...

A continuación mostraré una biblioteca para describir una TBox en Clojure lisp.

Nuestra primera tarea es tener un sitio donde almacenar la TBox, para ello debemos tener una conexión con un repositorio. Con el siguiente código creamos un repositorio en memoria y lo registramos con un nombre para usarlo posteriormente:

  (register-repository! :test (init-memory-repository!))
 

A continuación podemos pasar a describir nuestra TBox para la ontología que vamos a describir, la famosa aplicación para escribir blogs, para ello usamos las funciones (describe-owl-*):

 (write-graph-in-repository
    (describe-tbox
       ;; algunas propiedades de datos
       (describe-owl-datatype-property :superblog "title" (xsd-string))
       (describe-owl-datatype-property :superblog "content" (xsd-string))
       (describe-owl-datatype-property :superblog "name" (xsd-string))
                 
       ;; algunas clases
       (describe-owl-class :superblog "Blog")
       (describe-owl-class :superblog "Post")
       (describe-owl-class :superblog "Author")
                
       ;; asignamos propiedades a clases
       (describe-owl-class-has-property :superblog "Blog" :superblog "title")
       (describe-owl-class-has-property :superblog "Post" :superblog "title")
       (describe-owl-class-has-property :superblog "Post" :superblog "content")
       (describe-owl-class-has-property :superblog "Author" :superblog "name")
 
       ;; algunas propiedades de objetos
       (describe-owl-object-property :superblog "contains")
       (describe-owl-object-property :superblog "writes")
 
       ;; relaciones entre clases
       (describe-owl-class-has-property :superblog "Blog" :superblog "contains")
       (describe-owl-property-range :superblog "contains" :superblog "Post")
       (describe-owl-class-has-property :superblog "Author" :superblog "writes")
       (describe-owl-property-range :superblog "writes" :superblog "Post"))
 
    ;; seleccionamos la conexion con el repositorio anteriormente registrado
    (connection! :test))
 

El código anterior es equivalente a escribir una migración en Ruby on Rails, pero el hecho de usar OWL en vez de directamente una base de datos relacional, nos aporta una serie de beneficios, por ejemplo, la reutilización del esfuerzo empleado en modelar el dominio. En el ejemplo anterior podemos darnos cuenta de que las relaciones como título, ser autor de, etc, ya han sido modelados y estandarizados dentro del Dublin Core Metadata Initiative (http://en.wikipedia.org/wiki/Dublin_Core), ¿por qué no utilizar el soporte para el Dublin Core que incluye la biblioteca? La reutilización se basa en el concepto de kits de vocabularios, que incluyen clases y propiedades y funciones que trabajan sobre estas partículas OWL:

 (use 'com.agh.webserver.framework.persistence.rdf.vocabularies.dc)
 
 ;; cargamos la descripción del Dublin Core en el repositorio de test
 (import-vocabulary-kit :dc (connection! :test)) 
 
 ;; buscamos sinonimos entre nuestro dominio y el DC
 (write-graph-in-repository
    (describe-tbox
       (describe-owl-equivalent-properties :superblog "title" (dc-title))
       (describe-owl-equivalent-properties :superblog "writes" (dc-creator)))
    (connection! :test))
 

La descripción de la TBox de la ontología está en este momento almacenada en el repositorio, para poder usar la TBox de forma eficiente debemos iniciar la TBox al empezar a usar nuestra aplicación declarando que recursos de la ontología almacenada en el repositorio queremos utilizar:

   ;; iniciamos la TBox
  (tbox-register-name! :owl-thing (owl-Thing) :test)
  (tbox-register-name! :superblog-Post "http://superblog.com/Post" :test)
  (tbox-register-name! :superblog-Blog "http://superblog.com/Blog" :test)
  (tbox-register-name! :superblog-Author "http://superblog.com/Author" :test)
  (tbox-register-name! :superblog-content "http://superblog.com/content" :test)
  (tbox-register-name! :superblog-title "http://superblog.com/title" :test)
  (tbox-register-name! :superblog-name "http://superblog.com/name" :test)
  (tbox-register-name! :superblog-post "http://superblog.com/contains" :test)
  (tbox-register-name! :superblog-post "http://superblog.com/writes" :test)
 
  ;; iniciamos el kit de Dublin Core con los nombre por defecto que asigna la 
  :: biblioteca
  (tbox-register-vocabulary-dc :test)
 
   ;; el codigo de la aplicacion empezaria aqui
 

Ahora ya podríamos acceder a los recursos mediante su URI o mediante el nombre con el que se ha registrado. Un test que muestra la interacción entre las diferentes partes, además de la inferencia entre propiedades y subclases, podría ser:

 (deftest test-class-subclassing
   (let [orig-tbox @*tbox*
         orig-conn @*connections*
         orig-repos @*repositories-registry*
         repo (init-memory-repository!)
         graph (describe-tbox
                (describe-owl-datatype-property "http://test.com/prop_a" (xsd-float))
                (describe-owl-datatype-property "http://test.com/prop_b" (xsd-float))
                (describe-owl-class "http://test.com/class_a")
                (describe-owl-class "http://test.com/class_b")
                (describe-owl-class "http://test.com/class_c")
                (describe-owl-subclass "http://test.com/class_a" "http://test.com/class_b")
                (describe-owl-subclass "http://test.com/class_a" "http://test.com/class_c")
                (describe-owl-class-has-property "http://test.com/class_a" "http://test.com/prop_a")
                (describe-owl-class-has-property "http://test.com/class_b" "http://test.com/prop_b"))]
     (do (tbox-clear!)
         (register-repository! :test repo)
         (write-graph-in-repository graph (connection! :test))
         (tbox-register-name! :owl-thing (owl-Thing) :test)
         (tbox-register-name! :class_a "http://test.com/class_a" :test)
         (tbox-register-name! :class_b "http://test.com/class_b" :test)
         (tbox-register-name! :class_c "http://test.com/class_c" :test)
         (tbox-register-name! :prop_a "http://test.com/prop_a" :test)
         (tbox-register-name! :prop_b "http://test.com/prop_b" :test)
         (let [class-recovered (tbox-find-class-by-uri! "http://test.com/class_a")]
           (do 
               (is (= class-recovered
                      {:name :class_a
                       :uri "http://test.com/class_a"
                       :subclass-of [{:name :class_a
                                      :uri {:prefix "", :value "http://www.w3.org/2002/07/owl#Thing"}
                                      :subclass-of []
                                      :datatype-properties #{}
                                      :object-properties #{}
                                      :repository-name :test}
                                     {:name :class_b
                                      :uri {:prefix "", :value "http://test.com/class_b"}
                                      :subclass-of [{:name :owl-Thing
                                                     :uri {:prefix "", :value "http://www.w3.org/2002/07/owl#Thing"}
                                                     :subclass-of []
                                                     :datatype-properties #{}
                                                     :object-properties #{}
                                                     :repository-name :test}]
                                      :datatype-properties #{{:name nil
                                                              :uri
                                                              {:prefix "", :value "http://test.com/prop_b"}
                                                              :range {:prefix "", :value "http://www.w3.org/2001/XMLSchema#float"}
                                                              :equivalent-properties #{}
                                                              :repository-name :test}}
                                      :object-properties #{}
                                      :repository-name :test}
                                     {:name :class_c
                                      :uri {:prefix "", :value "http://test.com/class_c"}
                                      :subclass-of [{:name :owl-Thing
                                                     :uri {:prefix "", :value "http://www.w3.org/2002/07/owl#Thing"}
                                                     :subclass-of []
                                                     :datatype-properties #{}
                                                     :object-properties #{}
                                                     :repository-name :test}]
                                      :datatype-properties #{}
                                      :object-properties #{}
                                      :repository-name :test}]
                       :datatype-properties #{{:name :prop_b
                                               :uri {:prefix "", :value "http://test.com/prop_b"}
                                               :range {:prefix "", :value "http://www.w3.org/2001/XMLSchema#float"}
                                               :equivalent-properties #{}
                                               :repository-name :test}
                                              {:name :prop_a
                                               :uri
                                               {:prefix "", :value "http://test.com/prop_a"}
                                               :range {:prefix "", :value "http://www.w3.org/2001/XMLSchema#float"}
                                               :equivalent-properties #{}
                                               :repository-name :test}}
                       :object-properties #{}
                       :repository-name :test}
               (tbox-restore! orig-tbox)
               (repositories-register-restore! orig-repos)
               (connections-restore! orig-conn))))))
 

Al igual que OWL se situa sobre una pila de protocolos de la W3C para la web semántica, en concreto, una ontología OWL se codifica como un grafo RDF que a su vez se puede describir como un documento XML, la biblioteca OWL usa la bibliteca RDF que comenté anteriormente para describir los recursos en términos de constructores de un grafo RDF y recupera su información transformando ese grafo en consultas SPARQL.

En siguientes posts, veremos como usar esta TBox para hacer aserciones sobre objetos concretos dentro de la ABox.

Aunque todavía se encuentra muy lejos de ser usable para nada, si queréis hacer pruebas y juguetear con él, el código se encuentra disponible en mi repositorio de Github.

Tags: lisp, clojure, owl

servido por Antonio sin comentarios compártelo

sin comentarios · Escribe aquí tu comentario

Escribe tu comentario


Sobre mí

Avatar de Antonio

un rato de sol

Barcelona/Salamanca, España
ver perfil »
contacto »
Trabajador del metal y del acero, en la gloriosa XING AG, escribo software con el que poder ganarme el jornal. En mi tiempo libre sigo tecleando código de bonitos colores a medio camino entre lo sublime y lo terrible. Últimamente me gustan mucho los gatos.

Fotos

Antonio Garrote Hernández todavía no ha subido ninguna foto.

¡Anímale a hacerlo!

Buscar

suscríbete

Selecciona el agregador que utilices para suscribirte a este blog (también puedes obtener la URL de los feeds):

¿Qué es esto?

Crea tu blog gratis en La Coctelera