Как получить значение из сегментов агрегации в Java для результата запроса агрегации elasticsearch

Итак, я смог реплицировать запрос elasticsearch по своему желанию на Java с помощью restclient высокого уровня elasticsearch. Проблема в том, что я не могу получить нужные значения. Прежде чем я дам код, я хочу обратиться к общей цели на случай, если есть гораздо более простое решение (похоже, это не должно быть так сложно).

Общая цель: получить количество документов, в которых «посещено» == истина для каждого уникального значения в поле «рекомендатель».

Мой текущий статус: мне удалось написать запрос с желаемым выводом в kibana / elasticsearch, но когда я реплицирую этот запрос на Java, я не могу получить доступ к нужным мне данным. (Проверено с помощью searchRequest.source (). ToString ()).

Вот запрос:

{
  "aggs":{
    "recommenderIDs": {
      "terms": {
        "field": "recommender"
      },
      "aggs": {
        "visit_stats": {
          "filters": {
            "filters": {
              "visited": {
                "match":{
                  "visited": true
                }
              }
            }
          }
        }
      }
    }
  }
}

И это то, что у меня есть в моем java-коде:

// ...
        SearchRequest searchRequest = new SearchRequest(INDEX_REC_RECOMMENDATIONS);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        String aggregationName = "recommenderId";
        String filterName = "wasVisited";
        TermsAggregationBuilder aggQuery = AggregationBuilders
                .terms(aggregationName)
                .field(RecommendationRepoFieldNames.RECOMMENDER);
        AggregationBuilder aggFilters = AggregationBuilders.filters(
                filterName,
                new FiltersAggregator.KeyedFilter(
                        RecommendationRepoFieldNames.RECOMMENDER,
                        QueryBuilders.termQuery(RecommendationRepoFieldNames.VISITED, true))
        );
        aggQuery.subAggregation(aggFilters);
        searchSourceBuilder.aggregation(aggQuery);
        searchRequest.source(searchSourceBuilder);
//        System.out.println(searchRequest.source().toString());
        try {
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            Aggregations aggregations = searchResponse.getAggregations();
            Terms byRecommenderId = aggregations.get(aggregationName);
            Filters filterResponses = searchResponse.getAggregations().get(aggregationName);
//            for (Filters.Bucket entry : filterResponses.getBuckets()) {
//                String key = entry.getKeyAsString();
//            }
            for (Terms.Bucket bucket : byRecommenderId.getBuckets()) {
                String bucketKey = bucket.getKeyAsString();
                long totalDocs = bucket.getDocCount();
                Aggregation visitedDocs = bucket.getAggregations().get(filterName);
                //long visitedDocsCount = visitedDocs.getValue();
                System.out.println();
            }
        } catch (IOException e) { //...

Я возился с этим весь день и не могу добиться никакого прогресса. Это особенно расстраивает, потому что я могу видеть количество документов для каждой корзины рекомендаций, когда я отлаживаю в своей среде IDE, но я понятия не имею, как получить к ней доступ. Я понимаю, что существует около 180 классов, расширяющих агрегирование, и я пробовал несколько, но каждый раз терпел неудачу.

Кроме того, если вы знаете какой-либо достойный ресурс для клиента высокого уровня rest elasticsearch java, пожалуйста, дайте мне знать. Спасибо!

--------- РЕДАКТИРОВАТЬ 5/4/21 -------------

Пример вывода от elasticsearch:

// searchResponse (documents returned have been truncated to show only part we are interested in)

  "aggregations": {
    "sterms#recommenderId": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "AdjacentActivityRecommender",
          "doc_count": 3,
          "filters#wasVisited": {
            "buckets": {
              "recommender": {
                "doc_count": 2
              }
            }
          }
        },
        {
          "key": "DefaultProfileDBRecommender",
          "doc_count": 2,
          "filters#wasVisited": {
            "buckets": {
              "recommender": {
                "doc_count": 2
              }
            }
          }
        },
        {
          "key": "PSTR_SC_DI",
          "doc_count": 2,
          "filters#wasVisited": {
            "buckets": {
              "recommender": {
                "doc_count": 1
              }
            }
          }
        },
        {
          "key": "SignificantCategories",
          "doc_count": 2,
          "filters#wasVisited": {
            "buckets": {
              "recommender": {
                "doc_count": 2
              }
            }
          }
        }
      ]
    }
  }

searchResponse.getAggregations () затем сохраняется в агрегаты. В конце концов, мы можем перебирать сегменты для каждого идентификатора RecommenderID, но я никогда не могу войти в агрегаты внутри каждого контейнера, что мне и нужно сделать.


person redgrengrumbholt    schedule 04.05.2021    source источник
comment
Не могли бы вы опубликовать пример того, как эластичный поиск дает результат?   -  person Vitor Santos    schedule 04.05.2021
comment
Добавлен пример эластичного отклика. Счетчик документов равен 0 для каждого сегмента, что фактически ожидается в этом наборе результатов.   -  person redgrengrumbholt    schedule 04.05.2021
comment
API Java немного громоздок. По своему опыту я бы попытался получить вашу агрегацию и передать ее в MultiBucketsAggregation. Пример: ((MultiBucketsAggregation) aggregations.get (sterms # RecommenderId)). Затем вы можете перебрать каждую корзину с помощью метода getBuckets. Внутри каждой корзины вы должны иметь возможность вызывать getAggregations (), и это должно дать вам необходимые данные. Это мое лучшее предположение.   -  person Vitor Santos    schedule 04.05.2021
comment
Спасибо @VitorSantos! Я действительно понял это несколько дней назад, и это сработало. Раствор все время был прямо у меня под носом (ага !!). Мне нужна моя рабочая машина, и я опубликую решение здесь в понедельник для потомков.   -  person redgrengrumbholt    schedule 08.05.2021


Ответы (1)


Код решения размещен ниже:

    try {
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        Aggregations aggregations = searchResponse.getAggregations();
        Terms byRecommenderId = aggregations.get(aggregationName);
        for (Terms.Bucket bucket : byRecommenderId.getBuckets()) {
            String recommenderId = bucket.getKeyAsString();
            double totalDocs = bucket.getDocCount();
            // next two lines are the solution:
            Aggregations subAggregations = bucket.getAggregations();
            Filters byWasVisited = subAggregations.get(filterName);
            // always only one item from getBuckets()
            double totalVisited = byWasVisited.getBuckets().get(0).getDocCount();
            double percentVisited = totalVisited / totalDocs;
            recommenderViews.put(recommenderId, percentVisited);
        } 
        // ...

Проблема заключалась в том, что мне нужно было извлечь следующий внутренний уровень агрегации (subAggregations), который выполняется повторным вызовом getAggregations (), на этот раз внутри цикла. На этом этапе мы просто вызываем get (filterName) из подагрегатов.

person redgrengrumbholt    schedule 10.05.2021