From 8d0a26f4719175acf6d9c656e131199b350a1d83 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Sat, 23 Mar 2024 18:09:31 +0100 Subject: [PATCH 1/2] Add aliases for Elasticsearch indexes (#381) --- .../src/ElasticsearchSchemaManager.php | 34 +++++++++++++++++-- .../src/ElasticsearchSearcher.php | 19 +++++++++-- .../tests/ElasticsearchSchemaManagerTest.php | 12 ++++--- 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/packages/seal-elasticsearch-adapter/src/ElasticsearchSchemaManager.php b/packages/seal-elasticsearch-adapter/src/ElasticsearchSchemaManager.php index b8b8af54..f17f7365 100644 --- a/packages/seal-elasticsearch-adapter/src/ElasticsearchSchemaManager.php +++ b/packages/seal-elasticsearch-adapter/src/ElasticsearchSchemaManager.php @@ -14,6 +14,7 @@ namespace Schranz\Search\SEAL\Adapter\Elasticsearch; use Elastic\Elasticsearch\Client; +use Elastic\Elasticsearch\Exception\ClientResponseException; use Elastic\Elasticsearch\Response\Elasticsearch; use Schranz\Search\SEAL\Adapter\SchemaManagerInterface; use Schranz\Search\SEAL\Schema\Field; @@ -40,8 +41,20 @@ public function existIndex(Index $index): bool public function dropIndex(Index $index, array $options = []): TaskInterface|null { + /** @var Elasticsearch $response */ + $response = $this->client->indices()->getAlias([ + 'name' => $index->name, + ]); + + $targetIndexName = \array_key_first($response->asArray()); + + $this->client->indices()->deleteAlias([ + 'name' => $index->name, + 'index' => $targetIndexName, + ]); + $this->client->indices()->delete([ - 'index' => $index->name, + 'index' => $targetIndexName, ]); if (!($options['return_slow_promise_result'] ?? false)) { @@ -55,8 +68,20 @@ public function createIndex(Index $index, array $options = []): TaskInterface|nu { $properties = $this->createPropertiesMapping($index->fields); + $targetIndexName = $index->name . '_' . \date('YmdHis'); + try { + /** @var Elasticsearch $response */ + $response = $this->client->indices()->getAlias([ + 'name' => $index->name, + ]); + + $targetIndexName = \array_key_first($response->asArray()) ?? $targetIndexName; + } catch (ClientResponseException) { + // @ignoreException + } + $this->client->indices()->create([ - 'index' => $index->name, + 'index' => $targetIndexName, 'body' => [ 'mappings' => [ 'dynamic' => 'strict', @@ -65,6 +90,11 @@ public function createIndex(Index $index, array $options = []): TaskInterface|nu ], ]); + $this->client->indices()->putAlias([ + 'name' => $index->name, + 'index' => $targetIndexName, + ]); + if (!($options['return_slow_promise_result'] ?? false)) { return null; } diff --git a/packages/seal-elasticsearch-adapter/src/ElasticsearchSearcher.php b/packages/seal-elasticsearch-adapter/src/ElasticsearchSearcher.php index bec32603..8b32b884 100644 --- a/packages/seal-elasticsearch-adapter/src/ElasticsearchSearcher.php +++ b/packages/seal-elasticsearch-adapter/src/ElasticsearchSearcher.php @@ -147,13 +147,26 @@ public function search(Search $search): Result private function hitsToDocuments(array $indexes, array $hits): \Generator { $indexesByInternalName = []; - foreach ($indexes as $index) { - $indexesByInternalName[$index->name] = $index; - } /** @var array{_index: string, _source: array} $hit */ foreach ($hits as $hit) { $index = $indexesByInternalName[$hit['_index']] ?? null; + if (!$index instanceof Index) { + $lastMaxLength = 0; + + // find the correct index alias as we use %indexName%_%datetime% as index name + foreach ($indexes as $otherIndex) { + if ( + \str_starts_with($hit['_index'], $otherIndex->name . '_') + && $lastMaxLength < \strlen($otherIndex->name) + ) { + $index = $otherIndex; + $lastMaxLength = \strlen($index->name); + } + } + $indexesByInternalName[$hit['_index']] = $index; + } + if (!$index instanceof Index) { throw new \RuntimeException('SchemaMetadata for Index "' . $hit['_index'] . '" not found.'); } diff --git a/packages/seal-elasticsearch-adapter/tests/ElasticsearchSchemaManagerTest.php b/packages/seal-elasticsearch-adapter/tests/ElasticsearchSchemaManagerTest.php index 7a08a418..2f67d6c0 100644 --- a/packages/seal-elasticsearch-adapter/tests/ElasticsearchSchemaManagerTest.php +++ b/packages/seal-elasticsearch-adapter/tests/ElasticsearchSchemaManagerTest.php @@ -47,7 +47,9 @@ public function testSimpleElasticsearchMapping(): void $task = static::$schemaManager->dropIndex($index, ['return_slow_promise_result' => true]); $task->wait(); - $this->assertTrue(isset($mapping[$index->name]['mappings']['properties'])); + $targetIndexName = \array_key_first($mapping); + + $this->assertTrue(isset($mapping[$targetIndexName]['mappings']['properties'])); $this->assertSame([ 'id' => [ @@ -57,7 +59,7 @@ public function testSimpleElasticsearchMapping(): void 'title' => [ 'type' => 'text', ], - ], $mapping[$index->name]['mappings']['properties']); + ], $mapping[$targetIndexName]['mappings']['properties']); } public function testComplexElasticsearchMapping(): void @@ -76,7 +78,9 @@ public function testComplexElasticsearchMapping(): void $task = static::$schemaManager->dropIndex($index, ['return_slow_promise_result' => true]); $task->wait(); - $this->assertTrue(isset($mapping[$index->name]['mappings']['properties'])); + $targetIndexName = \array_key_first($mapping); + + $this->assertTrue(isset($mapping[$targetIndexName]['mappings']['properties'])); $this->assertSame([ 'article' => [ @@ -194,6 +198,6 @@ public function testComplexElasticsearchMapping(): void 'type' => 'keyword', 'index' => false, ], - ], $mapping[$index->name]['mappings']['properties']); + ], $mapping[$targetIndexName]['mappings']['properties']); } } From 496067c1e4aa05b230cba70467a490139226a211 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Sat, 23 Mar 2024 18:40:23 +0100 Subject: [PATCH 2/2] Add index aliases for Opensearch indexes (#384) --- .../src/OpensearchSchemaManager.php | 33 +++++++++++++++++-- .../src/OpensearchSearcher.php | 19 +++++++++-- .../tests/OpensearchSchemaManagerTest.php | 12 ++++--- 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/packages/seal-opensearch-adapter/src/OpensearchSchemaManager.php b/packages/seal-opensearch-adapter/src/OpensearchSchemaManager.php index ee8ecede..efee18fd 100644 --- a/packages/seal-opensearch-adapter/src/OpensearchSchemaManager.php +++ b/packages/seal-opensearch-adapter/src/OpensearchSchemaManager.php @@ -14,6 +14,7 @@ namespace Schranz\Search\SEAL\Adapter\Opensearch; use OpenSearch\Client; +use OpenSearch\Common\Exceptions\Missing404Exception; use Schranz\Search\SEAL\Adapter\SchemaManagerInterface; use Schranz\Search\SEAL\Schema\Field; use Schranz\Search\SEAL\Schema\Index; @@ -36,8 +37,19 @@ public function existIndex(Index $index): bool public function dropIndex(Index $index, array $options = []): TaskInterface|null { + $responseData = $this->client->indices()->getAlias([ + 'name' => $index->name, + ]); + + $targetIndexName = \array_key_first($responseData); + + $this->client->indices()->deleteAlias([ + 'name' => $index->name, + 'index' => $targetIndexName, + ]); + $this->client->indices()->delete([ - 'index' => $index->name, + 'index' => $targetIndexName, ]); if (!($options['return_slow_promise_result'] ?? false)) { @@ -51,8 +63,20 @@ public function createIndex(Index $index, array $options = []): TaskInterface|nu { $properties = $this->createPropertiesMapping($index->fields); + $targetIndexName = $index->name . '_' . \date('YmdHis'); + + try { + $responseData = $this->client->indices()->getAlias([ + 'name' => $index->name, + ]); + + $targetIndexName = \array_key_first($responseData) ?? $targetIndexName; + } catch (Missing404Exception) { + // @ignoreException + } + $this->client->indices()->create([ - 'index' => $index->name, + 'index' => $targetIndexName, 'body' => [ 'mappings' => [ 'dynamic' => 'strict', @@ -61,6 +85,11 @@ public function createIndex(Index $index, array $options = []): TaskInterface|nu ], ]); + $this->client->indices()->putAlias([ + 'name' => $index->name, + 'index' => $targetIndexName, + ]); + if (!($options['return_slow_promise_result'] ?? false)) { return null; } diff --git a/packages/seal-opensearch-adapter/src/OpensearchSearcher.php b/packages/seal-opensearch-adapter/src/OpensearchSearcher.php index deb71cec..a5512212 100644 --- a/packages/seal-opensearch-adapter/src/OpensearchSearcher.php +++ b/packages/seal-opensearch-adapter/src/OpensearchSearcher.php @@ -124,13 +124,26 @@ public function search(Search $search): Result private function hitsToDocuments(array $indexes, array $hits): \Generator { $indexesByInternalName = []; - foreach ($indexes as $index) { - $indexesByInternalName[$index->name] = $index; - } /** @var array{_index: string, _source: array} $hit */ foreach ($hits as $hit) { $index = $indexesByInternalName[$hit['_index']] ?? null; + if (!$index instanceof Index) { + $lastMaxLength = 0; + + // find the correct index alias as we use %indexName%_%datetime% as index name + foreach ($indexes as $otherIndex) { + if ( + \str_starts_with($hit['_index'], $otherIndex->name . '_') + && $lastMaxLength < \strlen($otherIndex->name) + ) { + $index = $otherIndex; + $lastMaxLength = \strlen($index->name); + } + } + $indexesByInternalName[$hit['_index']] = $index; + } + if (!$index instanceof Index) { throw new \RuntimeException('SchemaMetadata for Index "' . $hit['_index'] . '" not found.'); } diff --git a/packages/seal-opensearch-adapter/tests/OpensearchSchemaManagerTest.php b/packages/seal-opensearch-adapter/tests/OpensearchSchemaManagerTest.php index ed8a872f..c926f802 100644 --- a/packages/seal-opensearch-adapter/tests/OpensearchSchemaManagerTest.php +++ b/packages/seal-opensearch-adapter/tests/OpensearchSchemaManagerTest.php @@ -43,7 +43,9 @@ public function testSimpleOpensearchMapping(): void $task = static::$schemaManager->dropIndex($index, ['return_slow_promise_result' => true]); $task->wait(); - $this->assertTrue(isset($mapping[$index->name]['mappings']['properties'])); + $targetIndexName = \array_key_first($mapping); + + $this->assertTrue(isset($mapping[$targetIndexName]['mappings']['properties'])); $this->assertSame([ 'id' => [ @@ -52,7 +54,7 @@ public function testSimpleOpensearchMapping(): void 'title' => [ 'type' => 'text', ], - ], $mapping[$index->name]['mappings']['properties']); + ], $mapping[$targetIndexName]['mappings']['properties']); } public function testComplexOpensearchMapping(): void @@ -68,7 +70,9 @@ public function testComplexOpensearchMapping(): void $task = static::$schemaManager->dropIndex($index, ['return_slow_promise_result' => true]); $task->wait(); - $this->assertTrue(isset($mapping[$index->name]['mappings']['properties'])); + $targetIndexName = \array_key_first($mapping); + + $this->assertTrue(isset($mapping[$targetIndexName]['mappings']['properties'])); $this->assertSame([ 'article' => [ @@ -180,6 +184,6 @@ public function testComplexOpensearchMapping(): void 'uuid' => [ 'type' => 'keyword', ], - ], $mapping[$index->name]['mappings']['properties']); + ], $mapping[$targetIndexName]['mappings']['properties']); } }