Агрегация + сортировка +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/...