sábado, 27 de julio de 2013

I'm back. TODO list


  • Posible refactor de la API (facilitar su mantenimieno). Estudiar añadir Guava
  • Mejorar tests de la API
  • Añadir queries cypher
  • Sistema de queries dinámicas
  • Mejorar documentación (javadoc?) y logging
Vista:
  • Interfaz REST para la API
  • Buscar tecnología para servidor REST (Spring, Jersey, Wink, JBOSS, JEE)
  • d3: pruebas de concepto
  • Diseño de protitpos y casos de uso

domingo, 21 de abril de 2013

Capa de presentación

Para la capa de presentación utilizaremos la librería js d3:
http://d3js.org/

Mediante dicha librería y una interfaz REST de nuestros métodos de manipulación y búsqueda sobre los datos del graf, podremos realizar la capa de presentación de un modo ágil y rápido.

Bastará con adaptar nuestros datos de nodos y relaciones a un formato JSON predeterminado por d3 e implementar el web service REST con todos los métodos necesarios. Nos podrán ayudar:
-GSON (transformación de objetos a formato JSON)
-Spring RESTful services (una opción para crear el WS REST)

La aplicación mostrará en todo momento el grafo, mientras nos permite realizar otras operaciones:
-Permitirá ejecutar los 3 tipos de búsquedas descritos en la entrada anterior, mediante varios formularios. Los nodos y/o relaciones devueltos serán resaltados.
-Al pinchar sobre un nodo, podremos ver todas sus propiedades y se abrirá un menú para ejecutar cambios sobre el mismo, por ejemplo crear/eliminar alguna dependencia o atributo.
-Sería muy interesante disponer de herramientas de visualización del grafo. Por ejemplo, resaltar u ocultar un determinado tipo de relación o nodo.

El modelo de datos GedcomX es bastante completo y complejo. Por ello, creemos que sería necesario mostrar al usuario una versión simplificada del mismo. Tenemos varias opciones, y conforme vaya conociendo la librería d3 podrían aparecer nuevas opciones o descartar otras:
-Resaltar los nodos más importantes y sus relaciones: Persons y Relationships.
-Ocultar nodos menos importantes.
-Mostrar una capa de abstracción sobre el grafo original. El nodo Person sería un "supernodo". Al pinchar sobre Person, veríamos el detalle del subgrafo Person (Names, Identifiers, Facts...).


Librería de persistencia de GedcomX en grafo

Se ha desarrollado una librería Java que utilizará Neo4j como acceso datos (BD embebida, funcionará en local).

La librería consta de 3 partes bien diferenciadas:
-Servicio
-Wrappers
-DAO

El DAO centraliza todos los métodos que actúan directamente contra la BD. Métodos de CRUD de nodos, relaciones e índices.

El servicio será el interfaz principal que el desarrollador de la aplicación utilizará. Consta de métodos de creación del grafo a partir del modelo de datos GedcomX, y métodos de búsqueda de nodos/relaciones. Los tipos de búsquedas que se podrán invocar serán 3:
-Búsquedas predeterminadas (queries cypher guardadas)
-Búsquedas sobre los atributos (utilizarán los índices de Neo4j)
-Búsquedas dinámicas (traversal de Neo4j)

Por último, los wrappers son objectos que nos ayudan a interactuar con los nodos del grafo. Tienen todos los métodos que podemos invocar sobre cada tipo de nodo: modificación de atributos, validación, resolución de relaciones con otros nodos, eliminación controlada de nodos y dependencias, etc. Los wrappers no mantienen el estado, y dependen de la API de Neo4j para todas las operaciones. Esto penaliza ligeramente el rendimiento, pero será inapreciable ya que suponemos que Neo4j utiliza algún tipo de cache. A cambio, facilita muchísimo la manipulación de los nodos, la seguridad y consistencia de los nodos. Los wrappers también facilitan la creación de nodos a partir de un objecto GedcomX y la creación posterior de objectos GedcomX a partir de los datos del grafo.

