Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Paginação em buckets

Boa tarde, Tenho um cenário onde tenho que atravês de meses cheios, identificar produtos que foram comprados e pegar para cada produto a ultima venda. Hoje minha estrutura conta com 3 aggregation encadeada, onde uma faço a quebra de meses usando histogram seguido de uma aggregação pelo field nome do produto e depois um top_hits.

O que tenho de problema é que para usar a paginação nas aggregações tenho uma visualização erronia dos dados, e ao mesmo tempo não consigo fazer o from / size no hits (externo aos buckets de aggregations) pois lá os dados ainda não passaram por toda a order de agrupamento..

Existe algo que possa resolver esse tipo de problema ?

2 respostas

Fala ai Ricardo, de boa?

Cara vi que sua dúvida estava aberta aqui fazem 2 semanas, você já conseguiu resolver ?

Achei bem interessante, se conseguiu compartilha ai para gente dar uma olhadinha ?

solução!

Resolvi parcialmente com um workaround, basicamente a paginação não existe para as agregações (https://github.com/elastic/elasticsearch/issues/4915) porém resolvi com uma ideia baseada na ideia de dividir para conquistar: - A consulta que tinha 3 agregações foi fragmentada em 2 consultas até o ES. - A primeira fazia o filtro dos produtos no mês em questão, a jogada aqui foi colocar o size para delimitar o retorno em apenas X itens. - Uma vez retornado os itens, a agregação do top_hits é 1 para 1, então o size feito na primeira consulta já serviria de delimitador.

O problema que não foi solucionado é que para paginação, no cenário onde o usuário quer a partir do 20° item, os próximos 10, tenho que fazer um size de 30 e então 'picotar' do 20 até 30 e assim por diante, ou seja, tenho um processamento perdido..

public assinaturaQualquer (Parametros necessários) {

    List<Produts> resultList = new ArrayList<>();

    JsonNode distinctProdutsInPeriod;

    SearchRequestBuilder searchRequestBuilderGenerics = /*Método que monta query com o periodo de data e demais filters necessários*/;
    searchRequestBuilderGenerics.addAggregation(AggregationBuilders.terms(CALLS).field(fieldToAggregate).size(pageSize)); /* <- Pulo do gato */

    searchRequestBuilderGenerics.execute().get();

    distinctProdutsInPeriod = mapper.readTree(resultQuery.toString()).get(ES_AGGREGATIONS).get(CALLS).get(ES_BUCKETS);

    List<String> productsListFilter = new ArrayList<>();
    distinctProdutsInPeriod.forEach(each -> {
        productsListFilter.add(each.get(ES_KEY).asText());
    });

    if (productsListFilter.isEmpty()) {
        return resultList;
    }

    SearchResponse resultQuery = /*Método que monta query com o periodo de data e demais filters necessários E FAZ O 'IN' DA LISTA DE productsListFilter USANDO constantScoreQuery*/;
    resultQuery.addAggregation(AggregationBuilders.terms(CALLS).field(fieldToAggregate)
                .subAggregation(AggregationBuilders.topHits(LATEST_CALL).addSort(RECEIVED_ON, SortOrder.DESC).setSize(1)
                .setFetchSource(new String[] { /*Fields to return*/ }, null)));

    resultQuery.execute().get();

    JsonNode jsonNode = mapper.readTree(resultQuery.toString()).get(ES_AGGREGATIONS).get(CALLS).get(ES_BUCKETS);

    jsonNode.forEach(lastCall -> {
        /* Aqui só alegria */
        resultList.add(lastCall);
    });

    /* No caso meu front ficou responsável por picar a informação de acordo com que for usar. */
    return resultList;    
}