O YCSB é uma excelente ferramenta de benchmarking criada para ser facilmente ampliada por qualquer driver que ofereça suporte e implemente operações básicas como: inserção, leitura, atualização, exclusão e varredura. Os dados sintéticos simples introduzidos pelo YCSB se encaixam perfeitamente nesse paradigma.
Mas quando se trata de trabalhar com bancos de dados JSON, como o Couchbase e o MongoDB, o YCSB é útil porque as consultas se tornaram muito mais sofisticadas: consulta de matrizes e objetos aninhados, execução de junções e agregações.
A extensão YCSB-JSON, por um lado, deve ser capaz de utilizar todas as operações JSON possíveis suportadas por um banco de dados.
Por outro lado, a implementação dessa abordagem deve ser genérica o suficiente para ser facilmente estendida do YCSB e do MongoDB, Couchbase ou qualquer outro driver de banco de dados, independentemente do nível de consulta JSON que ele suporta.
A conexão YCSB-JSON foi projetada para emular melhor os cenários realistas do usuário final. Ela foi projetada para trabalhar com quaisquer dados JSON, sejam conjuntos de dados reais, pseudo-realistas ou totalmente sintéticos. E um dos requisitos para a ferramenta é que não haja nenhum valor codificado em predicados de consulta. Os usuários só podem controlar a cardinalidade dos dados durante o processo de geração do conjunto de dados.

Figura 1. Visão geral da implementação do YCSB-JSON
Modelo de dados
O modelo de dados que escolhemos para esse benchmark está bem descrito neste artigo: https://dzone.com/articles/ycsb-json-benchmarking-json-databases-by-extending
O conjunto de dados é gerado usando uma ferramenta fakeit e carregado em um banco de dados (Couchbase, MongoDB) por scripts externos. Enquanto o modelo é definido e os valores fixos são gerados aleatoriamente, esses dados são gerados aleatoriamente, mas não são sintéticos.
Gerenciamento de dados
Para cada operação na carga de trabalho, as consultas são fixas, mas os valores de limite para cada predicado parametrizado não são determinísticos. Portanto, foi escolhido o seguinte fluxo de gerenciamento de dados:
- Gerar documentos por fakeit.
- Carregue os dados gerados em um banco de dados por meio de qualquer script externo.
- Executar a fase de carregamento. Durante essa fase, o YCSB lerá um subconjunto aleatório dos documentos gerados e armazenará todos os seus valores em seu cache interno.
- Durante a fase de execução, o YCSB usará os valores de seu cache ao vincular e executar consultas no banco de dados.
Gerador de Predicados
O YCSB usa geradores ao operar com dados. O conector apresenta seu próprio gerador mapeado para um modelo de dados específico. O mapeamento e o modelo existem somente no espaço de nomes do gerador. A saída do gerador é um conjunto de predicados genéricos (pares campo-valor) para consultas específicas. Isso permite que os usuários modifiquem os modelos e ampliem a ferramenta com outras consultas sem modificar o restante do código principal.
Gerador de predicados: Gerador.java
Exemplo #1: Consulta de paginação
Uma das operações YCSB-JSON, a consulta de paginação, pode ser representada pela seguinte instrução:
SELECT * FROM WHERE address.zip = OFFSET LIMIT
O predicado da consulta é um campo dentro de um objeto. Ao usar o Couchbase N1QL, o campo pode ser acessado simplesmente como "address.zip". Mas outros bancos de dados podem não ser tão flexíveis, de modo que o gerador YCSB-JSON cria dois predicados: o predicado pai (endereço) e o predicado filho/aninhado (zip).
E o predicado filho tem um valor escolhido aleatoriamente na lista de valores de amostra para esse campo específico.
A função abaixo gera o Objeto SoeQueryPredicate
Onde nome é "endereço"
E predicado aninhado é outro objeto SoeQueryPredicate com o nome "zíper" e valor :

Exemplo #2 Consulta de relatório
Os predicados para consultas mais complexas são gerados da mesma forma. A única diferença é que, quando a consulta introduz vários predicados, a sequência de predicados (matriz de predicados) está sendo gerada em vez de um único predicado. Aqui está a consulta Relatório:
SELECT o2.month, c2.address.zip, SUM(o2.sale_price) FROM c2
INNER JOIN orders o2 ON KEYS c2.order_list
WHERE c2.address.zip = "value" AND o2.month = "value"
GROUP BY o2.month, c2.address.zip ORDER BY SUM(o2.sale_price)
A função abaixo gera a sequência de:
predicado "Month" (mês), predicado "address" (endereço) com predicado "zip" (CEP) aninhado, predicado "sale_price" (preço de venda) etc:

Outros geradores de consultas podem ser encontrados aqui:
https://github.com/couchbaselabs/YCSB/blob/soe/core/src/main/java/com/yahoo/ycsb/generator/soe/Generator.java
Novas operações
O código precisa ser atualizado com novas operações.
Assinaturas na classe DB:
https://github.com/couchbaselabs/YCSB/blob/soe/core/src/main/java/com/yahoo/ycsb/DB.java#L140:

Implementações no DBWrapper:
https://github.com/couchbaselabs/YCSB/blob/soe/core/src/main/java/com/yahoo/ycsb/DBWrapper.java#L346:

Ampliação do CoreWorkload com novas operações: SoeWorkload.java
Implementação de operações YCSB-JSON para Couchbase e MongoDB
A função de driver de banco de dados de uma operação YCSB-JSON recebe um parâmetro adicional que é um objeto gerador. Ele está sendo passado pela classe Workload e tem uma sequência de predicados específica pré-construída.
Como a estrutura e as sequências de predicados são bem definidas pelo gerador, um driver de BD pode acessar nomes e valores diretamente e construir a consulta usando sua linguagem de consulta nativa ou outros métodos de acesso. Abaixo estão exemplos de implementação de consultas de página e relatório.
Consulta de página, gerando instruções de consulta para o Couchbase:

para o MongoDB:

Consulta de relatório, Couchbase:

MongoDB:

Todas as implementações do Couchbase: Couchbase2Client.java
Todas as implementações do MongoDB: MongoDbClient.java
Referências
Parte 1 do artigo:
https://www.couchbase.com/blog/ycsb-json-benchmarking-json-databases-by-extending-ycsb/
Implementação do YCSB-JSON:
https://github.com/couchbaselabs/YCSB/tree/soe
FakeIt:
https://github.com/bentonam/fakeit
Próximas etapas
Implementar um gerador do tipo fakeit para simplificar a geração de dados e predicados de consulta.