37 private $scoreBuilderFactory;
42 private $filterBuilder;
47 private $conditionManager;
52 private $indexProviders;
62 private $entityMetadata;
67 private $queryContainerFactory;
72 private $matchBuilder;
77 private $temporaryStorage;
82 private $relevanceCalculationMethod;
87 private $temporaryStorageFactory;
112 array $indexProviders,
113 $relevanceCalculationMethod =
'SUM' 115 $this->scoreBuilderFactory = $scoreBuilderFactory;
116 $this->filterBuilder = $filterBuilder;
117 $this->conditionManager = $conditionManager;
119 $this->entityMetadata = $entityMetadata;
120 $this->indexProviders = $indexProviders;
121 $this->queryContainerFactory = $queryContainerFactory;
122 $this->matchBuilder = $matchBuilder;
123 $this->temporaryStorage = $temporaryStorageFactory->
create();
124 $this->temporaryStorageFactory = $temporaryStorageFactory;
125 if (!in_array($relevanceCalculationMethod, [
'SUM',
'MAX'],
true)) {
126 throw new \LogicException(
'Unsupported relevance calculation method used. Only SUM and MAX are allowed');
128 $this->relevanceCalculationMethod = $relevanceCalculationMethod;
142 if (!array_key_exists(
$request->getIndex(), $this->indexProviders)) {
143 throw new \LogicException(
'Index provider not configured');
148 $queryContainer = $this->queryContainerFactory->create(
156 $scoreBuilder = $this->scoreBuilderFactory->create();
161 BoolQuery::QUERY_CONDITION_MUST,
165 $select = $this->addDerivedQueries(
187 private function createAroundSelect(Select
$select, ScoreBuilder $scoreBuilder)
189 $parentSelect = $this->getConnection()->select();
193 $this->entityMetadata->getEntityId() =>
'entity_id',
194 'relevance' => sprintf(
'%s(%s)', $this->relevanceCalculationMethod, $scoreBuilder->getScoreAlias()),
196 )->group($this->entityMetadata->getEntityId());
197 return $parentSelect;
211 protected function processQuery(
212 ScoreBuilder $scoreBuilder,
213 RequestQueryInterface
$query,
216 QueryContainer $queryContainer
218 switch (
$query->getType()) {
219 case RequestQueryInterface::TYPE_MATCH:
221 $select = $queryContainer->addMatchQuery(
227 case RequestQueryInterface::TYPE_BOOL:
231 case RequestQueryInterface::TYPE_FILTER:
233 $select = $this->processFilterQuery($scoreBuilder,
$query,
$select, $conditionType, $queryContainer);
236 throw new \InvalidArgumentException(sprintf(
'Unknown query type \'%s\'',
$query->getType()));
250 private function processBoolQuery(
251 ScoreBuilder $scoreBuilder,
254 QueryContainer $queryContainer
256 $scoreBuilder->startQuery();
258 $select = $this->processBoolQueryCondition(
262 BoolQuery::QUERY_CONDITION_MUST,
266 $select = $this->processBoolQueryCondition(
270 BoolQuery::QUERY_CONDITION_SHOULD,
274 $select = $this->processBoolQueryCondition(
278 BoolQuery::QUERY_CONDITION_NOT,
282 $scoreBuilder->endQuery(
$query->getBoost());
297 private function processBoolQueryCondition(
298 ScoreBuilder $scoreBuilder,
302 QueryContainer $queryContainer
304 foreach ($subQueryList as $subQuery) {
305 $select = $this->processQuery($scoreBuilder, $subQuery,
$select, $conditionType, $queryContainer);
320 private function processFilterQuery(
321 ScoreBuilder $scoreBuilder,
325 QueryContainer $queryContainer
327 $scoreBuilder->startQuery();
328 switch (
$query->getReferenceType()) {
329 case FilterQuery::REFERENCE_QUERY:
337 $scoreBuilder->endQuery(
$query->getBoost());
339 case FilterQuery::REFERENCE_FILTER:
340 $filterCondition = $this->filterBuilder->build(
$query->getReference(), $conditionType);
341 if ($filterCondition) {
342 $select->where($filterCondition);
346 $scoreBuilder->endQuery(
$query->getBoost());
361 private function addDerivedQueries(
363 QueryContainer $queryContainer,
364 ScoreBuilder $scoreBuilder,
368 $matchQueries = $queryContainer->getMatchQueries();
369 if (!$matchQueries) {
370 $select->columns($scoreBuilder->build());
373 $matchContainer = array_shift($matchQueries);
374 $this->matchBuilder->build(
377 $matchContainer->getRequest(),
378 $matchContainer->getConditionType()
380 $select->columns($scoreBuilder->build());
393 private function getConnection()
395 return $this->resource->getConnection();
407 private function addMatchQueries(
413 $queriesCount = count($matchQueries);
415 $table = $this->temporaryStorage->storeDocumentsFromSelect(
$select);
416 foreach ($matchQueries as $matchContainer) {
418 $matchScoreBuilder = $this->scoreBuilderFactory->create();
419 $matchSelect = $this->matchBuilder->build(
422 $matchContainer->getRequest(),
423 $matchContainer->getConditionType()
425 $select = $this->joinPreviousResultToSelect($matchSelect,
$table, $matchScoreBuilder);
427 $previousResultTable =
$table;
428 $table = $this->temporaryStorage->storeDocumentsFromSelect(
$select);
429 $this->getConnection()->dropTable($previousResultTable->getName());
445 private function joinPreviousResultToSelect(Select
$query, Table $previousResultTable, ScoreBuilder $scoreBuilder)
448 [
'previous_results' => $previousResultTable->getName()],
449 'previous_results.entity_id = search_index.entity_id',
452 $scoreBuilder->addCondition(
'previous_results.score',
false);
453 $query->columns($scoreBuilder->build());
455 $query = $this->createAroundSelect(
$query, $scoreBuilder);
__construct(ScoreBuilderFactory $scoreBuilderFactory, Builder $filterBuilder, ConditionManager $conditionManager, ResourceConnection $resource, EntityMetadata $entityMetadata, QueryContainerFactory $queryContainerFactory, Match $matchBuilder, TemporaryStorageFactory $temporaryStorageFactory, array $indexProviders, $relevanceCalculationMethod='SUM')