El modelo de datos utilizado es el gedcomx adaptado a grafos:
https://github.com/FamilySearch/gedcomx/blob/master/specifications/conceptual-model-specification.md
Modelo de nodos.
https://docs.google.com/file/d/0B6umBbeGBIAtb0xYM3FhNGw2QTQ/edit?usp=sharing

Se han utilizado las dependencias siguientes:
-Reflections: utilizada para cargar en runtime todos los tipos de wrappers implementados. Ésto nos permite añadir nuevos wrappers de una manera más simple.
-Guice: Un Spring lightweight . Inyección de dependencias e interceptores. Ayuda a controlar la instanciación e independencia de los diferentes módulos de la librería. Mejora el diseño.

sábado, 2 de febrero de 2013

Grafo del modelo

Primera versión del grafo de nuestro modelo. He intentado añadir el máximo de información posible, de manera que nos sirva a modo de especificación. Iré añadiendo cosas que falten y corrigiendo errores sobre este mismo grafo. Aunque sería muy interesante encontrar una buena herramienta para especificar el grafo de manera más formal (Gephi es muy inestable. Probaré Neoclipse).

Grafo (descargar para ver mejor)

Los nodos representan tipos de nodos (excepto el nodo "root", que es único). El título de los nodos, que actuaría a modo de "node_type" es opcional. Realmente, puedes inferir el tipo de nodo que es por sus relaciones adyacentes. No obstante, si nos facilitase la implementación y la navegación, podríamos añadir el "node_type" en todos los nodos.

