Um guia para o Neo4J com Java

Um guia para o Neo4J com Java

1. Introdução

Este artigo é sobreNeo4j - um dos bancos de dados de gráficos mais maduros e completos do mercado hoje. Os bancos de dados gráficos abordam a tarefa de modelagem de dados com a visão de que muitas coisas na vida se prestam a serem representadas como uma coleção denodes (V) e conexões entre eles chamadasedges (E).

2. Neo4j incorporado

A maneira mais fácil de começar comNeo4j é usar a versão incorporada na qualNeo4j é executado na mesma JVM que seu aplicativo.

Primeiro, precisamos adicionar uma dependência do Maven:


    org.neo4j
    neo4j
    3.4.6

Você pode verificarthis link para baixar a versão mais recente.

A seguir, vamos criar uma fábrica:

GraphDatabaseFactory graphDbFactory = new GraphDatabaseFactory();

Por fim, criamos um banco de dados incorporado:

GraphDatabaseService graphDb = graphDbFactory.newEmbeddedDatabase(
  new File("data/cars"));

Agora a ação real pode começar! Primeiro, precisamos criar alguns nós em nosso gráfico e, para isso, precisamos iniciar uma transação, poisNeo4j rejeitará qualquer operação destrutiva, a menos que uma transação tenha sido iniciada:

graphDb.beginTx();

Depois que uma transação estiver em andamento, podemos começar a adicionar nós:

Node car = graphDb.createNode(Label.label("Car"));
car.setProperty("make", "tesla");
car.setProperty("model", "model3");

Node owner = graphDb.createNode(Label.label("Person"));
owner.setProperty("firstName", "example");
owner.setProperty("lastName", "example");

Aqui, adicionamos um nóCar com as propriedadesmakeemodel, bem como um nóPerson com as propriedadesfirstNameelastName

Agora podemos adicionar um relacionamento:

owner.createRelationshipTo(car, RelationshipType.withName("owner"));

A instrução acima adicionou uma borda unindo os dois nós com um rótuloowner. Podemos verificar essa relação executando uma consulta escrita na poderosa linguagemNeo4j’sCypher:

Result result = graphDb.execute(
  "MATCH (c:Car) <-[owner]- (p:Person) " +
  "WHERE c.make = 'tesla'" +
  "RETURN p.firstName, p.lastName");

Aqui, pedimos para encontrar um proprietário de carro para qualquer carro cuja marca seja tesla e nos devolva seu nome e sobrenome. Sem surpresa, isso retorna:\{p.firstName=example, p.lastName=example}

3. Cypher Query Language

Neo4j fornece uma linguagem de consulta muito poderosa e intuitiva que oferece suporte a toda a gama de recursos que se espera de um banco de dados. Vamos examinar como podemos realizar esse padrão, criar, recuperar, atualizar e excluir tarefas.

3.1. Criar Nó

A palavra-chave Create pode ser usada para criar nós e relacionamentos.

CREATE (self:Company {name:"example"})
RETURN self

Aqui, criamos uma empresa com uma única propriedadename. Uma definição de nó é marcada entre parênteses e suas propriedades são colocadas entre chaves. Nesse caso,self é um alias para o nó eCompany é um rótulo de nó.

3.2. Criar Relacionamento

É possível criar um nó e um relacionamento com esse nó, tudo em uma única consulta:

Result result = graphDb.execute(
  "CREATE (example:Company {name:\"example\"}) " +
  "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" +
  "RETURN example, tesla");

Aqui, criamos os nósexample etesla e estabelecemos uma relação de propriedade entre eles. Criar relacionamentos com nós preexistentes também é possível.

3.3. Recuperar dados

A palavra-chaveMATCH é usada para encontrar dados em combinação comRETURN para controlar quais pontos de dados são retornados. A cláusulaWHERE pode ser utilizada para filtrar apenas os nós que possuem as propriedades que desejamos.

Vamos descobrir o nome da empresa proprietária do modelo teslaX:

Result result = graphDb.execute(
  "MATCH (company:Company)-[:owns]-> (car:Car)" +
  "WHERE car.make='tesla' and car.model='modelX'" +
  "RETURN company.name");

3.4. Atualizar nós

A palavra-chaveSET pode ser usada para atualizar as propriedades ou rótulos do nó. Vamos adicionar quilometragem ao nosso tesla:

Result result = graphDb.execute("MATCH (car:Car)" +
  "WHERE car.make='tesla'" +
  " SET car.milage=120" +
  " SET car :Car:Electro" +
  " SET car.model=NULL" +
  " RETURN car");

Aqui, adicionamos uma nova propriedade chamadamilage, modificamos os rótulos para seremCareElectroe, finalmente, excluímos a propriedademodel completamente.

3.5. Apagar nós

A palavra-chave DELETE pode ser usada para remoção permanente de nós ou relacionamentos do gráfico:

graphDb.execute("MATCH (company:Company)" +
  " WHERE company.name='example'" +
  " DELETE company");

Aqui, excluímos uma empresa chamada example.

3.6. Vinculação de parâmetro

