Агрегация + сортировка +pagination в упругом поиске

Мне нужно сделать агрегацию + сортировку + разбиение на страницы в одном из индексов.

Я узнал о внутренней функциональности Elastic search,

У меня есть 5 общих осколков, он сортирует отдельные осколки и извлекает результат, по умолчанию каждый осколок будет возвращен в 10 записях. Затем 50 записей сортируются снова, и они будут извлекать 10 лучших записей, так как размер по умолчанию равен 10.

Ouput:

Агрегированные результаты возвращаются в отдельном поле под названием "агрегации". Для того, чтобы разбивать страницы на эти агрегированные данные, размер и из них не работают.

Так устали от termBuilder.size(500), теперь логика отличалась по этой ссылке (http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html)

Это приводит к неточности данных.

Может ли кто-нибудь предложить мне, как бороться с агрегацией + разбиение на страницы.

Ответ 1

В поиске elastics невозможно разбивать агрегацию. Запрос не даст точных результатов, если задан размер. Таким образом, единственный способ сортировки и разбивки на страницы - предоставить размер 0 и вернуть все документы, а затем получить требуемые результаты, скопировав все результаты в список для дальнейшей работы.

Ответ 2

Я думаю, что Composite Aggregation может решить вашу проблему, поскольку она позволяет разбивать на страницы в рамках агрегированных результатов.

Пожалуйста, обратитесь к этому документу

Ответ 3

Результаты агрегации пейджинга поддерживаются с помощью partition. Этот раздел в официальных документах очень полезен. https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html#_filtering_values_with_partitions

{
   "size": 0,
   "aggs": {
      "expired_sessions": {
         "terms": {
            "field": "account_id",
            "include": {
               "partition": 0,
               "num_partitions": 20
            },
            "size": 10000,
            "order": {
               "last_access": "asc"
            }
         },
         "aggs": {
            "last_access": {
               "max": {
                  "field": "access_date"
               }
            }
         }
      }
   }
}

Ответ 4

ElasticSearch поддерживает Bucket Sort Aggregation в версии 6.1 и новее. Это позволяет параметры "сортировать", "размер" и "от" в агрегированных результатах.

Пожалуйста, обратитесь к этому документу

Ответ 5

В elasticsearch нет точного решения. Вы можете использовать фильтрацию с параметрами разделов, но применяемый разделитель может разорвать ваш отсортированный результат. ES выполняет операцию разделения по заданному полю и возвращает ведра из запрашиваемого раздела. Таким образом, ваш результат заканчивается упорядоченным разделением (вам нужно сделать последующий запрос с другим номером раздела для сбора данных со всех разделов).

Мое предложение дает более высокое значение размера для каждого термина, как вы упомянули в своем вопросе.

Ответ 6

Вы можете использовать работу. Предположим, вы хотите показать 10 записей на странице в порядке возрастания поля f1, а затем сохранить последнее значение этого поля для каждой страницы (10-е, 20-е...) и использовать больше и сортировать в поисковом запросе.

Ответ 7

Если кто-то также борется с той же проблемой, вот решение для PHP и Elastica (http://elastica.io/), которое работает для меня.

function addAggregationFields($oAgg){
    $oAggField = new Stats('costs');
    $oAggField->setField('costs');
    $oAgg->addAggregation($oAggField);
    return $oAgg;
}
function addAggregationFilters($oAggFilter){
    $oFilters = new \Elastica\Query\Terms();
    $oFilters->setTerms("user_id", [3,7]);
    $oAggFilter->setFilter($oFilters);
    return $oAggFilter;
}


$iItemsInPage = 100;
$iPage        = 0;
$sGoupBy = "created_date";

$oStore = new Store();
$oStore->setConfiguration(new SearchConfiguration());
$oIndex = $oStore->getIndex("report_*");

$oAggFilter = new Filter('cardinality');
$oAggFilter = addAggregationFilters($oAggFilter);

$oAgg = new Cardinality('cardinality');
$oAgg->setField($sGoupBy);
$oAggFilter->addAggregation($oAgg);

$oCardinalityQuery = new Query();
$oCardinalityQuery->setSize(0);
$oCardinalityQuery->addAggregation($oAggFilter);
$resultSet = $oIndex->search($oCardinalityQuery)->getAggregations();

if(isset($resultSet['cardinality'])) {
    $iCardinality = $resultSet['cardinality']['cardinality']['value'];
    if(0 != $resultSet['cardinality']['cardinality']['value']) {
        $iPages = ceil($iCardinality / $iItemsInPage);
    } else {
        $iPages = 1;
    }
}

$oAggFilter = new Filter('aggregation_result');
$oAggFilter = addAggregationFilters($oAggFilter);

$oAgg = new \Elastica\Aggregation\Terms('terms');
$oAgg->setField($sGoupBy);
$oAgg->setParam("include", array("partition" => $iPage, "num_partitions" => $iPages));
$oAgg->setOrder('costs.sum', 'desc');

$oAgg->setSize($iItemsInPage);
$oAgg = $this->addAggregationFields($oAgg);
$oAggFilter->addAggregation($oAgg);

$oQuery = new Query();
$oQuery->addAggregation($oAggFilter);
$oQuery->setSize(0);

$resultSet = $oIndex->search($oQuery)->getAggregations();

Процесс описан здесь fooobar.com/info/4829910/...