Neo4j sólo permite primitivos y Strings como valor de las propiedades (http://docs.neo4j.org/chunked/milestone/graphdb-neo4j-properties.html), tendremos que apañarnos. En esta primera versión he intentado adaptar todos los tipos de datos de la especificación GedcomX a Neo4j. Los tipos que más problemas pueden darnos son las fechas y la longitud/latitud.

Las propiedades de los nodos obligatorias son las marcadas con "(1)". Las relaciones son direccionales y tienen marcada su frecuencia:

  • (*) 0 o más
  • (+) 1 o más
  • (1) 1 obligatoria
Lo que menos me convence del grafo diseñado es el nodo "CONCLUSION" y sus relaciones:
  • IS_PERSON
  • IS_RELATION
  • etc.
Puede acabar siendo difícil de mantener la integridad del grafo con esta técnica, probablemente sea mejor añadir las propiedades y relaciones del nodo "CONCLUSION" a cada uno de sus "subnodos".

El nodo apuntado por el nodo en rojo, puede ser substituido por una relación con propiedades, ya que la relación con "PERSON" es obligatoria.

He preparado un script Cypher de Neo4j muy pequeño y simple con unas instancias. Puede ser cargado en el servidor web de Neo4j:

// agent
create n = {id:"A1", phones:["23242452","53454353"]};
// agent->address
start n = node:node_auto_index(id="A1") create a={city:"Salt Lake City"}, n -[:HAS_ADDRESS]-> a;
// agent->name
start n = node:node_auto_index(id="A1") create a={value:"Family History Library"}, n -[:HAS_NAME]-> a;
// root to agent
start n = node(0), a = node:node_auto_index(id="A1") create n-[:HAS_AGENT]->a;

// source
create n = {id:"SOURCE1"}, c = {value:"citation"}, n-[:HAS_CITATION]->c;
// root to source
start n = node(0), a = node:node_auto_index(id="SOURCE1") create n-[:HAS_SOURCE]->a;

// person1
start root = node(0) create n ={id:"PERSON1"}, p , c, b= {type:"http://gedcomx.org/Birth"}, pl={original:"New York"}, n-[:IS_PERSON]->p-[:HAS_FACT]->b-[:PLACE]->pl, root-[:HAS_CONCLUSION]->c-[:IS_FACT]->b;
// person2
create n ={id:"PERSON2",gender:"http://gedcomx.org/Female"}, p , n-[:IS_PERSON]->p;
// root to conclusion
start n = node(0), p1 = node:node_auto_index(id="PERSON1"),  p2 = node:node_auto_index(id="PERSON2") create n-[:HAS_CONCLUSION]->p1, n-[:HAS_CONCLUSION]->p2;

// relationship
start c1 = node:node_auto_index(id="PERSON1"), c2 = node:node_auto_index(id="PERSON2") match p1<-[:IS_PERSON]-c1, p2<-[:IS_PERSON]-c2 create n = {id:"FAMILY1-PERSON1-PERSON2"}, r = {type:"http://gedcomx.org/Couple"}, n-[:IS_RELATIONSHIP]->r-[:PERSON1]->p1,r-[:PERSON2]->p2;
// root to conclusion
start n = node(0), a = node:node_auto_index(id="FAMILY1-PERSON1-PERSON2") create n-[:HAS_CONCLUSION]->a;



martes, 29 de enero de 2013

Introducción a Neo4j

Neo4j es un sistema de base de datos en grafo. Algunas de las ventajas que propone este paradigma son:

  • Escalabilidad
  • Alto rendimiento
  • Lenguaje de consultas "human friendly"

Los grafos se componen de nodos y relaciones. Ambos tienen propiedades. Las consultas sobre el grafo se basan en "traversals" que serían los caminos que unen los distintos nodos. Por último, para realizar búsquedas sobre nodos y relaciones, Neo4j utiliza índices sobre sus propiedades.

Cypher, el lenguaje formal utilizado para hacer las consultas, utiliza tanto los índices como los "traversals" para obtener datos.

Por ejemplo, obtenemos todas las películas rodadas el año 1999 mediante un acceso al índice de propiedades de películas, y luego mediante un "traversal" obtenermos las mascotas de los actores de dichas películas.

Cypher es un lenguaje bastante intuitivo y potente, y permite un grado de abstracción mayor que el SQL. De hecho, anunciar la consulta con lenguaje natural es una buena manera de empezar a realizar la query.

Mascotas de los actores que trabajaron en películas rodadas en 1999

La consulta final sería algo parecido a:


START movie=node:node_auto_index(year="1999") 
MATCH movie<-[:ACTS_IN]-actor-[:OWNS]->mascota 
RETURN mascota;


Uno de nuestras tareas será identificar qué elementos representamos como propiedades y qué elementos representamos como nodos. Por ejemplo: un nodo persona puede tener una propiedad "oficio" con valor "albañil", pero también podemos tener un nodo "albañil" y una relación -[:OFICIO]-> entre la persona y el nodo de "albañil". Ésto tendrá impacto en el rendimiento y en las consultas.

Neo4j está desarrollado en Java y se puede utilizado mediante su API y como componente externo, mediante una interfaz REST. Neo4j utiliza el sistema de ficheros para guardar todos su datos, que pueden ser fácilmente exportados e importados de una aplicación a otra.

Neo4j ha desarrollado un servidor que permite hacer operaciones básicas con los grafos, como exportar/importar, visualizar, manipular, ejecutar consultas en una consola, etc. Éste será el primer paso antes de implantarlo en un sistema propio.

Existe un proyecto de Spring que facilita la implementación de la capa de datos con Neo4j. Habrá que estudiarlo, no nos interesa comprometernos demasiado con un determinado framework. La solución debe ser reutilizable e independiente. Cuando lleguemos a la fase de definir el alcance de la implementación de nuestra librería gedcom-neo4j lo estudiaremos.

Enlaces útiles:
Neo4j
Documentación
Cheatsheet
Proyecto Spring
Blog
Videos




jueves, 24 de enero de 2013

Ficheros de ejemplo

Tenemos ficheros de ejemplo GEDCOM5.5 en el siguiente enlace:
http://www.geditcom.com/gedcom.html

Mediante la librería gedcom5-conversion, utilizando como el fichero de entrada "TGC551.ged" (descargado del anterior enlace), obtenemos el fichero GEDCOMX:
Fichero

Esto de momento nos sirve para familiarizarnos con la arquitectura GEDCOMX con un ejemplo bastante completo.

Falta comprobar cómo funcionan los links a las fuentes del fichero 5.5 y cómo se utilizarían en el fichero X.

sábado, 19 de enero de 2013

Primeros pasos con las librerías GEDCOM

Para empezar a utilizar las librerías Gedcom y GedcomX sólo tenemos que crear un proyecto Maven y configurar los siguientes repositorios:


<repositories>
<repository>
<id>gedcomx-release-repo</id>
<name>GEDCOM X Release Repository</name>
<url>https://repository-gedcom.forge.cloudbees.com/release/</url>
</repository>
<repository>
<id>gedcomx-snapshot-repo</id>
<name>GEDCOM X Snapshot Repository</name>
<url>https://repository-gedcom.forge.cloudbees.com/snapshot/</url>
</repository>
</repositories>

Y tenemos que añadir la dependendia:


<dependency>
<groupId>org.gedcomx</groupId>
<artifactId>gedcom5-conversion</artifactId>
<version>${gedcom5-conversion.version}</version>
</dependency>

Esta dependencia incluye todas las librerías que necesitamos. Las que utilizaremos directamente son:
  • gedcom-fileformat-java
  • Gedcom
  • gedcom5-conversion
Las primeras pruebas que he realizado incluyen los casos que detallo a continuación:

Lectura de fichero Gedcom5.5 (Gedcom)
El proyecto Gedcom y el proyecto Gedcom5-conversion incluyen varios ficheros de test .ged que he utilizado. Ademas, he encontrado ficheros de stress que nos ayudarán a comprobar todos los tags del estándar. El resultado de leer los ficheros es un modelo de datos que consiste en:
Personas
Familias
Fuentes
Repositorios

Escritura de fichero Gedcom5.5 (Gedcom)
Teniendo el fichero leído, comprobamos la escritura. He apreciado varios cambios de orden en los tags, pero ahora mismo no sé decir si eso provocaría inconsistencias.

Lectura/escritura de fichero GedcomX (gedcom-fileformat-java)
Este proceso sólo tiene una peculiaridad, que es el modelo conceptual. En GedcomX sólo existen:
Personas
Relaciones
Agentes
Fuentes
Todos estos tipos serían lo que llamamos "entidades Gedcom X". Además, tenemos los atributos, tanto globales como de cada entidad en particular (pares clave-valor). El proceso de lectura y escritura de fichero .gedx es bastante simple y no se aprecia ninguna inconsistencia en los datos de salida. El fichero .gedx se puede abrir como un fichero .jar. 
Será importante encontrar ficheros .gedx de stress. 

Paso de Gedcom5.5 a GedcomX (Gedcom y gedcom5-conversion)
Leemos el fichero Gedcom5.5 y lo mapeamos con el modelo de datos GedcomX. El resultado son las entidades GedcomX descritas anteriormente. 

Paso de GedcomX a Gedcom5.5
Este caso NO ESTÁ IMPLEMENTADO en el proyecto gedcom5-converson. Sólo existen mapeadores de modelo 5.5 a X y no a la inversa. Esto nos obliga a tomar una decisión:
  1. Fork del proyecto gedcom5-conversión. Ampliación de funcionalidad creando clases de mapping de entidades X a 5.5 realizando ingeniería inversa del código ya existente.
  2. El proyecto adopta el formato GedcomX como estándar de facto, PERMITIRÁ importar ficheros Gedcom5.5 como funcionalidad "legacy". NO permitirá exportar datos genealógicos en formato 5.5.
  3. Se utilizará el modelo de datos Gedcom que propone el parser Gedcom. NO se utilizará el modelo de datos GedcomX, ni el formato GedcomX de ficheros XML. Sólo se leerán y escribirán ficheros 5.5.