diff --git a/src/ElasticSearch.php b/src/ElasticSearch.php index 2b10385..5ef7f16 100644 --- a/src/ElasticSearch.php +++ b/src/ElasticSearch.php @@ -123,7 +123,7 @@ public function query($queryString, $type, $start = 0, $count = 10, $order = '_i /** * (Re)Generate the index for a given resource * @param IndexIterator|array $documents - * @return integer + * @throws ClientErrorResponseException */ public function index($documents = []): int { diff --git a/src/ElasticSearchIndexer.php b/src/ElasticSearchIndexer.php index f405c6c..8c41c4d 100644 --- a/src/ElasticSearchIndexer.php +++ b/src/ElasticSearchIndexer.php @@ -22,6 +22,7 @@ namespace oat\tao\elasticsearch; use Elasticsearch\Client; +use Elasticsearch\Common\Exceptions\ClientErrorResponseException; use Psr\Log\LoggerInterface; use RuntimeException; use Iterator; @@ -74,6 +75,7 @@ public function getIndexNameByDocument(IndexDocument $document): string /** * @param Iterator $documents * @return int The number of indexed documents + * @throws ClientErrorResponseException */ public function buildIndex(Iterator $documents): int { @@ -110,6 +112,10 @@ public function buildIndex(Iterator $documents): int if ($blockSize === self::INDEXING_BLOCK_SIZE) { $clientResponse = $this->client->bulk($params); + if ($clientResponse['errors'] === true) { + throw new ClientErrorResponseException($this->parseErrors($clientResponse)); + } + $this->logger->debug('client response: '. json_encode($clientResponse)); $count += $blockSize; @@ -121,7 +127,11 @@ public function buildIndex(Iterator $documents): int if ($blockSize > 0) { $clientResponse = $this->client->bulk($params); - $this->logger->debug('client response: '. json_encode($clientResponse)); + if ($clientResponse['errors'] === true) { + throw new ClientErrorResponseException($this->parseErrors($clientResponse)); + } + + $this->logger->debug('client response: ' . json_encode($clientResponse)); $count += $blockSize; } @@ -141,7 +151,7 @@ public function deleteDocument($id): bool $deleteParams = [ 'type' => '_doc', 'index' => $document['_index'], - 'id' => $document['_id'] + 'id' => $document['_id'], ]; $this->getClient()->delete($deleteParams); @@ -154,6 +164,7 @@ public function deleteDocument($id): bool /** * @param array $ids * @param string $type + * * @return array */ public function searchResourceByIds($ids = []) @@ -214,4 +225,15 @@ private function extendBatch(string $action, string $indexName, IndexDocument $d return $params; } + + private function parseErrors(array $clientResponse): string + { + $errors = ''; + + foreach ($clientResponse['items'] as $response) { + $response = reset($response); + $errors .= $response['error']['reason'] . '; '; + } + return $errors; + } } diff --git a/test/ElasticSearchIndexerTest.php b/test/ElasticSearchIndexerTest.php index e12cbe5..850367f 100644 --- a/test/ElasticSearchIndexerTest.php +++ b/test/ElasticSearchIndexerTest.php @@ -23,6 +23,7 @@ namespace oat\tao\test\elasticsearch; use Elasticsearch\Client; +use Elasticsearch\Common\Exceptions\ClientErrorResponseException; use oat\generis\test\TestCase; use oat\oatbox\log\LoggerService; use oat\tao\elasticsearch\ElasticSearchIndexer; @@ -30,6 +31,7 @@ use oat\tao\model\search\index\IndexDocument; use oat\tao\model\TaoOntology; use ArrayIterator; +use PHPUnit\Framework\MockObject\MockObject; /** * ElasticSearchIndexerTest @@ -88,6 +90,106 @@ public function testGetIndexNameByDocumentForUnclassifieds(): void $this->assertSame(IndexerInterface::UNCLASSIFIEDS_DOCUMENTS_INDEX, $indexName); } + public function testBuildIndexBulkErrorResponseAfter100(): void + { + $this->expectException(ClientErrorResponseException::class); + $this->expectExceptionMessage('some reason; some other reason'); + + $document = $this->createMock(IndexDocument::class); + $document->expects($this->any()) + ->method('getBody') + ->willReturn([ + 'type' => [ + TaoOntology::CLASS_URI_ITEM, + ], + ]); + + $document->expects($this->any()) + ->method('getId') + ->willReturn('some_id'); + + $this->client + ->expects($this->atMost(100)) + ->method('bulk') + ->willReturn([ + 'errors' => true, + 'items' => [ + [ + [ + 'error' => [ + 'reason' => 'some reason', + ], + ], + ], + [ + [ + 'error' => [ + 'reason' => 'some other reason', + ], + ], + ], + ], + ]); + + $iterator = $this->createIterator($this->getMultipleDocs($document, 101)); + + + $this->sut->buildIndex($iterator); + } + + private function getMultipleDocs(MockObject $doc, $quantity) + { + $bigArray = []; + for ($i = 1; $i <= $quantity; $i++) { + array_push($bigArray, $doc); + } + + return $bigArray; + } + + public function testBuildIndexBulkErrorResponse(): void + { + $this->expectException(ClientErrorResponseException::class); + $this->expectExceptionMessage('some reason; some other reason'); + $document = $this->createMock(IndexDocument::class); + $document->expects($this->any()) + ->method('getBody') + ->willReturn([ + 'type' => [ + TaoOntology::CLASS_URI_ITEM, + ], + ]); + + $document->expects($this->any()) + ->method('getId') + ->willReturn('some_id'); + + $this->client + ->method('bulk') + ->willReturn([ + 'errors' => true, + 'items' => [ + [ + [ + 'error' => [ + 'reason' => 'some reason', + ], + ], + ], + [ + [ + 'error' => [ + 'reason' => 'some other reason', + ], + ], + ], + ], + ]); + $iterator = $this->createIterator([$document]); + + $this->sut->buildIndex($iterator); + } + public function testBuildIndex(): void { $document = $this->createMock(IndexDocument::class);