diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml
index 35697bcf..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: |-
@@ -742,7 +749,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([
@@ -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: |-
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/
+
+
+
+
+
+
+
diff --git a/src/Contracts/MultiSearchFederation.php b/src/Contracts/MultiSearchFederation.php
index 3f9db1ec..d998aa37 100644
--- a/src/Contracts/MultiSearchFederation.php
+++ b/src/Contracts/MultiSearchFederation.php
@@ -16,6 +16,16 @@ class MultiSearchFederation
*/
private ?int $offset = null;
+ /**
+ * @var array>|null
+ */
+ private ?array $facetsByIndex = null;
+
+ /**
+ * @var array{maxValuesPerFacet: positive-int}|null
+ */
+ private ?array $mergeFacets = null;
+
/**
* @param non-negative-int $limit
*
@@ -40,10 +50,36 @@ public function setOffset(int $offset): self
return $this;
}
+ /**
+ * @param array> $facetsByIndex
+ *
+ * @return $this
+ */
+ public function setFacetsByIndex(array $facetsByIndex): self
+ {
+ $this->facetsByIndex = $facetsByIndex;
+
+ return $this;
+ }
+
+ /**
+ * @param array{maxValuesPerFacet: positive-int} $mergeFacets
+ *
+ * @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{maxValuesPerFacet: positive-int},
* }
*/
public function toArray(): array
@@ -51,6 +87,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/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/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/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/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']);
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));
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));
diff --git a/tests/Settings/EmbeddersTest.php b/tests/Settings/EmbeddersTest.php
new file mode 100644
index 00000000..35497559
--- /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);
+ }
+}