Uso práctico de Java y Neo4j: Sistema de recomendación

1
6346

En este tutorial veremos cómo conectarnos y consumir información de la base de datos de grafos Neo4j, para ello realizaremos una sencilla aplicación de recomendación.

Índice de contenidos

1. Introducción

Como ya vimos en el tutorial Primeros pasos con Neo4j, de Juan Alonso Ramos, Neo4j es una base de datos orientada a grafos implementada en java.

El uso de Neo4j esta recomendado para:

  • Búsquedas en base a grafos
  • Sistemas de recomendación
  • Redes sociales
  • Gestión de identidades y accesos
  • Detección de fraude
  • Gestión de datos maestros

Tal y como describen en su propia web, Casos de uso de Neo4j, junto con una serie de white papers con más información sobre cada uno de los casos recomendados.

En este tutorial realizaremos un ejemplo básico, través de una aplicación Java, de sistema de recomendación en el que para un conjunto personas que se conocen entre ellas, se recomendará a una persona concreta otro conjunto de personas a conocer.

¡Manos a la obra!

2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro Retina 15′ (2.5 Ghz Intel Core I7, 16GB DDR3).
  • Sistema Operativo: Mac OS El Capitan 10.11.5.
  • Entorno de desarrollo: IntelliJ IDEA ULTIMATE 2016.1.2
  • Apache Maven 3.3.0.
  • JDK 1.8.0_71
  • Spring Boot
  • Neo4j 3.0.2

3. Preparar el contexto

3.1. Neo4j

Lo primero que necesitamos es mantener una instancia de Neo4j instalada en nuestro sistema. Para ello aconsejamos seguir el tutorial mencionado con anterioridad Primeros pasos con Neo4j.

3.2. Proyecto IntelliJ

En segundo lugar vamos a crear un esqueleto para nuestro proyecto. Dado que no es el objetivo de este tutorial, no hace falta preocuparse por cómo crearlo, disponéis de todo el código subido en github: SocialRecommendation.

Este repositorio de git mantiene tanto la estructura del proyecto listo para utilizarse, como una copia de la instancia de Neo4j con la información necesaria. No obstante facilitaremos los pasos necesarios para crear una nueva instancia de Neo4j y cómo alimentarla.

3.3. Creación de un nuevo grafo

Con Neo4j se pueden crear grafos atendiendo al momento de la creación y a la necesidad de que la información persista, por ello podemos elegir entre:

  • Por un lado, crear la base de datos de manera estática o de manera dinámica (en tiempo de ejecución),
  • por otro lado, crear la base de datos persistente o temporal (en memoria).

Para este tutorial, hemos creído conveniente crearla de manera estática y persistente. A continuación se muestran los pasos a seguir para proceder con la creación de la instancia.

Primero abriremos el gestor gráfico de neo4j, nos mostrará una ventana como la siguiente:

Configurar_grafo_01

Continuamos pulsando sobre «Choose«, lo que nos ofrecerá un diálogo en el que podremos seleccionar la nueva ubicación de nuestra base de datos Neo4j.

Después nos aseguramos de que la configuración se encuentra correctamente establecida pulsando sobre el botón «Options…«, lo que nos mostrará una ventana como la que se ve a continuación:

Configurar_grafo_02

Una vez comprobada la correcta configuración cerramos la ventana de configuración y procedemos con la creación de la base de datos pulsando sobre el botón «Start«, lo que iniciará el proceso de creación de los ficheros necesarios para dar soporte a la base de datos. No se trata de un proceso inmediato, así que puede que tarde un momento.

Configurar_grafo_03

Cuando el proceso de creación de la nueva base de datos haya finalizado, el cuadro «Status» cambiará a color verde, informandonos del fin de la tarea.

Configurar_grafo_04

Con esto pondremos fin al proceso de creación de nuestra base de datos Neo4j.

Podremos comprobar que todo ha funcionado correctamente accediendo al interfaz web de administración de neo4j en el enlace que se muestra en el cuadro «Status«, en nuestro caso «http://localhost:7474/«.

3.4. Alimentando el grafo

El proceso de alimentación del grafo es muy sencillo.

En este caso vamos a proceder con la carga de información desde ficheros csv donde mantendremos información referente a personas y a las amistades que entre ellos han surgido.

Para ello, debemos colocar los ficheros con dicha información en la carpeta «./neo4j.databas/import/» de la dirección donde hayamos creado nuestra nueva instancia de Neo4j.

A continuación nos dirigimos al gestor web de Neo4j, en nuestro caso «http://localhost:7474/«, y procedemos con los siguientes pasos:

Alimentando_grafo_01

Continuando, en el cuadro de inserción de consultas de Neo4j creamos la clave primaria para nuestra tabla «Person«:

CREATE CONSTRAINT ON (p:Person) ASSERT p.userId IS UNIQUE;

Lo que nos debería arrojar un resultado como el siguiente:

Alimentando_grafo_02

Después realizaremos la carga de las personas mediante:

LOAD CSV FROM "file:///personas.csv" AS row CREATE (:Person {id: toInt(row[0]), name:row[1]});

Lo que nos devolverá un mensaje como el siguiente:

Alimentando_grafo_03

Para finalizar cargamos las relaciones entre las personas con:

