Skip to content

Commit

Permalink
Merge branch 'main' into 8.8
Browse files Browse the repository at this point in the history
  • Loading branch information
ezimuel committed May 22, 2023
2 parents 32580dc + bd99d31 commit 68dfe7c
Show file tree
Hide file tree
Showing 11 changed files with 855 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .ci/test-matrix.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
STACK_VERSION:
- 8.8-SNAPSHOT
- 8.9-SNAPSHOT

PHP_VERSION:
- 8.2-cli
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
matrix:
php-version: [7.4, 8.0, 8.1, 8.2]
os: [ubuntu-latest]
es-version: [8.8-SNAPSHOT]
es-version: [8.9-SNAPSHOT]

steps:
- name: Checkout
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/unified-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
strategy:
fail-fast: false
matrix:
stack_version: ['8.8.0-SNAPSHOT']
stack_version: ['8.9.0-SNAPSHOT']

steps:
- name: Checkout
Expand Down
2 changes: 1 addition & 1 deletion src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
final class Client implements ClientInterface
{
const CLIENT_NAME = 'es';
const VERSION = '8.8.0';
const VERSION = '8.9.0';
const API_COMPATIBILITY_HEADER = '%s/vnd.elasticsearch+%s; compatible-with=8';

use ClientEndpointsTrait;
Expand Down
166 changes: 166 additions & 0 deletions src/Helper/Iterators/SearchHitIterator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
<?php
/**
* Elasticsearch PHP Client
*
* @link https://github.com/elastic/elasticsearch-php
* @copyright Copyright (c) Elasticsearch B.V (https://www.elastic.co)
* @license https://opensource.org/licenses/MIT MIT License
*
* Licensed to Elasticsearch B.V under one or more agreements.
* Elasticsearch B.V licenses this file to you under the MIT License.
* See the LICENSE file in the project root for more information.
*/
declare(strict_types = 1);

namespace Elastic\Elasticsearch\Helper\Iterators;

use Countable;
use Elastic\Elasticsearch\Exception\ClientResponseException;
use Elastic\Elasticsearch\Exception\ServerResponseException;
use Iterator;

class SearchHitIterator implements Iterator, Countable
{

/**
* @var SearchResponseIterator
*/
private SearchResponseIterator $searchResponses;

/**
* @var int
*/
protected int $currentKey;

/**
* @var int
*/
protected int $currentHitIndex;

/**
* @var array|null
*/
protected ?array $currentHitData;

/**
* @var int
*/
protected int $count = 0;

/**
* Constructor
*
* @param SearchResponseIterator $searchResponses
*/
public function __construct(SearchResponseIterator $searchResponses)
{
$this->searchResponses = $searchResponses;
}

/**
* Rewinds the internal SearchResponseIterator and itself
*
* @return void
* @throws ClientResponseException
* @throws ServerResponseException
* @see Iterator::rewind()
*/
public function rewind(): void
{
$this->currentKey = 0;
$this->searchResponses->rewind();

// The first page may be empty. In that case, the next page is fetched.
$currentPage = $this->searchResponses->current();
if ($this->searchResponses->valid() && empty($currentPage['hits']['hits'])) {
$this->searchResponses->next();
}

$this->count = 0;
if (isset($currentPage['hits']['total']['value'], $currentPage['hits']['total'])) {
$this->count = $currentPage['hits']['total']['value'] ?? $currentPage['hits']['total'];
}

$this->readPageData();
}

/**
* Advances pointer of the current hit to the next one in the current page. If there
* isn't a next hit in the current page, then it advances the current page and moves the
* pointer to the first hit in the page.
*
* @return void
* @throws ClientResponseException
* @throws ServerResponseException
* @see Iterator::next()
*/
public function next(): void
{
$this->currentKey++;
$this->currentHitIndex++;
$currentPage = $this->searchResponses->current();
if (isset($currentPage['hits']['hits'][$this->currentHitIndex])) {
$this->currentHitData = $currentPage['hits']['hits'][$this->currentHitIndex];
} else {
$this->searchResponses->next();
$this->readPageData();
}
}

/**
* Returns a boolean indicating whether or not the current pointer has valid data
*
* @return bool
* @see Iterator::valid()
*/
public function valid(): bool
{
return is_array($this->currentHitData);
}

/**
* Returns the current hit
*
* @return array
* @see Iterator::current()
*/
public function current(): array
{
return $this->currentHitData;
}

/**
* Returns the current hit index. The hit index spans all pages.
*
* @return int
* @see Iterator::key()
*/
public function key(): int
{
return $this->currentKey;
}

/**
* Advances the internal SearchResponseIterator and resets the currentHitIndex to 0
*
* @internal
*/
private function readPageData(): void
{
if ($this->searchResponses->valid()) {
$currentPage = $this->searchResponses->current();
$this->currentHitIndex = 0;
$this->currentHitData = $currentPage['hits']['hits'][$this->currentHitIndex];
} else {
$this->currentHitData = null;
}
}

/**
* {@inheritDoc}
*/
public function count(): int
{
return $this->count;
}
}
192 changes: 192 additions & 0 deletions src/Helper/Iterators/SearchResponseIterator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
<?php
/**
* Elasticsearch PHP Client
*
* @link https://github.com/elastic/elasticsearch-php
* @copyright Copyright (c) Elasticsearch B.V (https://www.elastic.co)
* @license https://opensource.org/licenses/MIT MIT License
*
* Licensed to Elasticsearch B.V under one or more agreements.
* Elasticsearch B.V licenses this file to you under the MIT License.
* See the LICENSE file in the project root for more information.
*/
declare(strict_types = 1);

namespace Elastic\Elasticsearch\Helper\Iterators;

use Elastic\Elasticsearch\ClientInterface;
use Elastic\Elasticsearch\Exception\ClientResponseException;
use Elastic\Elasticsearch\Exception\ServerResponseException;
use Iterator;

class SearchResponseIterator implements Iterator
{

/**
* @var ClientInterface
*/
private ClientInterface $client;

/**
* @var array
*/
private array $params;

/**
* @var int
*/
private int $currentKey = 0;

/**
* @var array
*/
private array $currentScrolledResponse;

/**
* @var string|null
*/
private ?string $scrollId;

/**
* @var string duration
*/
private $scrollTtl;

/**
* Constructor
*
* @param ClientInterface $client
* @param array $searchParams Associative array of parameters
* @see ClientInterface::search()
*/
public function __construct(ClientInterface $client, array $searchParams)
{
$this->client = $client;
$this->params = $searchParams;

if (isset($searchParams['scroll'])) {
$this->scrollTtl = $searchParams['scroll'];
}
}

/**
* Destructor
*
* @throws ClientResponseException
* @throws ServerResponseException
*/
public function __destruct()
{
$this->clearScroll();
}

/**
* Sets the time to live duration of a scroll window
*
* @param string $timeToLive
* @return $this
*/
public function setScrollTimeout(string $timeToLive): SearchResponseIterator
{
$this->scrollTtl = $timeToLive;
return $this;
}

/**
* Clears the current scroll window if there is a scroll_id stored
*
* @return void
* @throws ClientResponseException
* @throws ServerResponseException
*/
private function clearScroll(): void
{
if (!empty($this->scrollId)) {
/* @phpstan-ignore-next-line */
$this->client->clearScroll(
[
'body' => [
'scroll_id' => $this->scrollId
],
'client' => [
'ignore' => 404
]
]
);
$this->scrollId = null;
}
}

/**
* Rewinds the iterator by performing the initial search.
*
* @return void
* @throws ClientResponseException
* @throws ServerResponseException
* @see Iterator::rewind()
*/
public function rewind(): void
{
$this->clearScroll();
$this->currentKey = 0;
/* @phpstan-ignore-next-line */
$this->currentScrolledResponse = $this->client->search($this->params)->asArray();
$this->scrollId = $this->currentScrolledResponse['_scroll_id'];
}

/**
* Fetches every "page" after the first one using the lastest "scroll_id"
*
* @return void
* @throws ClientResponseException
* @throws ServerResponseException
* @see Iterator::next()
*/
public function next(): void
{
/* @phpstan-ignore-next-line */
$this->currentScrolledResponse = $this->client->scroll(
[
'body' => [
'scroll_id' => $this->scrollId,
'scroll' => $this->scrollTtl
]
]
)->asArray();
$this->scrollId = $this->currentScrolledResponse['_scroll_id'];
$this->currentKey++;
}

/**
* Returns a boolean value indicating if the current page is valid or not
*
* @return bool
* @see Iterator::valid()
*/
public function valid(): bool
{
return isset($this->currentScrolledResponse['hits']['hits'][0]);
}

/**
* Returns the current "page"
*
* @return array
* @see Iterator::current()
*/
public function current(): array
{
return $this->currentScrolledResponse;
}

/**
* Returns the current "page number" of the current "page"
*
* @return int
* @see Iterator::key()
*/
public function key(): int
{
return $this->currentKey;
}
}
Loading

0 comments on commit 68dfe7c

Please sign in to comment.