Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add facetSearch function to Indexes #550

Merged
merged 1 commit into from
Jul 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions src/Contracts/FacetSearchQuery.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

namespace Meilisearch\Contracts;

class FacetSearchQuery
{
private ?string $q = null;
private ?string $matchingStrategy = null;
private ?array $filter = null;
private ?string $facetQuery = null;
private ?string $facetName = null;

public function setQuery(string $q): FacetSearchQuery
{
$this->q = $q;

return $this;
}

public function setMatchingStrategy(string $matchingStrategy): FacetSearchQuery
{
$this->matchingStrategy = $matchingStrategy;

return $this;
}

public function setFilter(array $filter): FacetSearchQuery
{
$this->filter = $filter;

return $this;
}

public function setFacetQuery(string $facetQuery): FacetSearchQuery
{
$this->facetQuery = $facetQuery;

return $this;
}

public function setFacetName(string $facetName): FacetSearchQuery
{
$this->facetName = $facetName;

return $this;
}

public function toArray(): array
{
return array_filter([
'q' => $this->q,
'matchingStrategy' => $this->matchingStrategy,
'filter' => $this->filter,
'facetQuery' => $this->facetQuery,
'facetName' => $this->facetName,
], function ($item) { return null !== $item; });
}
}
11 changes: 11 additions & 0 deletions src/Endpoints/Indexes.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Meilisearch\Endpoints;

use Meilisearch\Contracts\Endpoint;
use Meilisearch\Contracts\FacetSearchQuery;
use Meilisearch\Contracts\Http;
use Meilisearch\Contracts\Index\Settings;
use Meilisearch\Contracts\IndexesQuery;
Expand All @@ -15,6 +16,7 @@
use Meilisearch\Endpoints\Delegates\HandlesSettings;
use Meilisearch\Endpoints\Delegates\HandlesTasks;
use Meilisearch\Exceptions\ApiException;
use Meilisearch\Search\FacetSearchResult;
use Meilisearch\Search\SearchResult;

class Indexes extends Endpoint
Expand Down Expand Up @@ -211,6 +213,15 @@ public function rawSearch(?string $query, array $searchParams = []): array
return $result;
}

// Facet Search

public function facetSearch(FacetSearchQuery $params): FacetSearchResult
{
$response = $this->http->post(self::PATH.'/'.$this->uid.'/facet-search', $params->toArray());

return new FacetSearchResult($response);
}

// Stats

public function stats(): array
Expand Down
59 changes: 59 additions & 0 deletions src/Search/FacetSearchResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

declare(strict_types=1);

namespace Meilisearch\Search;

class FacetSearchResult implements \Countable, \IteratorAggregate
{
/**
* @var array<int, array<string, mixed>>
*/
private array $facetHits;
private int $processingTimeMs;
private ?string $facetQuery;

public function __construct(array $body)
{
$this->facetHits = $body['facetHits'] ?? [];
$this->facetQuery = $body['facetQuery'];
$this->processingTimeMs = $body['processingTimeMs'];
}

/**
* @return array<int, array>
*/
public function getFacetHits(): array
{
return $this->facetHits;
}

public function getProcessingTimeMs(): int
{
return $this->processingTimeMs;
}

public function toArray(): array
{
return [
'facetHits' => $this->facetHits,
'facetQuery' => $this->facetQuery,
'processingTimeMs' => $this->processingTimeMs,
];
}

public function toJSON(): string
{
return json_encode($this->toArray(), JSON_PRETTY_PRINT);
}

public function getIterator(): \ArrayIterator
{
return new \ArrayIterator($this->facetHits);
}

public function count(): int
{
return \count($this->facetHits);
}
}
42 changes: 42 additions & 0 deletions tests/Endpoints/FacetSearchTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace Tests\Endpoints;

use Meilisearch\Contracts\FacetSearchQuery;
use Meilisearch\Endpoints\Indexes;
use Tests\TestCase;

final class FacetSearchTest extends TestCase
{
private Indexes $index;

protected function setUp(): void
{
parent::setUp();

$this->index = $this->createEmptyIndex($this->safeIndexName());
$this->index->updateDocuments(self::DOCUMENTS);
$promise = $this->index->updateFilterableAttributes(['genre']);
$this->index->waitForTask($promise['taskUid']);
}

public function testBasicSearchWithFilters(): void
{
$response = $this->index->search('prince', ['facets' => ['genre']]);

$this->assertSame(array_keys($response->getFacetDistribution()['genre']), [
'adventure', 'fantasy',
]);

$response = $this->index->facetSearch(
(new FacetSearchQuery())
->setFacetQuery('fa')
->setFacetName('genre')
->setQuery('prince')
);

$this->assertSame(array_column($response->getFacetHits(), 'value'), ['fantasy']);
}
}