Nos exemplos acima, temos valores de parâmetros embutidos em código, o que não é a melhor prática. Felizmente,Neo4j fornece um recurso para vincular variáveis ​​a uma consulta:

Map params = new HashMap<>();
params.put("name", "example");
params.put("make", "tesla");
params.put("model", "modelS");

Result result = graphDb.execute("CREATE (example:Company {name:$name}) " +
  "-[:owns]-> (tesla:Car {make: $make, model: $model})" +
  "RETURN example, tesla", params);

4. Driver Java

Até agora, vimos como interagir com uma instânciaNeo4j incorporada, no entanto, com toda a probabilidade de produção, gostaríamos de executar um servidor autônomo e conectar-se a ele por meio de um driver fornecido. Primeiro, precisamos adicionar outra dependência em nosso mavenpom.xml:


    org.neo4j.driver
    neo4j-java-driver
    1.6.2

Você pode seguirthis link para verificar a versão mais recente deste driver.

Agora podemos estabelecer uma conexão:

Driver driver = GraphDatabase.driver(
  "bolt://localhost:7687", AuthTokens.basic("neo4j", "12345"));

Em seguida, crie uma sessão:

Session session = driver.session();

Por fim, podemos executar algumas consultas:

session.run("CREATE (example:Company {name:\"example\"}) " +
  "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" +
  "RETURN example, tesla");

Assim que terminarmos todo o nosso trabalho, precisamos fechar a sessão e o driver:

session.close();
driver.close();

5. Driver JDBC

Também é possível interagir comNeo4j por meio de um driver JDBC. Ainda outra dependência para nossopom.xml:


    org.neo4j
    neo4j-jdbc-driver
    3.4.0

Você pode seguirthis link para baixar a versão mais recente deste driver.

A seguir, vamos estabelecer uma conexão JDBC:

Connection con = DriverManager.getConnection(
  "jdbc:neo4j:bolt://localhost/?user=neo4j,password=12345,scheme=basic");

Aquicon é uma conexão JDBC regular que pode ser usada para criar e executar instruções ou instruções preparadas:

try (Statement stmt = con.
  stmt.execute("CREATE (example:Company {name:\"example\"}) "
  + "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})"
  + "RETURN example, tesla")

    ResultSet rs = stmt.executeQuery(
      "MATCH (company:Company)-[:owns]-> (car:Car)" +
      "WHERE car.make='tesla' and car.model='modelX'" +
      "RETURN company.name");

    while (rs.next()) {
        rs.getString("company.name");
    }
}

6. Mapeamento de objeto-gráfico

Object-Graph-Mapping ou OGM é uma técnica que nos permite usar nossos POJOs de domínio como entidades no banco de dadosNeo4j. Vamos examinar como isso funciona. A primeira etapa, como de costume, adicionamos novas dependências ao nossopom.xml:


    org.neo4j
    neo4j-ogm-core
    3.1.2



    org.neo4j
    neo4j-ogm-embedded-driver
    3.1.2

Você pode verificarOGM Core LinkeOGM Embedded Driver Link para verificar as versões mais recentes dessas bibliotecas.

Em segundo lugar, anotamos nossos POJOs com anotações OGM:

@NodeEntity
public class Company {
    private Long id;

    private String name;

    @Relationship(type="owns")
    private Car car;
}

@NodeEntity
public class Car {
    private Long id;

    private String make;

    @Relationship(direction = "INCOMING")
    private Company company;
}

@NodeEntity informaNeo4j que este objeto precisará ser representado por um nó no gráfico resultante. @Relationship comunica a necessidade de criar um relacionamento com um nó que representa o tipo relacionado. Nesse caso, acompany possui acar.

Observe queNeo4j requer que cada entidade tenha uma chave primária, com um campo chamadoid sendo selecionado por padrão. Um campo com nome alternativo pode ser usado anotando-o com@Id @GeneratedValue.

Em seguida, precisamos criar uma configuração que será usada para inicializar o OGM deNeo4j. Para simplificar, vamos usar um banco de dados incorporado apenas na memória:

Configuration conf = new Configuration.Builder().build();

Depois disso, inicializamosSessionFactory com a configuração que criamos e um nome de pacote no qual residem nossos POJOs anotados:

SessionFactory factory = new SessionFactory(conf, "com.example.graph");

Finalmente, podemos criar umSession e começar a usá-lo:

Session session = factory.openSession();
Car tesla = new Car("tesla", "modelS");
Company example = new Company("example");

example.setCar(tesla);
session.save(example);

Aqui iniciamos uma sessão, criamos nossos POJOs e pedimos à sessão OGM para mantê-los. O tempo de execução OGM deNeo4j converteu objetos transparentemente em um conjunto de consultasCypher que criaram nós e bordas apropriados no banco de dados.

Se esse processo parece familiar, é porque é! É exatamente assim que o JPA funciona, a única diferença é se o objeto é convertido em linhas que são mantidas em um RDBMS ou se uma série de nós e arestas persiste em um banco de dados gráfico.

7. Conclusão

Este artigo analisou alguns conceitos básicos de um banco de dados orientado a gráficos Neo4j.

Como sempre, o código neste artigo está disponívelover on Github.