-
Notifications
You must be signed in to change notification settings - Fork 32
Add multi search #288
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
base: main
Are you sure you want to change the base?
Add multi search #288
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,240 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Meilisearch\Bundle\Contracts; | ||
|
||
use Meilisearch\Contracts\SearchQuery as EngineQuery; | ||
|
||
class SearchQuery | ||
{ | ||
/** | ||
* @var class-string | ||
*/ | ||
private string $className; | ||
private ?string $q = null; | ||
private ?array $filter = null; | ||
private ?array $attributesToRetrieve = null; | ||
private ?array $attributesToCrop = null; | ||
private ?int $cropLength; | ||
private ?array $attributesToHighlight = null; | ||
private ?string $cropMarker = null; | ||
private ?string $highlightPreTag = null; | ||
private ?string $highlightPostTag = null; | ||
private ?array $facets = null; | ||
private ?bool $showMatchesPosition = null; | ||
private ?array $sort = null; | ||
private ?string $matchingStrategy = null; | ||
private ?int $offset = null; | ||
private ?int $limit = null; | ||
private ?int $hitsPerPage = null; | ||
private ?int $page = null; | ||
private ?array $vector = null; | ||
private ?array $attributesToSearchOn = null; | ||
private ?bool $showRankingScore = null; | ||
private ?bool $showRankingScoreDetails = null; | ||
|
||
/** | ||
* @param class-string $className | ||
*/ | ||
public function __construct(string $className) | ||
{ | ||
$this->className = $className; | ||
} | ||
|
||
/** | ||
* @return class-string | ||
*/ | ||
public function getClassName(): string | ||
{ | ||
return $this->className; | ||
} | ||
|
||
public function setQuery(string $q): SearchQuery | ||
{ | ||
$this->q = $q; | ||
|
||
return $this; | ||
} | ||
|
||
public function getQuery(): ?string | ||
{ | ||
return $this->q; | ||
} | ||
|
||
public function setFilter(array $filter): SearchQuery | ||
{ | ||
$this->filter = $filter; | ||
|
||
return $this; | ||
} | ||
|
||
public function getFilter(): ?array | ||
{ | ||
return $this->filter; | ||
} | ||
|
||
public function setAttributesToRetrieve(array $attributesToRetrieve): SearchQuery | ||
{ | ||
$this->attributesToRetrieve = $attributesToRetrieve; | ||
|
||
return $this; | ||
} | ||
|
||
public function setAttributesToCrop(array $attributesToCrop): SearchQuery | ||
{ | ||
$this->attributesToCrop = $attributesToCrop; | ||
|
||
return $this; | ||
} | ||
|
||
public function setCropLength(?int $cropLength): SearchQuery | ||
{ | ||
$this->cropLength = $cropLength; | ||
|
||
return $this; | ||
} | ||
|
||
public function setAttributesToHighlight(array $attributesToHighlight): SearchQuery | ||
{ | ||
$this->attributesToHighlight = $attributesToHighlight; | ||
|
||
return $this; | ||
} | ||
|
||
public function setCropMarker(string $cropMarker): SearchQuery | ||
{ | ||
$this->cropMarker = $cropMarker; | ||
|
||
return $this; | ||
} | ||
|
||
public function setHighlightPreTag(string $highlightPreTag): SearchQuery | ||
{ | ||
$this->highlightPreTag = $highlightPreTag; | ||
|
||
return $this; | ||
} | ||
|
||
public function setHighlightPostTag(string $highlightPostTag): SearchQuery | ||
{ | ||
$this->highlightPostTag = $highlightPostTag; | ||
|
||
return $this; | ||
} | ||
|
||
public function setFacets(array $facets): SearchQuery | ||
{ | ||
$this->facets = $facets; | ||
|
||
return $this; | ||
} | ||
|
||
public function setShowMatchesPosition(?bool $showMatchesPosition): SearchQuery | ||
{ | ||
$this->showMatchesPosition = $showMatchesPosition; | ||
|
||
return $this; | ||
} | ||
|
||
public function setShowRankingScore(?bool $showRankingScore): SearchQuery | ||
{ | ||
$this->showRankingScore = $showRankingScore; | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @param bool $showRankingScoreDetails whether the feature is enabled or not | ||
*/ | ||
public function setShowRankingScoreDetails(?bool $showRankingScoreDetails): SearchQuery | ||
{ | ||
$this->showRankingScoreDetails = $showRankingScoreDetails; | ||
|
||
return $this; | ||
} | ||
|
||
public function setSort(array $sort): SearchQuery | ||
{ | ||
$this->sort = $sort; | ||
|
||
return $this; | ||
} | ||
|
||
public function setMatchingStrategy(string $matchingStrategy): SearchQuery | ||
{ | ||
$this->matchingStrategy = $matchingStrategy; | ||
|
||
return $this; | ||
} | ||
|
||
public function setOffset(?int $offset): SearchQuery | ||
{ | ||
$this->offset = $offset; | ||
|
||
return $this; | ||
} | ||
|
||
public function setLimit(?int $limit): SearchQuery | ||
{ | ||
$this->limit = $limit; | ||
|
||
return $this; | ||
} | ||
|
||
public function setHitsPerPage(?int $hitsPerPage): SearchQuery | ||
{ | ||
$this->hitsPerPage = $hitsPerPage; | ||
|
||
return $this; | ||
} | ||
|
||
public function setPage(?int $page): SearchQuery | ||
{ | ||
$this->page = $page; | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @param list<float|list<float>> $vector a multi-level array floats | ||
*/ | ||
public function setVector(array $vector): SearchQuery | ||
{ | ||
$this->vector = $vector; | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @param list<non-empty-string> $attributesToSearchOn | ||
*/ | ||
public function setAttributesToSearchOn(array $attributesToSearchOn): SearchQuery | ||
{ | ||
$this->attributesToSearchOn = $attributesToSearchOn; | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @internal | ||
*/ | ||
public function toEngineQuery(string $prefix, array $indices): EngineQuery | ||
{ | ||
$query = new EngineQuery(); | ||
foreach ($indices as $indice) { | ||
if ($indice['class'] === $this->className) { | ||
$query->setIndexUid("$prefix{$indice['name']}"); | ||
|
||
break; | ||
} | ||
} | ||
if (null !== $this->q) { | ||
$query->setQuery($this->q); | ||
} | ||
|
||
// @todo: set all data | ||
|
||
return $query; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -7,6 +7,7 @@ | |||||||||||
use Doctrine\Common\Util\ClassUtils; | ||||||||||||
use Doctrine\Persistence\ObjectManager; | ||||||||||||
use Meilisearch\Bundle\Collection; | ||||||||||||
use Meilisearch\Bundle\Contracts\SearchQuery; | ||||||||||||
use Meilisearch\Bundle\Engine; | ||||||||||||
use Meilisearch\Bundle\Entity\Aggregator; | ||||||||||||
use Meilisearch\Bundle\Exception\ObjectIdNotFoundException; | ||||||||||||
|
@@ -188,6 +189,42 @@ public function search( | |||||||||||
return $results; | ||||||||||||
} | ||||||||||||
|
||||||||||||
public function multiSearch(ObjectManager $objectManager, array $queries): array | ||||||||||||
{ | ||||||||||||
$prefix = $this->configuration->get('prefix'); | ||||||||||||
$indices = $this->configuration->get('indices'); | ||||||||||||
|
||||||||||||
// $response = $this->engine->multiSearch(array_map(function (SearchQuery $query) use ($prefix, $indices) { | ||||||||||||
// $this->assertIsSearchable($query->getClassName()); | ||||||||||||
// | ||||||||||||
// return $query->toEngineQuery($prefix, $indices); | ||||||||||||
// }, $queries)); | ||||||||||||
Comment on lines
+197
to
+201
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
$response = $this->engine->multiSearch(array_map(static fn (SearchQuery $query) => $query->toEngineQuery($prefix, $indices), $queries)); | ||||||||||||
$results = []; | ||||||||||||
|
||||||||||||
foreach ($response['results'] as $indexResponse) { | ||||||||||||
$indexResults = []; | ||||||||||||
$className = $this->getClassNameFromIndex($indexResponse['indexUid']); | ||||||||||||
|
||||||||||||
foreach ($indexResponse['hits'] as $hit) { | ||||||||||||
if (!isset($hit[self::RESULT_KEY_OBJECTID])) { | ||||||||||||
throw new ObjectIdNotFoundException(sprintf('There is no "%s" key in the multi search "%s" result.', self::RESULT_KEY_OBJECTID, $indexResponse['indexUid'])); | ||||||||||||
} | ||||||||||||
|
||||||||||||
$repo = $objectManager->getRepository($className); | ||||||||||||
$entity = $repo->find($hit['objectID']); | ||||||||||||
|
||||||||||||
if (null !== $entity) { | ||||||||||||
$indexResults[] = $entity; | ||||||||||||
} | ||||||||||||
} | ||||||||||||
|
||||||||||||
$results[$className] = $indexResults; | ||||||||||||
} | ||||||||||||
|
||||||||||||
return $results; | ||||||||||||
} | ||||||||||||
|
||||||||||||
public function rawSearch( | ||||||||||||
string $className, | ||||||||||||
string $query = '', | ||||||||||||
|
@@ -346,4 +383,20 @@ private function assertIsSearchable(string $className): void | |||||||||||
throw new Exception('Class '.$className.' is not searchable.'); | ||||||||||||
} | ||||||||||||
} | ||||||||||||
|
||||||||||||
/** | ||||||||||||
* @return class-string | ||||||||||||
*/ | ||||||||||||
private function getClassNameFromIndex(string $index): string | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems to be a common thing in the bundle, no? I'm wondering if this could be reused somewhere else. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, but I'd leave that for later :) |
||||||||||||
{ | ||||||||||||
$prefix = $this->configuration->get('prefix'); | ||||||||||||
|
||||||||||||
foreach ($this->configuration->get('indices') as $indice) { | ||||||||||||
if ("$prefix{$indice['name']}" === $index) { | ||||||||||||
return $indice['class']; | ||||||||||||
} | ||||||||||||
} | ||||||||||||
|
||||||||||||
throw new Exception(sprintf('Cannot find searchable class for "%s" index.', $index)); | ||||||||||||
} | ||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👀