弹性搜索中的聚合+排序+分页

时间:2015-01-05 09:27:40

标签: elasticsearch

我需要在其中一个索引中进行聚合+排序+分页。

我了解了弹性搜索的内部功能,

我有5个总分片,它会对各个分片进行排序并获取结果,默认情况下,每个分片将返回10个记录。然后再对50条记录进行排序,它将获取前十条记录,因为默认大小为10。

输出中:

聚合结果在名为“aggregations”的单独字段中返回。为了在此聚合数据中进行分页,大小和from不起作用。

厌倦了做termBuilder.size(500),现在逻辑因此链接而异(http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html

导致数据不准确。

任何人都可以建议我如何处理聚合+分页。

8 个答案:

答案 0 :(得分:12)

在elasticsearch中,不可能对聚合进行分页。如果指定了大小,查询将不会给出准确的结果。因此,进行排序和分页的唯一方法是给出大小为0并返回所有文档,然后通过将所有结果累积到列表中以获得进一步操作来获得所需的结果。

答案 1 :(得分:1)

使用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"
               }
            }
         }
      }
   }
}

答案 2 :(得分:1)

我认为Composite Aggregation可能会解决您的问题,因为它允许在汇总结果中进行分页。

请参阅this doc

答案 3 :(得分:1)

ElasticSearch在v6.1和更高版本中支持function watchForm(){ // for every form on the page $('form').on('submit', function(e){ // empty the error element $('#js-error-message').empty(); var searchState = $('#js-stateMenuForm :selected').val(); // call the function that uses the value you are looking forward to. getParks(searchState); // where e is the event e.preventDefault(); return false; // force return of the form's submission }); } 。它允许在汇总结果中进行“排序”,“大小”和“来自”参数。

请参阅this doc

答案 4 :(得分:0)

在弹性搜索中,没有准确的解决方案。 You may use filtering with partition options但已应用的分区程序可能会破坏您的排序结果。 ES对给定字段执行分区操作,从请求的分区返回存储桶。因此,您的结果会以分区顺序结束。(您需要使用其他分区号进行后续请求以从所有分区收集数据。)

我的建议是,如您在问题中所提到的,为每个字词提供更高的尺寸值。

答案 5 :(得分:0)

您可以使用解决方法。假设您希望按字段f1的升序显示每页10条记录,然后为每个页面存储该字段的最后一个值(第10个,第20个......),并在搜索查询中使用大于和排序。

答案 6 :(得分:0)

如果有人也遇到同样的问题,那么这里有一个适用于我的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();

此处https://stackoverflow.com/a/54351245/2923963

描述了该过程

答案 7 :(得分:0)

是的,可以进行分页+排序+搜索elasticsearch Open link。 Elasticsearch在v6.X及更高版本中支持 Bucket Sort Aggregation 。此 bucket_sort 使用条款/ date_histogram存储桶中的所有记录并对其应用。因此,在这种情况下,我们必须保持存储桶大小足够大或大于存储桶记录,以便将所有可能的记录保留在存储桶中。示例如下...

{
    "aggs": {
        "aggs1": {
            "terms": {
                "field": "field_name.keyword",
                // We can do sort here also
                "size": 1000000  // Keep this size big integer. This keep all possible result in bucket
            },
            "aggs": {
                "bucket_sort": {
                    "bucket_sort": {                                 
                        "sort": [{
                            "_key": {
                                "order": "asc"
                            }
                        }],
                        // This "from" and "size" use above terms bucket size. it applies over available bucket data [This one give actual result]
                        // Bellow is standard pagination as we do
                        "from": 0,
                        "size": 10
                    }
                }
            }
        }
    },
    "size": 0
}