elastic / elasticsearch-php

Official PHP client for Elasticsearch.
https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html
MIT License
5.25k stars 963 forks source link

please help me change the php code from pagination from + size to search_after #1404

Closed chongshengdz closed 2 weeks ago

chongshengdz commented 1 month ago

please help me change the php code from pagination from + size to search_after, product_id is the unique id for sorting.

   $start = ($params['page'] - 1) * $params['limit'];
    $body = [
        '_source' => ['product_id','name','categories','category_0_name','category_1_name','model','manufacturer'],
        'query' => $query,
        'from' => $start,
        'size' => $params['limit'],
        'sort' => ['product_id' => ['order' => asc]]
    ];

    $search = [
        'index' => $index,
        //'type' => $type,
        'type' => '_doc',
        'body' => $body
    ];

    $return = [
        'hits' => [],
        'total' => 0,
        'took' => null,
        'filters' => [],
    ];

    try{
        $results = $this->client->search($search);
    }catch(\Exception $e){
        $this->registry->get('log')->write('FATAL: Search failed. Error: '.$e->getMessage());
        return $return;
    }

    $return['took'] = $results['took'];
    $return['timed_out'] = $results['timed_out'];

    $language = $this->session->data['language'];

    if (isset($results['hits']) && count($results['hits'])):
        $return['total'] = $results['hits']['total'];
        $return['hits'] = [];
        $position = 1;
        foreach ($results['hits']['hits'] as $hit):
            $return['hits'][] = $hit['_id'];
            $return['products'][$hit['_id']] = [
                'id' => (int) $hit['_id'],
                'product_id' =>   $hit['_source']['product_id'],
                'name' => $hit['_source']['name'][$language],
                'category_0_name' => isset($hit['_source']['category_0_name'][$language]) ? $hit['_source']['category_0_name'][$language] : '',
                'category_1_name' => isset($hit['_source']['category_1_name'][$language]) ? $hit['_source']['category_1_name'][$language] : '',
                'position' =>   $position,
                'model' =>   $hit['_source']['model'],
                'position_overall' =>   $position + $start,
                'manufacturer' => isset($hit['_source']['manufacturer']) ? $hit['_source']['manufacturer']['name'] : '_none_',
            ];
            $position++;
        endforeach;
    endif;
dadoonet commented 1 month ago

That has also been reported and discussed at https://discuss.elastic.co/t/360323

ezimuel commented 2 weeks ago

@chongshengdz I removed your comment since it was not appropriate. Please, remember that this is an issue repository about the library and not a place to ask for consultancy. Elastic has the discuss.elastic.co for this type of request and community support.

That said, the search_after is a parameter that you need to send in order to start search after a sort result. You can read about it in the Elasticsearch documentation here.

Here the code that you need to change:

$body = [
    '_source' => ['product_id','name','categories','category_0_name','category_1_name','model','manufacturer'],
    'query' => $query,
    'size' => $params['limit'],
    'sort' => ['product_id' => ['order' => 'asc']]
];

// the search_after must be passed in the request, if not this is the first search
if (isset($params['search_after'])) {
    $body['search_after'] = $params['search_after']; // array
}

$search = [
    'index' => $index,
    'body' => $body
];

$return = [
    'hits' => [],
    'total' => 0,
    'took' => null,
    'filters' => [],
];

try{
    $results = $this->client->search($search);
}catch(\Exception $e){
    $this->registry->get('log')->write('FATAL: Search failed. Error: '.$e->getMessage());
    return $return;
}

$return['took'] = $results['took'];
$return['timed_out'] = $results['timed_out'];

$language = $this->session->data['language'];

if (isset($results['hits']) && count($results['hits'])):
    $return['total'] = $results['hits']['total'];
    $return['hits'] = [];
    $position = 1;
    foreach ($results['hits']['hits'] as $hit):
        $return['hits'][] = $hit['_id'];
        $return['products'][$hit['_id']] = [
            'id' => (int) $hit['_id'],
            'product_id' =>   $hit['_source']['product_id'],
            'name' => $hit['_source']['name'][$language],
            'category_0_name' => isset($hit['_source']['category_0_name'][$language]) ? $hit['_source']['category_0_name'][$language] : '',
            'category_1_name' => isset($hit['_source']['category_1_name'][$language]) ? $hit['_source']['category_1_name'][$language] : '',
            'position' =>   $position,
            'model' =>   $hit['_source']['model'],
            'position_overall' =>   $position + $start,
            'manufacturer' => isset($hit['_source']['manufacturer']) ? $hit['_source']['manufacturer']['name'] : '_none_',
        ];
        $search_after = $hit['sort']; // we need to store the last sort value (array)
        $position++;
    endforeach;
endif;

// here you need to pass the $search_after to the next request as $params['search_after]
// remember that search_after is an array

As reported in the documentation, if you do an index refresh between multiple search, you can have inconsistent results. In order to avoid this you need to have a Point in time value (PIT) that will freeze the results for a keep_alive time frame (es. 1m).

chongshengdz commented 2 weeks ago

@ezimuel could you please share your email address, so I can send you the ftp account, still don't quite understand how to do it.

chongshengdz commented 2 weeks ago

search_plus-control.txt

search_plus-model.txt @ezimuel here are the control and model files, please help me change the php code from pagination from + size to search_after again, I do really need your help.

ezimuel commented 2 weeks ago

@chongshengdz I'm sorry but I cannot give you my email address or helping more on this. Again, this github repository is not a consultancy service. We only focus on issue related to the elasticseach-php client library. Moreover, I took already some of my time to help you in the previous comment, where I changed the code that you provided showing how to apply the search_after feature.

I suggest to ask in https://discuss.elastic.co/ for more help. I'm sorry but I'll close this since it's not an issue.