From 1a9846f3f5be759c6d477d8c620c1f8466e57f82 Mon Sep 17 00:00:00 2001 From: meili-bot <74670311+meili-bot@users.noreply.github.com> Date: Mon, 23 Sep 2024 18:22:09 +0200 Subject: [PATCH 1/9] Update README.md From 2fbca6fb1a8f4b1e3f93227eff9ffdc7ef3e3358 Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Tue, 8 Oct 2024 16:20:47 +0200 Subject: [PATCH 2/9] embedder is now a mandatory field --- tests/Endpoints/SearchTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Endpoints/SearchTest.php b/tests/Endpoints/SearchTest.php index dbd6cac3..eea4046c 100644 --- a/tests/Endpoints/SearchTest.php +++ b/tests/Endpoints/SearchTest.php @@ -701,12 +701,12 @@ public function testVectorSearch(): void $this->assertIsValidPromise($promise); $index->waitForTask($promise['taskUid']); - $response = $index->search('', ['vector' => [-0.5, 0.3, 0.85], 'hybrid' => ['semanticRatio' => 1.0]]); + $response = $index->search('', ['vector' => [-0.5, 0.3, 0.85], 'hybrid' => ['semanticRatio' => 1.0, 'embedder' => 'manual']]); self::assertSame(5, $response->getSemanticHitCount()); self::assertArrayNotHasKey('_vectors', $response->getHit(0)); - $response = $index->search('', ['vector' => [-0.5, 0.3, 0.85], 'hybrid' => ['semanticRatio' => 1.0], 'retrieveVectors' => true]); + $response = $index->search('', ['vector' => [-0.5, 0.3, 0.85], 'hybrid' => ['semanticRatio' => 1.0, 'embedder' => 'manual'], 'retrieveVectors' => true]); self::assertSame(5, $response->getSemanticHitCount()); self::assertArrayHasKey('_vectors', $response->getHit(0)); From f1bc0cbf8989b35f02ff63ea8ca00be1bfe8ebec Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Tue, 8 Oct 2024 16:16:10 +0200 Subject: [PATCH 3/9] Add Embedder tests --- tests/Settings/EmbeddersTest.php | 57 ++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 tests/Settings/EmbeddersTest.php diff --git a/tests/Settings/EmbeddersTest.php b/tests/Settings/EmbeddersTest.php new file mode 100644 index 00000000..805d7c5b --- /dev/null +++ b/tests/Settings/EmbeddersTest.php @@ -0,0 +1,57 @@ +host, getenv('MEILISEARCH_API_KEY')); + $http->patch('/experimental-features', ['vectorStore' => true]); + $this->index = $this->createEmptyIndex($this->safeIndexName()); + } + + public function testGetDefaultEmbedders(): void + { + $response = $this->index->getEmbedders(); + + self::assertSame(self::DEFAULT_EMBEDDER, $response); + } + + public function testUpdateEmbedders(): void + { + $newEmbedders = ['manual' => ['source' => 'userProvided', 'dimensions' => 3, 'binaryQuantized' => true]]; + + $promise = $this->index->updateEmbedders($newEmbedders); + + $this->assertIsValidPromise($promise); + $this->index->waitForTask($promise['taskUid']); + + $embedders = $this->index->getEmbedders(); + + self::assertSame($newEmbedders, $embedders); + } + + public function testResetEmbedders(): void + { + $promise = $this->index->resetEmbedders(); + + $this->assertIsValidPromise($promise); + + $this->index->waitForTask($promise['taskUid']); + $embedders = $this->index->getEmbedders(); + + self::assertSame(self::DEFAULT_EMBEDDER, $embedders); + } +} From 6e038a3b7065e464ff91c403583232ec0de3bebe Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Tue, 8 Oct 2024 15:53:37 +0200 Subject: [PATCH 4/9] Make embedder field mandatory in SimilarDocumentsQuery --- .code-samples.meilisearch.yaml | 2 +- src/Contracts/SimilarDocumentsQuery.php | 32 ++++-------- tests/Contracts/SimilarDocumentsQueryTest.php | 52 ++++++++----------- tests/Endpoints/SimilarDocumentsTest.php | 4 +- 4 files changed, 37 insertions(+), 53 deletions(-) diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index 35697bcf..535134d8 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -742,7 +742,7 @@ distinct_attribute_guide_distinct_parameter_1: |- search_parameter_guide_matching_strategy_3: |- $client->index('movies')->search('white shirt', ['matchingStrategy' => 'frequency']); get_similar_post_1: |- - $similarQuery = new SimilarDocumentsQuery('TARGET_DOCUMENT_ID'); + $similarQuery = new SimilarDocumentsQuery('TARGET_DOCUMENT_ID', 'default'); $client->index('INDEX_NAME')->searchSimilarDocuments($similarQuery); multi_search_federated_1: |- $client->multiSearch([ diff --git a/src/Contracts/SimilarDocumentsQuery.php b/src/Contracts/SimilarDocumentsQuery.php index ab6dc95b..04c65ae3 100644 --- a/src/Contracts/SimilarDocumentsQuery.php +++ b/src/Contracts/SimilarDocumentsQuery.php @@ -11,6 +11,11 @@ class SimilarDocumentsQuery */ private $id; + /** + * @var non-empty-string + */ + private string $embedder; + /** * @var non-negative-int|null */ @@ -21,11 +26,6 @@ class SimilarDocumentsQuery */ private ?int $limit = null; - /** - * @var non-empty-string|null - */ - private ?string $embedder = null; - /** * @var list|null */ @@ -48,11 +48,13 @@ class SimilarDocumentsQuery private $rankingScoreThreshold; /** - * @param int|string $id + * @param int|string $id + * @param non-empty-string $embedder */ - public function __construct($id) + public function __construct($id, string $embedder) { $this->id = $id; + $this->embedder = $embedder; } /** @@ -91,18 +93,6 @@ public function setFilter(array $filter): self return $this; } - /** - * @param non-empty-string $embedder - * - * @return $this - */ - public function setEmbedder(string $embedder): self - { - $this->embedder = $embedder; - - return $this; - } - /** * @param list $attributesToRetrieve an array of attribute names to retrieve * @@ -166,10 +156,10 @@ public function setRankingScoreThreshold($rankingScoreThreshold): self /** * @return array{ * id: int|string, + * embedder: non-empty-string, * offset?: non-negative-int, * limit?: positive-int, * filter?: array|string>, - * embedder?: non-empty-string, * attributesToRetrieve?: list, * showRankingScore?: bool, * showRankingScoreDetails?: bool, @@ -181,10 +171,10 @@ public function toArray(): array { return array_filter([ 'id' => $this->id, + 'embedder' => $this->embedder, 'offset' => $this->offset, 'limit' => $this->limit, 'filter' => $this->filter, - 'embedder' => $this->embedder, 'attributesToRetrieve' => $this->attributesToRetrieve, 'showRankingScore' => $this->showRankingScore, 'showRankingScoreDetails' => $this->showRankingScoreDetails, diff --git a/tests/Contracts/SimilarDocumentsQueryTest.php b/tests/Contracts/SimilarDocumentsQueryTest.php index 79785d92..88cbe6e1 100644 --- a/tests/Contracts/SimilarDocumentsQueryTest.php +++ b/tests/Contracts/SimilarDocumentsQueryTest.php @@ -10,54 +10,48 @@ final class SimilarDocumentsQueryTest extends TestCase { /** - * @param int|string $id + * @param int|string $id + * @param non-empty-string $embedder * - * @testWith [123] - * ["test"] + * @testWith [123, "default"] + * ["test", "manual"] */ - public function testConstruct($id): void + public function testConstruct($id, string $embedder): void { - $data = new SimilarDocumentsQuery($id); + $data = new SimilarDocumentsQuery($id, $embedder); - self::assertSame(['id' => $id], $data->toArray()); + self::assertSame(['id' => $id, 'embedder' => $embedder], $data->toArray()); } public function testSetOffset(): void { - $data = (new SimilarDocumentsQuery('test'))->setOffset(66); + $data = (new SimilarDocumentsQuery('test', 'default'))->setOffset(66); - self::assertSame(['id' => 'test', 'offset' => 66], $data->toArray()); + self::assertSame(['id' => 'test', 'embedder' => 'default', 'offset' => 66], $data->toArray()); } public function testSetLimit(): void { - $data = (new SimilarDocumentsQuery('test'))->setLimit(50); + $data = (new SimilarDocumentsQuery('test', 'default'))->setLimit(50); - self::assertSame(['id' => 'test', 'limit' => 50], $data->toArray()); + self::assertSame(['id' => 'test', 'embedder' => 'default', 'limit' => 50], $data->toArray()); } public function testSetFilter(): void { - $data = (new SimilarDocumentsQuery('test'))->setFilter([ + $data = (new SimilarDocumentsQuery('test', 'default'))->setFilter([ ['genres = horror', 'genres = mystery'], "director = 'Jordan Peele'", ]); - self::assertSame(['id' => 'test', 'filter' => [['genres = horror', 'genres = mystery'], "director = 'Jordan Peele'"]], $data->toArray()); - } - - public function testSetEmbedder(): void - { - $data = (new SimilarDocumentsQuery('test'))->setEmbedder('default'); - - self::assertSame(['id' => 'test', 'embedder' => 'default'], $data->toArray()); + self::assertSame(['id' => 'test', 'embedder' => 'default', 'filter' => [['genres = horror', 'genres = mystery'], "director = 'Jordan Peele'"]], $data->toArray()); } public function testSetAttributesToRetrieve(): void { - $data = (new SimilarDocumentsQuery('test'))->setAttributesToRetrieve(['name', 'price']); + $data = (new SimilarDocumentsQuery('test', 'default'))->setAttributesToRetrieve(['name', 'price']); - self::assertSame(['id' => 'test', 'attributesToRetrieve' => ['name', 'price']], $data->toArray()); + self::assertSame(['id' => 'test', 'embedder' => 'default', 'attributesToRetrieve' => ['name', 'price']], $data->toArray()); } /** @@ -66,9 +60,9 @@ public function testSetAttributesToRetrieve(): void */ public function testSetShowRankingScore(bool $showRankingScore): void { - $data = (new SimilarDocumentsQuery('test'))->setShowRankingScore($showRankingScore); + $data = (new SimilarDocumentsQuery('test', 'default'))->setShowRankingScore($showRankingScore); - self::assertSame(['id' => 'test', 'showRankingScore' => $showRankingScore], $data->toArray()); + self::assertSame(['id' => 'test', 'embedder' => 'default', 'showRankingScore' => $showRankingScore], $data->toArray()); } /** @@ -77,9 +71,9 @@ public function testSetShowRankingScore(bool $showRankingScore): void */ public function testSetShowRankingScoreDetails(bool $showRankingScoreDetails): void { - $data = (new SimilarDocumentsQuery('test'))->setShowRankingScoreDetails($showRankingScoreDetails); + $data = (new SimilarDocumentsQuery('test', 'default'))->setShowRankingScoreDetails($showRankingScoreDetails); - self::assertSame(['id' => 'test', 'showRankingScoreDetails' => $showRankingScoreDetails], $data->toArray()); + self::assertSame(['id' => 'test', 'embedder' => 'default', 'showRankingScoreDetails' => $showRankingScoreDetails], $data->toArray()); } /** @@ -88,9 +82,9 @@ public function testSetShowRankingScoreDetails(bool $showRankingScoreDetails): v */ public function testSetRetrieveVectors(bool $retrieveVectors): void { - $data = (new SimilarDocumentsQuery('test'))->setRetrieveVectors($retrieveVectors); + $data = (new SimilarDocumentsQuery('test', 'default'))->setRetrieveVectors($retrieveVectors); - self::assertSame(['id' => 'test', 'retrieveVectors' => $retrieveVectors], $data->toArray()); + self::assertSame(['id' => 'test', 'embedder' => 'default', 'retrieveVectors' => $retrieveVectors], $data->toArray()); } /** @@ -101,8 +95,8 @@ public function testSetRetrieveVectors(bool $retrieveVectors): void */ public function testSetRankingScoreThreshold($rankingScoreThreshold): void { - $data = (new SimilarDocumentsQuery('test'))->setRankingScoreThreshold($rankingScoreThreshold); + $data = (new SimilarDocumentsQuery('test', 'default'))->setRankingScoreThreshold($rankingScoreThreshold); - self::assertSame(['id' => 'test', 'rankingScoreThreshold' => $rankingScoreThreshold], $data->toArray()); + self::assertSame(['id' => 'test', 'embedder' => 'default', 'rankingScoreThreshold' => $rankingScoreThreshold], $data->toArray()); } } diff --git a/tests/Endpoints/SimilarDocumentsTest.php b/tests/Endpoints/SimilarDocumentsTest.php index 20ce0048..c5d6e40c 100644 --- a/tests/Endpoints/SimilarDocumentsTest.php +++ b/tests/Endpoints/SimilarDocumentsTest.php @@ -30,14 +30,14 @@ public function testBasicSearchWithSimilarDocuments(): void self::assertSame(1, $response->getHitsCount()); $documentId = $response->getHit(0)['id']; - $response = $this->index->searchSimilarDocuments(new SimilarDocumentsQuery($documentId)); + $response = $this->index->searchSimilarDocuments(new SimilarDocumentsQuery($documentId, 'manual')); self::assertGreaterThanOrEqual(4, $response->getHitsCount()); self::assertArrayNotHasKey('_vectors', $response->getHit(0)); self::assertArrayHasKey('id', $response->getHit(0)); self::assertSame($documentId, $response->getId()); - $similarQuery = new SimilarDocumentsQuery($documentId); + $similarQuery = new SimilarDocumentsQuery($documentId, 'manual'); $response = $this->index->searchSimilarDocuments($similarQuery->setRetrieveVectors(true)); self::assertGreaterThanOrEqual(4, $response->getHitsCount()); self::assertArrayHasKey('_vectors', $response->getHit(0)); From 03311e0421eb1dbc88dc09c74b8fb17addf3d7f7 Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Tue, 8 Oct 2024 16:52:33 +0200 Subject: [PATCH 5/9] Add facet distribution settings to federated search --- src/Contracts/MultiSearchFederation.php | 35 ++++++++++++++++++- tests/Contracts/MultiSearchFederationTest.php | 14 ++++++++ tests/Endpoints/MultiSearchTest.php | 3 +- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/Contracts/MultiSearchFederation.php b/src/Contracts/MultiSearchFederation.php index 3f9db1ec..79a6ff8f 100644 --- a/src/Contracts/MultiSearchFederation.php +++ b/src/Contracts/MultiSearchFederation.php @@ -16,6 +16,13 @@ class MultiSearchFederation */ private ?int $offset = null; + /** + * @var array>|null + */ + private ?array $facetsByIndex = null; + + private ?array $mergeFacets = null; + /** * @param non-negative-int $limit * @@ -40,10 +47,34 @@ public function setOffset(int $offset): self return $this; } + /** + * @param array> $facetsByIndex + * + * @return $this + */ + public function setFacetsByIndex(array $facetsByIndex): self + { + $this->facetsByIndex = $facetsByIndex; + + return $this; + } + + /** + * @return $this + */ + public function setMergeFacets(array $mergeFacets): self + { + $this->mergeFacets = $mergeFacets; + + return $this; + } + /** * @return array{ * limit?: non-negative-int, - * offset?: non-negative-int + * offset?: non-negative-int, + * facetsByIndex?: array>, + * mergeFacets?: array, * } */ public function toArray(): array @@ -51,6 +82,8 @@ public function toArray(): array return array_filter([ 'limit' => $this->limit, 'offset' => $this->offset, + 'facetsByIndex' => $this->facetsByIndex, + 'mergeFacets' => $this->mergeFacets, ], static function ($item) { return null !== $item; }); } } diff --git a/tests/Contracts/MultiSearchFederationTest.php b/tests/Contracts/MultiSearchFederationTest.php index 191b3692..ec002b21 100644 --- a/tests/Contracts/MultiSearchFederationTest.php +++ b/tests/Contracts/MultiSearchFederationTest.php @@ -29,4 +29,18 @@ public function testSetOffset(): void self::assertSame(['offset' => 5], $data->toArray()); } + + public function testSetFacetsByIndex(): void + { + $data = (new MultiSearchFederation())->setFacetsByIndex(['books' => ['author', 'genre']]); + + self::assertSame(['facetsByIndex' => ['books' => ['author', 'genre']]], $data->toArray()); + } + + public function testSetMergeFacets(): void + { + $data = (new MultiSearchFederation())->setMergeFacets(['maxValuesPerFacet' => 10]); + + self::assertSame(['mergeFacets' => ['maxValuesPerFacet' => 10]], $data->toArray()); + } } diff --git a/tests/Endpoints/MultiSearchTest.php b/tests/Endpoints/MultiSearchTest.php index 0352cae0..9d82ac9c 100644 --- a/tests/Endpoints/MultiSearchTest.php +++ b/tests/Endpoints/MultiSearchTest.php @@ -89,7 +89,7 @@ public function testFederation(): void // By setting the weight to 0.9 this query should appear second ->setFederationOptions((new FederationOptions())->setWeight(0.9)), ], - (new MultiSearchFederation())->setLimit(2) + (new MultiSearchFederation())->setLimit(2)->setFacetsByIndex([$this->booksIndex->getUid() => ['genre'], $this->songsIndex->getUid() => ['duration-float']])->setMergeFacets(['maxValuesPerFacet' => 10]) ); self::assertArrayHasKey('hits', $response); @@ -97,6 +97,7 @@ public function testFederation(): void self::assertArrayHasKey('limit', $response); self::assertArrayHasKey('offset', $response); self::assertArrayHasKey('estimatedTotalHits', $response); + self::assertArrayHasKey('facetDistribution', $response); self::assertCount(2, $response['hits']); self::assertSame(2, $response['limit']); self::assertSame(0, $response['offset']); From a812bc156f7f0790ba5f1cb806c7f06de5fb2bfe Mon Sep 17 00:00:00 2001 From: Many the fish Date: Wed, 9 Oct 2024 07:22:36 +0200 Subject: [PATCH 6/9] Update tests/Settings/EmbeddersTest.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tomas Norkūnas --- tests/Settings/EmbeddersTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Settings/EmbeddersTest.php b/tests/Settings/EmbeddersTest.php index 805d7c5b..35497559 100644 --- a/tests/Settings/EmbeddersTest.php +++ b/tests/Settings/EmbeddersTest.php @@ -12,7 +12,7 @@ final class EmbeddersTest extends TestCase { private Indexes $index; - public const DEFAULT_EMBEDDER = null; + private const DEFAULT_EMBEDDER = null; protected function setUp(): void { From 71ba8f7c1efaacc9301db6d4ac82728e5876482f Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Wed, 9 Oct 2024 10:00:53 +0200 Subject: [PATCH 7/9] Precise mergeFacets type --- src/Contracts/MultiSearchFederation.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Contracts/MultiSearchFederation.php b/src/Contracts/MultiSearchFederation.php index 79a6ff8f..d998aa37 100644 --- a/src/Contracts/MultiSearchFederation.php +++ b/src/Contracts/MultiSearchFederation.php @@ -21,6 +21,9 @@ class MultiSearchFederation */ private ?array $facetsByIndex = null; + /** + * @var array{maxValuesPerFacet: positive-int}|null + */ private ?array $mergeFacets = null; /** @@ -60,6 +63,8 @@ public function setFacetsByIndex(array $facetsByIndex): self } /** + * @param array{maxValuesPerFacet: positive-int} $mergeFacets + * * @return $this */ public function setMergeFacets(array $mergeFacets): self @@ -74,7 +79,7 @@ public function setMergeFacets(array $mergeFacets): self * limit?: non-negative-int, * offset?: non-negative-int, * facetsByIndex?: array>, - * mergeFacets?: array, + * mergeFacets?: array{maxValuesPerFacet: positive-int}, * } */ public function toArray(): array From 39d3cbd6f3878459adc090eeff1c4fe2ad48b0cb Mon Sep 17 00:00:00 2001 From: curquiza Date: Thu, 10 Oct 2024 17:37:56 +0200 Subject: [PATCH 8/9] Add code samples --- .code-samples.meilisearch.yaml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index 535134d8..94872534 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -722,7 +722,14 @@ search_parameter_reference_retrieve_vectors_1: |- $client->index('INDEX_NAME')->search('kitchen utensils', [ 'retrieveVectors' => true, 'hybrid' => [ - 'embedder': 'default' + 'embedder': 'EMBEDDER_NAME' + ] + ]); +search_parameter_guide_hybrid_1: |- + $client->index('INDEX_NAME')->search('kitchen utensils', [ + 'hybrid' => [ + 'semanticRatio' => 0.9, + 'embedder' => 'EMBEDDER_NAME' ] ]); search_parameter_reference_ranking_score_threshold_1: |- @@ -756,7 +763,7 @@ multi_search_federated_1: |- (new MultiSearchFederation()) ); search_parameter_reference_locales_1: |- - $client->index('INDEX_NAME')->search('進撃の巨人', [ + $client->index('INDEX_NAME')->search('QUERY TEXT IN JAPANESE', [ 'locales' => ['jpn'] ]); get_localized_attribute_settings_1: |- From fc17a622b2bcfa72317258e5f2e1040bd65c9c72 Mon Sep 17 00:00:00 2001 From: Bruno Casali Date: Mon, 28 Oct 2024 14:55:08 +0100 Subject: [PATCH 9/9] Force new meilisearch version on tests.yml --- .github/workflows/tests.yml | 2 +- docker-compose.yml | 2 +- phpunit.xml.dist.bak | 25 +++++++++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 phpunit.xml.dist.bak diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b3d04cde..afa864e5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -69,7 +69,7 @@ jobs: name: integration-tests (PHP ${{ matrix.php-version }}) (${{ matrix.http-client }}) services: meilisearch: - image: getmeili/meilisearch:latest + image: getmeili/meilisearch:v1.11.0 ports: - '7700:7700' env: diff --git a/docker-compose.yml b/docker-compose.yml index 97838e8a..2f74ff20 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,7 +14,7 @@ services: - ./:/home/package meilisearch: - image: getmeili/meilisearch:latest + image: getmeili/meilisearch:v1.10.0 ports: - "7700" environment: diff --git a/phpunit.xml.dist.bak b/phpunit.xml.dist.bak new file mode 100644 index 00000000..b9d5e31d --- /dev/null +++ b/phpunit.xml.dist.bak @@ -0,0 +1,25 @@ + + + + + ./tests + + + + + src/ + + + + + + +