USING PERIODIC COMMIT;
LOAD CSV FROM "file:///amistades.csv" AS row
MATCH (p1:Person {id: toInt(row[0])}), (p2:Person {id: toInt(row[1])})
CREATE (p1)-[:KNOWS]->(p2);

Lo que nos dará un resultado como:

Alimentando_grafo04

Finalmente, si realizamos una consulta simple, podremos visualizar el grafo que hemos generado:

MATCH (n:Person) RETURN n LIMIT 25;

El resultado:

Alimentando_grafo_05

Con esto habremos puesto fin al proceso de carga de la información para nuestra aplicación.

4. El código

Ahora procederemos a repasar las principales partes del código fuente de la aplicación.

4.1. La conexión a Neo4j

Establecemos la conexión a la base de datos a través de la siguiente clase de configuración:

SocialRecommendationNeo4jConfiguration.java
@EnableTransactionManagement
@Configuration
@EnableNeo4jRepositories(basePackages = "com.adictosaltrabajo.neo4j.core.repository")
public class SocialRecommendationNeo4jConfiguration extends Neo4jConfiguration {

    @Autowired
    private Environment env;
    private org.neo4j.ogm.config.Configuration config;
    private SessionFactory sessionFactory;

    @Bean
    public org.neo4j.ogm.config.Configuration getConfiguration() {
        config = new org.neo4j.ogm.config.Configuration();
        config.driverConfiguration()
                .setDriverClassName(env.getProperty("neo4j.driverClassName"))
                .setURI(env.getProperty("neo4j.uri"));
        return config;
    }

    @Override
    public SessionFactory getSessionFactory() {
        sessionFactory = new SessionFactory(getConfiguration(), "com.adictosaltrabajo.neo4j.core.model");
        return sessionFactory;
    }

    @Override
    @Bean
    @Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
    public Session getSession() throws Exception {
        return sessionFactory.openSession();
    }

}

El método getConfiguration establecerá los parámetros de configuración de la conexión a nuestra base de datos Neo4j. Estos parámetros se establecen mediante el fichero de configuración de la aplicación application.properties:

neo4j.driverClassName=org.neo4j.ogm.drivers.http.driver.HttpDriver
neo4j.uri=http://neo4j:adictos@localhost:7474

El método getSessionFactory nos proporciona una factoría de sesiones de la que se hará uso de manera interna cada vez que se quiera consultar a la base de datos. En ella se establece el path hasta los modelos que representarán en Java los elementos de la base de datos.

Por último, getSession nos provee de una sesión a través del sessionFactory.

4.2. El sistema de recomendación

Gracias al lenguaje Cypher, que nos permite realizar consultas de manera expresiva y eficiente sobre Neo4j, nuestro sistema de recomendación va a consistir en una simple y llana consulta friendsOfMyFriends.

PersonRepository.java
@Repository
public interface PersonRepository extends GraphRepository {

    @Query("MATCH (b:Person)-[:KNOWS]->(a:Person) " +
            "WHERE b.name = {name} " +
            "RETURN collect(a) " +
            "LIMIT {limit}")
    List friends(@Param("name") String name, @Param("limit") int limit);

    @Query("MATCH (person:Person)-[:KNOWS]->(friend:Person)-[:KNOWS]->(foaf:Person) " +
            "WHERE person.name = {name} " +
                "AND person <> foaf " +
                "AND NOT (person) -[:KNOWS]-> (foaf) " +
            "RETURN collect(distinct(foaf)) " +
            "LIMIT {limit}")
    List friendsOfMyFriends(@Param("name") String name, @Param("limit") int limit);

}

El método friends nos devolverá los amigos directos de una persona filtrando por su nombre.

Tal y como comentábamos con anterioridad, el método friendsOfMyFriends es el encargado de realizar la recomendación de personas. Nos devuelve todas las personas que son conocidas por los amigos de una persona estableciendo varios filtros:

    • El nombre de la persona a la que se va a recomendar otras personas
person.name = {name}
    • Esas personas no pueden ser la propia persona.
AND person <> foaf
    • Por último deben ser personas desconocidas.
AND NOT (person) -[:KNOWS]-> (foaf)

5. La aplicación

Para visualizar este sistema de recomendaciones hemos creado una aplicación web muy sencilla, en la que lo único que hacemos es mostrar información.

Inicialmente cuando entramos en la aplicación mostraremos la tabla de personas existentes en el sistema

Neo4j_aplicacion_1
Cada nombre es un enlace a dos conjuntos de información de la persona: Sus amigos y las recomendaciones:

Neo4j_aplicacion_2

6. Conclusiones

Este tutorial es una aproximación muy básica sobre Neo4j, cómo conectarnos y cómo consumir datos desde sus grafos a través de CQL (Cypher Query Language).

Ya sean grafos no dirigidos, dirigidos, con peso… gracias, tanto a la estructura de datos que mantiene Neo4j consumir información de grafos se hace realmente sencillo.

En posteriores tutoriales sería interesante explorar un poco más en profundidad algunos aspectos de Neo4j más avanzados o con mayor complejidad.

Esperamos que este tutorial, aunque sumamente sencillo, os haya servido para perderle el miedo a esta herramienta y os animéis a hacer uso de ella.

1 COMENTARIO

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad