Más cosas que voy implementando en mi biblioteca OWL para Clojure.
En otro post, mostré como se podía definir la TBox, con un procedimiento similar al de usar migraciones para definir el esquema de una base de datos relacional. Ahora vamos mostrar lo que sería el equivalente ontológico a insertar filas en las tablas del esquema relacional, es decir a insertar aserciones en la ABox.
Creamos una TBox de prueba:
(describe-tbox (describe-owl-class :test "Person") (describe-owl-datatype-property :test "name" (xsd-string)) (describe-owl-datatype-property :test "age" (xsd-decimal)) (describe-owl-class-has-property :test "Person" :test "name") (describe-owl-class-has-property :test "Person" :test "age"))
Una vez guardada la TBox en un repositorio e iniciada (con alias :test-Person, :test-name y :test-age para los recursos), podremos crear individuos en la ABox que sean tipos de las clases OWL contenidas en la TBox, para ello usamos la función (abox-create-individual)
(abox-create-individual :test-Person
"http://test.com/abox/people#"
{ :test-name "Helena",
:test-age 24 })
Esta función crea un nuevo individuo con URI "http://test.com/abox/people#IDENTIFIER", donde IDENTIFIER es un identificador universal único (UUID) que se genera con la llamada a la función. La función inserta los tripletes RDF necesarios para asertar que el individuo recién creado es del tipo :test-Person, así como de todas sus superclases (en este caso owl:Thing). Además da valores a las propiedaded test:name y test:age.
Los tripletes RDF equivalentes serían (con notación Turtle):
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . @prefix test: <http://test.com/tbox/people#> . @prefix owl: <http://www.w3.org/2002/07/owl#> . @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . <"http://test.com/abox/people#IDENTIFIER"> rdf:type test:Person ; rdf:type owl:Thing ; test:age "24"^^xsd:decimal ; test:name "Helena"^^xsd:string .
A la hora de crear individuos en la ABox, hay que tener en cuenta que se pueden crear individuos con valores sólo para algunas propiedades, o con propiedades no definidas en la clase OWL o ni siquiera en la TBox. Una de las características de las lógicas descriptivas, la base formal de OWL, es que tienen una semántica denominada de "mundo abierto" (ver el "Cambridge Handbook of DL"). Siguiendo una semántica "open world", si una información no se ha asertado en la ontología, no quiere decir que no exista, sino que todavía no se conoce. Lo mismo sucede para la información extra. Es interesante comparar esta semántica con una semántica de "mundo cerrado", como la que siguen las bases de datos relacionales, donde si un dato no está en la tabla, significa un error, no desconocimiento. Esta situación se agrava cuando contamos con pocos constructores OWL y no hay soporte para un razonador, si no que se trabaja solo con las aserciones explícitas de la ontología.
Una forma de poner restricciones a lo que insertamos en la ABox, sin recurrir a hacer un test de consistencia con un reasoner tras realizar las aserciones, es permitir añadir validaciones a los recursos descritos en la TBox. Estas validaciones se realizan cuando se quiere hacer una aserción en la ABox para ver si la aserción está permitida o no, controlando qué es válido y qué no es válido asertar. Aún así, esta solución no deja de ser una pequeña chapuza, ya que perdemos la información de las validaciones que no está contenida en la ontología, por lo que siempre que sea posible, se debe modelar correctamente la ontología, insertando la información posible y después añadir las validaciones.
Estas validaciones, son predicados y se pueden realizar en el registro de la TBox. y pueden ir asociadas a cualquier acción y recurso. Por ejemplo:
(tbox-register-name! :owl-thing (owl-Thing) :connection) (tbox-register-name! :test-Person :test "Person" :connection) (tbox-register-name! :test-age :test "age" :connection) (tbox-register-name! :test-name :test "name" :connection) (tbox-register-validation-on! :create :test-age (fn [age] (> (:value age) 18)))
En este caso, comprobamos que al crear un nuevo individuo que da valor a la propiedad test:age, el valor de la edad es mayor que 18. En este caso la validación es para un propiedad, y se comprobaría cuando se realizase una acción sobre cualquier clase con esa propiedad, de esta manera se pueden reutilizar las validaciones entre diferentes clases. Cuando la validación es a nivel de clase, pero no común para las propiedad compartida entre clases, se puede registrar la validación a nivel de clase:
(tbox-register-name! :test-AdultPerson :test "AdultPerson" :connection) (tbox-register-validation-on! :create :test-AdultPerson (fn [properties] (> (:value (:test-age properties)) 18)))
Así se comprobaría el predicado cuando se crea un individuo de la clase test:AdultPerson, pero no cuando ce crea cualquier otro individuo de una clase relacionada con la propiedad test:age.
Con las validaciones se pueden ofrecer una semántica para casi todo: propiedades obligatorias, formato correcto de valores ... siempre que no sean excusa para perder información que podría haberse asertado algún constructor de OWL, como allValuesFrom, etc.
