A NoSQL Battle — pt. 2

Continuando com a prova de conceito

Benchmark for NoSQL decision — Now itś time for ArangoDB

No último post, eu contei um pouco do problema que tínhamos e que iniciou o estudo e também falei do Mongo. Nesse post eu vou falar do Arango.

É de comer?

O ArangoDB (de acordo com a empresa, Arango é um tipo de abacate do México/Guatemala) é um banco de dados NoSQL multi modelo, servindo tanto para armazenar documentos, grafos ou “chave-valor”.

Por quê chamou a atenção?

Além de ser multi modelo, outras features me pareceram ser bem interessantes:

  • No modelo de documentos, é possível fazer uma query com JOIN
  • Existe o conceito de “transactions”, o que facilita um possível rollback em caso de alguma falha
  • Armazenamento compacto (pelo menos é o que eles afirmam)
  • O cluster master-master (ou “multi-master”)
  • Interface visual para navegação e query nativa
  • Arango Query Language (AQL): lembra a forma de escrever SQL e funciona com todos os modelos. Ou seja, é uma linguagem declarativa que pode facilitar a escrita e o entendimento de uma query grande.
  • API Rest nativa para executar queries

Sei que para várias pessoas o framework Foxx (um framework Javascript embutido no Arango que facilita criação de backends) também seria um diferencial mas, para o benchmark, não seria uma comparação adequada. E também não ia ter tempo para ver como integrar isso com o modelo Aclow de desenvolvimento.

E o código?

Obviamente, segui aqui as mesmas regras da batalha descrita no post anterior.

O ArangoDB pode salvar os documentos de 2 formas: como um BaseDocument ou como um VPack. O VPack funciona como um compressor de dados. Porém, por falta de tempo, eu resolvi usar o BaseDocument mesmo e acho que isso impactou pouco o resultado do benchmark (onde o tamanho do storage final não foi levado em consideração).

Uma das diferenças entre o Arango e o Mongo é que o Vertx já possui uma biblioteca nativa assíncrona para o Mongo, mas não para o Arango. Mas o Arango oferece as 2 opções de biblioteca para Java, então eu achei que seria interessante fazer ambas as possibilidades sempre que possível/viável.

Como temos um novo tipo de dados, o DataHelper teve que ser ligeiramente alterado:

Insert

Depois de preparar os dados, precisamos inserí-los um a um no banco.

Igual ao Mongo, essas funções recebem aquele JsonArray e, de forma recursiva, faz a inserção deles no Arango. Na função síncrona, eu precisei informar para o vertx que o código era bloqueante.

Step 1 — Full Scan

Como eu comentei antes, o AQL lembra o SQL. Então, para fazer um `Select * FROM table` você usa o `FOR var_name IN collection_name RETURN var_name`. Ou seja, você está mapeando o retorno da query em um objeto “var_name”, que poderá ser usado em outros pontos da query, como se fosse um “for each / for in”.

Step 2

Na primeira função (fullscan) eu fiz um interpolação de strings do próprio Kotlin. Porém o ArangoDB oferece um forma mais segura de fazer isso, com os “bindVars”. De acordo com a documentação, eles tratam problemas tipo “sql injection”, então é uma boa prática. Na query, basta colocar as variáveis com um “@” e dois “@@” exclusivamente para as collections.
Para filtrar os dados baseado em um campo, o AQL oferece a sintaxe “FILTER” (linha 8). Veja que estou filtrando uma propriedade do objeto “o” declarado no “FOR” (linha 7)

Step 3

Leitura com apresentação das colunas A, B e E para um campo com vários valores (IN)

Diferentemente do Step 2, o comando de FILTER não é de equalidade e sim de “contains” (IN). E veja como é fácil escrever essa query.
Para retornar só determinadas propriedades/colunas de cada objeto da lista de resultados, basta fazer uma “projection”, que consiste de um objeto JSON especificando quais propriedades devem aparecer. Esse objeto é “aplicado” no comando RETURN. Fácil, não?

Step 4

Para o Step 4, a query deve filtrar dados baseados em um boundaries de valores, ou seja, limite inferior e limite superior para um campo. Veja o comando FILTER na linha 9. Parece Javascript, não? Fácil de ler e entender.

Step 5

Uma variação do step anterior, no Step 5 a query deve filtrar os dados baseados em boudaries de um campo e depois somar os valores baseado em outro campo. Olha que legal: o ArangoDB entende que o resultado de uma query é um array de objetos que atendem as premissas dos filtros. Portanto, é possível aplicar funções de agregação nesse array, como um SUM de um campo específico do array.

Step6

Explicando: imagine que você quer fazer uma query que some os valores da propriedade A e da propriedade B, agrupados por ano.

Para essa query, utilizei 2 novos comandos: COLLECT e [*]

O keyword COLLECT pode ser usado para agrupar um array de dados por um ou mais critérios de agrupamento. O comando COLLECT vai eliminar todas as variáveis no escopo atual e depois dele ser executado, somente as variáveis introduzidas por ele é que estarão disponíveis.
Na linha 9 eu faço o uso do COLLECT agrupando os dados pela propriedade passada e atribuo esses valores em uma variável nomeada “groups” (é, tava sem criatividade quando nomeei essa variável :| ). O motivo de eu querer guardar esses valores foi para poder retornar esses nomes em cada objeto do array a ser retornado. Ou seja, eu posso colocar o ANO do agrupamento em cada objeto retornado.
Para fazer a somatória, novamente eu uso o conceito de array de retorno. Mas, como preciso fazer a somatória dos valores da propriedade específica para todos os objetos do array, o Arango oferece uma forma de fazer uma operação que traversa um array: [*]. 
E, para terminar, eu especifiquei um JSON de projection que monta os objetos de retorno da minha query.

Step 7

Ufa, ta quase no final.

Bom, aqui não temos nenhuma novidade quanto à query (do que já vimos antes).

Executando

Igualzinho ao post anterior.

Conclusão

Exciting! O ArangoDB ainda não ganhou a tração que merce e por isso não tem uma comunidade grande, mas eu achei que é um BD completo. É multi-modelo, tem uma interface gráfica agradável e o AQL é fácil de aprender, usar e dar manutenção.

Quanto à ambiente de produção, eles sugerem usar o DC/OS com o Meses para criar um cluster escalável. Pelo o que eu vi, o DC/OS tem um pacote pronto para o ArangoDB, o que pode parecer que economiza tempo, mas você precisa saber configurar o DC/OS, que me parece ser mais complicado que o RancherOS, mas eu não sou especialista em nenhum dos 2. Algum DevOps quer opinar sobre o assunto?

Voltando ao benchmark em questão, vou deixar as comparações e o resultado da escolha para depois da explicação sobre o Aerospike.

Code away: into infinity and beyond!