Анализ ответа на вложенный запрос агрегации

#java #json #elasticsearch

#java #json #elasticsearch

Вопрос:

Это результат вложенного запроса агрегации ES. Мне нужно проанализировать этот ответ и преобразовать его в новый формат JSON. Из следующего JSON единственными полями, которые меня интересуют, являются значения key_as_a_string и значение яблок и апельсинов для каждого ключа.

 "aggregations": {
    "Inner_aggregation": {
        "doc_count": 366,
        "Hours_aggregation": {
            "doc_count": 366,
            "by_day": {
                "buckets": [
                    {
                        "key_as_string": "2016-01-11",
                        "key": 1452556800000,
                        "doc_count": 1,
                        "Apples": {
                            "value": 5
                        },
                        "Oranges": {
                            "value": 3
                        }
                    },
                    {
                        "key_as_string": "2016-01-12",
                        "key": 1452556800000,
                        "doc_count": 1,
                        "Apples": {
                            "value": 43
                        },
                        "Oranges": {
                            "value": 2
                        }
                    },
                    .........,
                    .........
                ]
            }
        }
    }
 }
}
  

Я могу проанализировать его с помощью Jackson objectmapper или с помощью метода sr.getAggregations().get(«histogram_name»), а затем выполнить итерацию по коллекциям. Хотел узнать, есть ли простой способ.

Требуемый формат JSON

 {
    "Results": [{
        "key_as_string": "2016-01-11",
        "Apple_to_Orange_Ratio": 0.112
    }, {
        "key_as_string": "2016-01-12",
        "Apple_to_Orange_Ratio": 0.12
    }]
}
  

Соотношение будет найдено простым делением количества яблок и апельсинов.

Комментарии:

1. нет, это ответ интерфейса rest, поступающий из кластера, вы не можете изменить формат ответа. В этом весь смысл rest. Для перевода данных может потребоваться переводчик между вашим кластером и клиентом.

Ответ №1:

Когда ваше представление Java сильно отличается от сложной вложенной структуры, может оказаться бесполезным сопоставлять json непосредственно с классами Java. Вы могли бы обрабатывать такого рода данные динамически.

Вот способ обработки таких данных с использованием Java 8 и библиотеки Dynamics.

Мы анализируем json в структуру карты / списка и преобразуем это в динамический экземпляр

 Map jsonMap = new ObjectMapper().readValue(exampleJson, Map.class);
Dynamic jsonData = Dynamic.from(jsonMap);
  

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

 List<MyResult> results = jsonData
    .dget("aggregations.Inner_aggregation.Hours_aggregation.by_day.buckets")
    .children()
    .map(bucket -> new MyResult(bucket))
    .collect(toList());
  

Теперь наш класс myResult может обрабатывать данные корзины, которые также являются динамическим экземпляром.

 public class MyResult {
    private final Dynamic bucket;

    public Result(Dynamic bucket) {
        this.bucket = bucket;
    }

    public String getKey() {
        return bucket.get("key_as_string").asString();
    }

    public double getAppleToOrangeRatio() {
        double apples = bucket.dget("Apples.value").convert().intoDouble();
        double oranges = bucket.dget("Oranges.value").convert().intoDouble();
        return oranges / apples;
    }
}
  

И мы можем получить доступ к соотношениям.

 double appleToOrangeRatio = results.get(0).getAppleToOrangeRatio();
// 0.6
  

См. https://github.com/alexheretic/dynamics для получения источника, документации и примеров.