Neo4J: trabajando con grafos

En los últimos años, todos estamos escuchando el auge de las bases de datos no relacionales. Bases de datos que ya no dependen de tablas, columnas, filas o esquemas para almacenar y trabajar con la información, sino que nos permiten almacenar estructuras dinámicas de datos, gráficos, pares de clave valor, etc.

Las bases de datos NoSQL nos aportan una buena escalabilidad, alta disponibilidad y resiliencia, además de facilitarnos el desarrollo.

Uno de los tipos de bases de datos NoSQL menos empleados en el desarrollo de proyectos hoy en día, pero no por ello menos importante, son las bases de datos de grafo.

¿NoSQL? ¿Grafos?

Un grafo se compone de dos elementos: un nodo y una relación. Un nodo representa una entidad (una persona, cosa, categoría o similar) y cada relación representa cómo están asociados dos nodos.

Por ejemplo, el nodo “Persona 1” tiene una relación con el nodo “Persona 2” de tipo amistad. Además, a  “Persona 1” le gustan las películas y a “Persona 2” los libros.

Esta estructura nos permite modelar todo tipo de escenarios definidos por entidades y relaciones entre sí: una red social, motores de recomendaciones en tiempo real, etc.

Los beneficios de utilizar una base de datos de estas características son:

  • Flexibilidad: los datos no tienen que mantener una estructura rígida, los nodos pueden ser cada uno de un tipo diferente, se pueden añadir con facilidad atributos adicionales.
  • Búsqueda: podemos hacer búsquedas muy rápidas basadas en las relaciones establecidas entre los nodos, por ejemplo: “¿cuándo se han hecho amigas dos personas?”.
  • Indexación: las bases de datos de grafo se indexan de forma natural por sus relaciones, proporcionando un acceso más rápido en comparación a cómo resuelve una base de datos relacional las foreign keys entre diferentes tablas.

Utilizando una base de datos de grafo: Neo4j

Una de estas bases de datos de grafo es Neo4j, desarrollada por la empresa sueca Neo Technology, que liberó su primera versión en febrero de 2010. Implementada en Java, funciona con una sola escritura maestra y varias réplicas de lectura.

Sus principales características son:

  • Soporta transacciones ACID:
  • No hay esquema.
  • Alta disponibilidad, balanceo de carga de lectura.
  • Independientemente del tamaño de la red, la velocidad de las operaciones es constante.

Podemos acceder a consultar los datos mediante su propio lenguaje de consulta Cypher, así como mediante Gremlin. También expone un API Rest por el que podemos recuperar la información.

Nuestra primera prueba con Neo4j

Vamos a instalarla utilizando Homebrew. También puede descargarse en la web oficial. Necesitamos tener al menos instalado java 1.7.

Arrancamos Neo4j con el comando neo4j start, que nos levantará un cliente web en http://localhost:7474.

Vamos a crear “Juego de Tronos” y a añadir varios personajes. Para ello, utilizaremos Cypher, el lenguaje propio de Neo4j, que como veremos es muy intuitivo.

Primero, crearemos en la consola superior nuestro primer nodo, el libro:

CREATE (GOT:Book {title:'Game of Thrones', published: 1996})

La estructura de la sentencia como podemos ver es muy sencilla: CREATE + “etiqueta del nodo (GOT) + Tipo de Nodo (Book) + información del nodo en formato JSON (title, published)

Esto nos dará como resultado nuestro primer nodo, “GOT”, de tipo Book, que tiene como atributos el título y la fecha de publicación. Ahora ya podemos ver más información en nuestro cliente de la base de datos que estamos creando:

Ahora crearemos unos cuantos personajes (en este caso, el tipo de nodo es “Person”):

CREATE (ES:Person {name:'Eddard Stark', titles: 'Lord of Winterfell, Warden of the North, Hang of the King, Protector of the Realm, Lord Regent', born: '263 AC'})
CREATE (TL:Person {name:'Tywin Lannister’', titles: 'Lord of Casterly Rock, Shield of Lannisport and Warden of the West’', born: '242 AC'})
CREATE (DT:Person {name:'Daenerys Targaryen’', titles: 'Daenerys Stormborn of the House Targaryen, First of Her Name, the Unburnt, Queen of the Andals and the First Men, Khaleesi of the Great Grass Sea, Breaker of Chain, and Mother of Dragons', born: '172 AC'})

Sus relaciones con el libro:

MATCH (ES:Person), (GOT: Book) CREATE (ES)-[:APPEARS_IN]->(GOT)

Con esta instrucción le decimos que localice un nodo de tipo Person etiquetado como “ES, y otro de tipo Book etiquetado como “GOT”, y que cree una relación llamada “APPEARS_IN” entre ellos, de una sola dirección (el personaje aparece en el libro, y no al revés).

Ya podemos consultar el pequeño grafo que hemos creado con el comando MATCH(n) RETURN n:

Incluyendo Neo4j en nuestros proyectos con Spring

Neo4j cuenta con una implementación de Spring Data que nos facilita enormemente la integración con esta base de datos no relacional, podemos consultar el API aquí.

Para utilizarlo, tan solo necesitaremos añadir a nuestro proyecto de Spring la dependencia:

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-neo4j</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>

Y crear nuestros nodos con las anotaciones apropiadas (@NodeEntity para indicar que es un nodo, @Relationship para mapear la relación):

@NodeEntity
public class Book {

	@Id
	@GeneratedValue
	private Long id;

	private String published;

	private String title;

	@Relationship(type="APPEARS_IN", direction = Relationship.INCOMING )
	private Set<Character> characters;

	
	public Long getId() {
		return id;
	}

	public String getPublished() {
		return published;
	}

	public String getTitle() {
		return title;
	}

	public Set<Character> getCharacters() {
		return characters;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public void setPublished(String published) {
		this.published = published;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public void setCharacters(Set<Character> characters) {
		this.characters = characters;
	}
}

También podremos crear un Repository de Spring Data, que nos proporcionará los métodos de acceso básicos y que podremos ampliar con nuestras propias operaciones personalizadas:

public interface BookRepository extends Neo4jRepository <Book, Long> {
}

Como vemos, es muy fácil utilizar este tipo de bases de datos y podemos modelar casi cualquier escenario que se nos ocurra. Al igual que con cualquier tecnología, siempre es recomendable utilizarla en el caso concreto en el que aplique (jamás se nos ocurriría utilizarla para almacenar documentos).

Además, haciendo uso de las facilidades que nos da Spring y la consola que nos proporciona Neo4j podremos visualizar los grafos y hacer nuestras consultas a la base de datos con gran facilidad. Como dicen los evangelistas de las bases de datos de grafo… “If you can whiteboard it, you can graph it!”.

Desarrolla su día a día como Arquitecto Java en Paradigma, le gusta programar, investigar nuevas tecnologías y frameworks, el código bien hecho y el trabajo en equipo. Cree en la artesanía del software, el pragmatismo y el código limpio.

Ver toda la actividad de Eva Lozano

Escribe un comentario