BT

Fazendo Grafos divertidos novamente com Java

| por Otavio Santana Seguir 3 Seguidores em 14 ago 2018. Tempo estimado de leitura: 8 minutos |

A tecnologia NoSQL tem se popularizado nas mais diversas áreas e com diferentes usos, o que inclui casos de sucesso com bancos de grafos. Os bancos de dados de grafos possuem uma estrutura bastante diferente da base de dados relacional e o seu uso ficou bastante forte, sobretudo com sistema de recomendação. O objetivo deste artigo é cobrir o que essa tecnologia faz, a sua estrutura, vantagens além do seu uso com Java.

The Graph Structure

Os bancos de grafos se caracterizam sobretudo pela possibilidade de armazenar os relacionamentos de maneira bastante aprofundada, estes relacionamentos possuem direção e propriedades, muito comum em recomendação, afinal, o fato de alguém conhecer um artista famoso não é recíproco, ou seja, que essa artista também conheça essa pessoa. Basicamente, os elementos do grafos são:

  • Propriedade: Essa é a menor unidade da estrutura, ela é composta por uma tupla em que a chave é o nome da propriedade e o valor é a informação é semelhante ao Map.Entry de um java.util.Map.
  • Vertex: Ao tentar realizar uma comparação com o mundo relacional isso seria semelhante às tabelas que possuem uma quantidade ilimitada de propriedades. Vale salientar que a maioria dos bancos do tipo grafos não possuem uma estrutura definida, schemaless, ou seja, elas "nascem" em momento da execução (diferente de uma tecnologia de persistência relacional que tem schema, ou seja, a campo estará lá, porém, caso a informação não existe ela será definida como nula.
  • Edge: esse objeto representa o relacionamento entre os vértices que, assim como o Vertex, também possui um número indefinido de propriedades além da direção de uma relação. Ou seja, o relacionamento possui propriedades e sentido que faz com que o grafo tenha uma maior profundidade que os bancos relacionais. Salientando, o sentido do relacionamento no grafo é um conceito realmente importante, como já mencionado, uma pessoa pode conhecer um artista apesar dessa artista não o conhecê-lo.

Alguns bancos do tipo Grafo

Existem diversos bancos de grafos, sendo o mais famoso o Neo4J.

  • Neo4j
  • ArangoDB
  • Titan
  • OrientDB

O imenso número de APIs

Em conjunto com o grande número de banco de dados do tipo grafo, há um grande número de API. Geralmente, cada banco possui sua própria sintaxe para a comunicação. Essa abordagem traz diversos problemas, como por exemplo, um sistema grande ficará "refém" daquele provedor de banco de dados, uma vez que existe um alto custo na mudança, além do que, a curva de aprendizagem acaba sendo elevada.

TinkerPop

Com o objetivo do bloqueio entre banco de dados do tipo grafo, já explicado anteriormente, nasceu o Apache Tinkerpop que é uma solução open source provida pela Fundação Apache. Seu objetivo é trazer uma API padrão para os bancos de dados do tipo grafo, pense em JDBC para grafo, que inclui suporte tanto para operações como inserção, atualização e remoção, quanto para consulta com o Gremlin. No momento em que escrevo, o Apache Tinkerpop tem suporte a mais de 30 bancos de dados.

Grafos sobre a tecnologia relacional

Observe a figura abaixo; a pergunta mais simples seria "como representar uma cadeia alimentar numa estrutura alimentar?". Existe a possibilidade, porém, tal estrutura não será construída de maneira tão simples como se for representada com grafos, afinal, o sentido de quem é o predador e quem é a presa importa.

Pensando como grafos a consulta se torna bastante simples. No mundo relacional existe o SQL que é um padrão para consulta e alterações de dados do mundo relacional. No mundo dos Grafos existe algo parecido que é o Gremlin, no qual é possível realizar consultas e alterações nos elementos do Grafo (Vertex e Edge). Pensando no exemplo citado anteriormente, a cadeia alimentar, é possível percorrer as informações com o Gremin utilizando uma estrutura semelhante ao do while e o for.

g.V().repeat(out("eats")).times(3);//to go three times in the graph 
g.V().repeat(out("eats")) .until(has("name", "grass"));//to go as a "do while" structure

Simples, não? Mas e as minhas entidades?

O Apache TinkerPop possui suporte ao Java, porém, apenas como API de comunicação e a estrutura de grafos ele não é semelhante às entidades que encontramos no mundo corporativo, por exemplo, entidade Pessoa ou Livro no qual os desenvolvedores Java estão habituados a trabalhar.

Grafos e Eclipse JNoSQL

No mundo de grafos, o Eclipse JNoSQL tem uma integração com o Apache Tinkerpop como camada de mapeamento. Assim, comparando com o mundo relacional o Apache Tinkerpop seria como o JDBC e o Eclipse JNosQL como JPA. Os próximos passos serão para ilustrar essa integração entre as duas ferramentas.

Exemplo de Mapeamento

Um ponto a se destacar no mapeamento é sua grande semelhança com o JPA. O objetivo é bastante simples: utilizar a nomenclatura que o desenvolvedor Java já está acostumado a utilizar levando em consideração que a tecnologia utilizada é NoSQL. Por exemplo: como o conceito de entidade não é específico dos bancos de dados relacionais foi possível utilizá-los em problemas. Para o parser, transição entre o Vertex e uma instância, os getter e setter não são obrigatório e assim como o CDI é necessário que a entidade possua um construtor não privado sem argumentos.

@Entity 
public class Book { 
   @Id 
   private Long id; 
   @Column 
  private String name; 
} 
@Entity 
public class Person { 
   @Id 
   private Long id; 
   @Column 
   private String name; 
   @Column 
   private int age; 
   @Column 
   private String occupation; 
   @Column 
   private Double salary; 
}

Utilizando JNoSQL

O primeiro passo para a integração do Eclipse JNoSQL é tornar o Graph do TinkerPop visível para o CDI. Para fazer isso é necessário fazer com que exista um método que produza a interface Graph. Por exemplo, para utilizar o Neo4J embarcado como mostra o código abaixo:

@ApplicationScoped
public class GraphProducer {
    private Graph graph;
    @PostConstruct
    public void init() {
        String absolutePath = “any path”;
        this.graph = Neo4jGraph.open(absolutePath);
    }
    @Produces
    @ApplicationScoped
    public Graph getGraph() {
        return graph;
    }
}

Tão logo uma instância do Graph visível pelo CDI, o próximo passo é injetar um GraphTemplate. O GraphTemplate é semelhante ao padrão Template Method, porém focado em operações com Grafos e com ele é possível criar vértex, que serão as Entidades definidas, além das relações entre as entidades, que são os Edge, que serão representadas no Eclipse JNoSQL como EdgeEntity.

@Inject
private GraphTemplate graph;
//to CDI 2.0 with Java SE
GraphTemplate graph = container.select(GraphTemplate.class).get();

A partir desse GraphTemplate é possível inserir as entidades no banco de dados além de realizar as ligações das mesmas, e ela é responsável também por realizar as buscas com o wrapper do Gremlin que será explicado a seguir.

Person poliana = Person.builder().withName("Poliana").withAge(25).build();
Book shack = Book.builder().withAge(2007).withName("The Shack").build();
graphTemplate.insert(poliana);
graphTemplate.insert(shack);
//relationship
EdgeEntity reads = graphTemplate.edge(poliana, "reads", shack);
reads.add("where", "Brazil");

Realizando queries JNoSQL and TinkerPop

Para ilustrar a funcionalidade dos Grafos com o Tinkerpop, existirá o seguinte cenário:

Imagine uma campanha de marketing essa tal campanha tem o objetivo de atingir o seguinte público:

  • Um desenvolvedor
  • Salário maior e igual $3,000
  • Ter idade entre 20 e 25 anos
//In this scenario both SQL and Tinkerpop easy to do.
List developers = graph.getTraversalVertex() 
      .has("salary", gte(3_000D)) 
      .has("age", between(20, 25)) 
      .has("occupation", "developer") 
      .stream().collect(toList());

Nesse primeiro passo, é muito simples fazer tanto no Grafos quanto no mundo relacional, porém, haverá um segundo passo nesse exemplo que tornará a consulta mais difícil. Partindo do ponto que uma pessoa que não esteja nesse perfil possa conhecer uma pessoa que esteja e assim realizar a recomendação ou simplesmente que compre o produto, o próximo passo terá o objetivo de trazer as pessoas que o nosso alvo conhece.

List result = graph.getTraversalVertex()
.has("salary", gte(3_000D))
.has("age", between(20, 25))
.has("occupation", "developer")
.out("knows");

A campanha foi um sucesso! Porém, o dia dos namorados está chegando e com isso uma nova campanha de marketing. Para esse caso é necessário que, além do desenvolvedor, se traga o parceiro ou futuro parceiro. Nesse caso, o princípio é que o público-alvo seja conhecido por uma pessoa (ou seja, utilizaremos o in no parâmetro) e além disso esse conhecido sinta amor pelo desenvolvedor. Como foi visto, as relações possuem propriedades, assim, será necessário verificar a propriedade desse Edge, por isso o inE e em seguida verificar as suas propriedades como mostra o código abaixo.

List love = graph.getTraversalVertex()
.has("salary", gte(3_000D))
.has("age", between(20, 25))
.has("occupation", "Developer")
.inE("knows")
.has("feel", "love")
.bothV()
.stream()
.distinct()
.collect(toList());

Com isso foi apresentado um novo conceito de persistência com Grafos, além das suas possibilidades de uso como hierarquia, cadeia alimentar ou uma estrutura de uma empresa, ou relações muito mais densas que exijam que as relações tenham propriedades. Caso uma aplicação tenha um modelo complexo a ponto de requerer diversas relações N para N numa base relacional, talvez, seja um bom indício para olhar cuidadosamente para outro paradigma de persistência que o caso do banco de grafos, que assim como o relacional, trabalha num padrão de comunicação única com o Apache Tinkerpop.

Referências

Otavio é um engenheiro de software apaixonado, focado em Java. Sua principal experiência é em persistência poliglota e aplicações de alta performance em financas, social mídia e e-commerce. Otavio é um membro tanto de Expert Groups e Expert Leader em diversos JSRs no comitê executivo JCP. Ele trabalha em diversos projetos da Fundação Eclipse e Apache, como o Apache Tamaya, Eclipse JNoSQL, Eclipse MicroProfile, JakartaEE. Um Líder JUG e speaker global nas conferências JavaOne e Devoxx. Recebeu reconhecimentos por suas contribuições OSS, como o JCP Outstanding Award, membro do ano e JSR inovador, Duke's Choice Award e Java Champion Award.

Avalie esse artigo

Relevância
Estilo/Redação

Olá visitante

Você precisa cadastrar-se no InfoQ Brasil ou para enviar comentários. Há muitas vantagens em se cadastrar.

Obtenha o máximo da experiência do InfoQ Brasil.

Dê sua opinião

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

Receber mensagens dessa discussão
Comentários da comunidade

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

Receber mensagens dessa discussão

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

Receber mensagens dessa discussão

Dê sua opinião
BT