Loading src/ElasticSearch/Document/ProductDocument.php +4 −1 Original line number Diff line number Diff line Loading @@ -10,14 +10,16 @@ class ProductDocument implements Document private FacetCollection $keywordFacets; private FacetCollection $numberFacets; private ?string $fullSearchContent = null; private array $info; private FacetCategory $categoryFacet; public function __construct(FacetCategory $categoryFacet) public function __construct(FacetCategory $categoryFacet, array $info = []) { $this->keywordFacets = new FacetCollection(); $this->numberFacets = new FacetCollection(); $this->categoryFacet = $categoryFacet; $this->info = $info; } /** Loading Loading @@ -60,6 +62,7 @@ class ProductDocument implements Document 'keyword_facet' => $this->getKeywordFacets()->es(), 'number_facet' => $this->getNumberFacets()->es() ], 'data' => $this->info ]; if ($this->fullSearchContent) { Loading src/ElasticSearch/Domain/SearchResultFactory.php +20 −6 Original line number Diff line number Diff line Loading @@ -49,6 +49,20 @@ final class SearchResultFactory } } foreach ($buckets as $bucket) { $code = $bucket['key']; if (isset($data['aggregations']["keyword_facet_$code"]['agg_special']['agg_keyword_facet_code']['buckets'])) { $bucketsFiltered[$code] = []; foreach ($data['aggregations']["keyword_facet_$code"]['agg_special']['agg_keyword_facet_code']['buckets'] as $filtredBucket) { foreach ($filtredBucket['agg_keyword_facet_value']['buckets'] as $values) { if ($filtredBucket['key'] === $code) { $bucketsFiltered[$code][$values['key']] = $values; } } } } } foreach ($buckets as $bucket) { $code = $bucket['key']; $valueBucket = $bucket['agg_keyword_facet_value']['buckets']; Loading @@ -74,8 +88,8 @@ final class SearchResultFactory foreach ($data['aggregations']['number_facet_filtered']['all_number_facet_filtered']['agg_number_facet_code']['buckets'] as $bucket) { $bucketsFiltered[$bucket['key']] = [ 'data' => $bucket, 'min' => $bucket['agg_number_facet_min_value'], 'max' => $bucket['agg_number_facet_max_value'] 'min' => $bucket['agg_number_facet_value']['min'], 'max' => $bucket['agg_number_facet_value']['max'] ]; } } Loading @@ -88,13 +102,13 @@ final class SearchResultFactory $selectedMin = $selectedMax = null; if (isset($bucketsFiltered[$code])) { $count = $bucketsFiltered[$code]['data']['doc_count']; $selectedMin = $bucketsFiltered[$code]['min']['value']; $selectedMax = $bucketsFiltered[$code]['max']['value']; $selectedMin = $bucketsFiltered[$code]['min']; $selectedMax = $bucketsFiltered[$code]['max']; } $facet->items->add(FacetItemRange::createFromRange( $bucket['agg_number_facet_min_value']['value'], $bucket['agg_number_facet_max_value']['value'], $bucket['agg_number_facet_value']['min'], $bucket['agg_number_facet_value']['max'], $count, $selectedMin, $selectedMax Loading src/ElasticSearch/Domain/SearchService.php +65 −33 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ use IQDEV\ElasticSearch\Search\Pagination; use IQDEV\ElasticSearch\Search\Request; use Elastic\Elasticsearch\Client; use IQDEV\Search\{Filter\Filter, Filter\FilterCollection, Filter\FilterKeyword, Filter\FilterCategory, Filter\FilterNumber, Loading @@ -22,8 +23,7 @@ use IQDEV\Search\{Filter\Filter, SearchService as DomainSearchService, Sorting\SortingFieldPair as DSortingFieldPair, Sorting\SortingPropertyKeywordPair as DSortingPropertyKeywordPair, Sorting\SortingPropertyNumberPair as DSortingPropertyNumberPair }; Sorting\SortingPropertyNumberPair as DSortingPropertyNumberPair}; use IQDEV\ElasticSearch\Search\Sorting\SortingCollection; use IQDEV\ElasticSearch\Search\Sorting\SortingFieldsPair; use IQDEV\ElasticSearch\Search\Sorting\SortingPropertyKeywordPair; Loading @@ -44,8 +44,6 @@ final class SearchService implements DomainSearchService { $request = new Request(); $commonQuery = new Query(); $filterKeyword = new Query(); $filterNumber = new Query(); if ($q->filters) { foreach ($q->filters as $filter) { Loading @@ -54,23 +52,10 @@ final class SearchService implements DomainSearchService $request->getQuery()->must( (new Terms('category_id', $filter->value)) ); continue; } if ($filter instanceof FilterNumber) { $oFacet = new FilterNumberFacet($filter->key, $filter->min, $filter->max); $filterNumber->filter($oFacet); $commonQuery->filter($oFacet); continue; } if ($filter instanceof FilterKeyword) { $oFacet = new FilterKeywordFacet($filter->key, $filter->value); $filterKeyword->filter($oFacet); $commonQuery->filter($oFacet); continue; break; } } $commonQuery = $this->getQuery($q->filters); } $commonFilter = clone $commonQuery; $commonFilter->setType(Query::TYPE_FILTER); Loading Loading @@ -103,19 +88,46 @@ final class SearchService implements DomainSearchService $request->addMatch('full_search_content', ['query' => $q->query]); } if ($filterKeyword->isEmpty() === false) { $nestedFilterKeyword = new Nested(); $nestedFilterKeyword->setPath('search_data') ->setQuery($filterKeyword); $getKey = static fn (string $type, string $name): string => sprintf('%s_facet_%s', $type, $name); if ($commonQuery->isEmpty() === false) { foreach ($q->filters as $filter) { /** @var Filter $filter */ if ($filter instanceof FilterCategory || $filter instanceof FilterNumber) { continue; } if ($filterNumber->isEmpty() === false) { $nestedFilterNumber = new Nested(); $nestedFilterNumber->setPath('search_data') ->setQuery($filterNumber); $oFilters = new FilterCollection(); if ($filter instanceof FilterKeyword) { foreach ($q->filters as $filter2) { if (!($filter2 instanceof Filter) || $filter2 instanceof FilterCategory) { continue; } if ($filter->key() === $filter2->key()) { continue; } $oFilters->add($filter2); } } $aggsFiltered = new Aggs($getKey('keyword', $filter->key())); $aggsFiltered->addAggs( AggsKeyWordFacet::create( 'agg_special', 'keyword_facet' ) ); if (false === $oFilters->isEmpty()) { $aggsFiltered->setQuery($this->getQuery($oFilters)); } else { $aggsFiltered->setNested((new Nested())->setPath('search_data')); } $request->getAggs()->add($aggsFiltered); } if ($commonQuery->isEmpty() === false) { $nestedFilter = new Nested(); $nestedFilter->setPath('search_data') ->setQuery($commonQuery); Loading Loading @@ -148,4 +160,24 @@ final class SearchService implements DomainSearchService return SearchResultFactory::createFromResponse($response, $request); } private function getQuery(FilterCollection $filters): Query { $commonQuery = new Query(); foreach ($filters as $filter) { if ($filter instanceof FilterNumber) { $oFacet = new FilterNumberFacet($filter->key, $filter->min, $filter->max); $commonQuery->filter($oFacet); continue; } if ($filter instanceof FilterKeyword) { $oFacet = new FilterKeywordFacet($filter->key, $filter->value); $commonQuery->filter($oFacet); continue; } } return $commonQuery; } } src/ElasticSearch/Indexer/BaseIndexProvider.php 0 → 100644 +44 −0 Original line number Diff line number Diff line <?php namespace IQDEV\ElasticSearch\Indexer; use IQDEV\ElasticSearch\Configuration; use IQDEV\ElasticSearch\Document\ProductDocument; use IQDEV\ElasticSearch\Facet\FacetCategory; use IQDEV\ElasticSearch\Facet\FacetKeyword; use IQDEV\ElasticSearch\Facet\FacetNumber; class BaseIndexProvider implements IndexProvider { private array $products; private Configuration $configuration; public function __construct($products, $configuration) { $this->configuration = $configuration; $this->products = $products; } public function get(): \Generator { foreach ($this->products as $product) { $document = new ProductDocument(new FacetCategory($product['category']), $product['data'] ?? []); foreach ($product['properties'] as $type => $values) { foreach ($values as $key => $prop) { if ($type === 'number') { $document->getNumberFacets()->add(new FacetNumber($key, $prop)); } else { $document->getKeywordFacets()->add(new FacetKeyword($key, $prop)); } } } $document->setFullSearchContent($product['name']); yield new Index( $this->configuration->getIndexName(), $document, $product['id'] ); } } } No newline at end of file src/ElasticSearch/Search/Aggs/AggsNumberFacet.php +1 −9 Original line number Diff line number Diff line Loading @@ -18,17 +18,9 @@ final class AggsNumberFacet (new Terms("{$path}.{$facet}.facet_code")) ); $aggFacetValue = new Aggs("agg_{$facet}_min_value"); $aggFacetValue = new Aggs("agg_{$facet}_value"); $aggFacetValue->setExtremumTerms( (new ExtremumTerms("{$path}.{$facet}.facet_value")) ->setOperation('min') ); $aggFacetCode->addAggs($aggFacetValue); $aggFacetValue = new Aggs("agg_{$facet}_max_value"); $aggFacetValue->setExtremumTerms( (new ExtremumTerms("{$path}.{$facet}.facet_value")) ->setOperation('max') ); $aggFacetCode->addAggs($aggFacetValue); Loading Loading
src/ElasticSearch/Document/ProductDocument.php +4 −1 Original line number Diff line number Diff line Loading @@ -10,14 +10,16 @@ class ProductDocument implements Document private FacetCollection $keywordFacets; private FacetCollection $numberFacets; private ?string $fullSearchContent = null; private array $info; private FacetCategory $categoryFacet; public function __construct(FacetCategory $categoryFacet) public function __construct(FacetCategory $categoryFacet, array $info = []) { $this->keywordFacets = new FacetCollection(); $this->numberFacets = new FacetCollection(); $this->categoryFacet = $categoryFacet; $this->info = $info; } /** Loading Loading @@ -60,6 +62,7 @@ class ProductDocument implements Document 'keyword_facet' => $this->getKeywordFacets()->es(), 'number_facet' => $this->getNumberFacets()->es() ], 'data' => $this->info ]; if ($this->fullSearchContent) { Loading
src/ElasticSearch/Domain/SearchResultFactory.php +20 −6 Original line number Diff line number Diff line Loading @@ -49,6 +49,20 @@ final class SearchResultFactory } } foreach ($buckets as $bucket) { $code = $bucket['key']; if (isset($data['aggregations']["keyword_facet_$code"]['agg_special']['agg_keyword_facet_code']['buckets'])) { $bucketsFiltered[$code] = []; foreach ($data['aggregations']["keyword_facet_$code"]['agg_special']['agg_keyword_facet_code']['buckets'] as $filtredBucket) { foreach ($filtredBucket['agg_keyword_facet_value']['buckets'] as $values) { if ($filtredBucket['key'] === $code) { $bucketsFiltered[$code][$values['key']] = $values; } } } } } foreach ($buckets as $bucket) { $code = $bucket['key']; $valueBucket = $bucket['agg_keyword_facet_value']['buckets']; Loading @@ -74,8 +88,8 @@ final class SearchResultFactory foreach ($data['aggregations']['number_facet_filtered']['all_number_facet_filtered']['agg_number_facet_code']['buckets'] as $bucket) { $bucketsFiltered[$bucket['key']] = [ 'data' => $bucket, 'min' => $bucket['agg_number_facet_min_value'], 'max' => $bucket['agg_number_facet_max_value'] 'min' => $bucket['agg_number_facet_value']['min'], 'max' => $bucket['agg_number_facet_value']['max'] ]; } } Loading @@ -88,13 +102,13 @@ final class SearchResultFactory $selectedMin = $selectedMax = null; if (isset($bucketsFiltered[$code])) { $count = $bucketsFiltered[$code]['data']['doc_count']; $selectedMin = $bucketsFiltered[$code]['min']['value']; $selectedMax = $bucketsFiltered[$code]['max']['value']; $selectedMin = $bucketsFiltered[$code]['min']; $selectedMax = $bucketsFiltered[$code]['max']; } $facet->items->add(FacetItemRange::createFromRange( $bucket['agg_number_facet_min_value']['value'], $bucket['agg_number_facet_max_value']['value'], $bucket['agg_number_facet_value']['min'], $bucket['agg_number_facet_value']['max'], $count, $selectedMin, $selectedMax Loading
src/ElasticSearch/Domain/SearchService.php +65 −33 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ use IQDEV\ElasticSearch\Search\Pagination; use IQDEV\ElasticSearch\Search\Request; use Elastic\Elasticsearch\Client; use IQDEV\Search\{Filter\Filter, Filter\FilterCollection, Filter\FilterKeyword, Filter\FilterCategory, Filter\FilterNumber, Loading @@ -22,8 +23,7 @@ use IQDEV\Search\{Filter\Filter, SearchService as DomainSearchService, Sorting\SortingFieldPair as DSortingFieldPair, Sorting\SortingPropertyKeywordPair as DSortingPropertyKeywordPair, Sorting\SortingPropertyNumberPair as DSortingPropertyNumberPair }; Sorting\SortingPropertyNumberPair as DSortingPropertyNumberPair}; use IQDEV\ElasticSearch\Search\Sorting\SortingCollection; use IQDEV\ElasticSearch\Search\Sorting\SortingFieldsPair; use IQDEV\ElasticSearch\Search\Sorting\SortingPropertyKeywordPair; Loading @@ -44,8 +44,6 @@ final class SearchService implements DomainSearchService { $request = new Request(); $commonQuery = new Query(); $filterKeyword = new Query(); $filterNumber = new Query(); if ($q->filters) { foreach ($q->filters as $filter) { Loading @@ -54,23 +52,10 @@ final class SearchService implements DomainSearchService $request->getQuery()->must( (new Terms('category_id', $filter->value)) ); continue; } if ($filter instanceof FilterNumber) { $oFacet = new FilterNumberFacet($filter->key, $filter->min, $filter->max); $filterNumber->filter($oFacet); $commonQuery->filter($oFacet); continue; } if ($filter instanceof FilterKeyword) { $oFacet = new FilterKeywordFacet($filter->key, $filter->value); $filterKeyword->filter($oFacet); $commonQuery->filter($oFacet); continue; break; } } $commonQuery = $this->getQuery($q->filters); } $commonFilter = clone $commonQuery; $commonFilter->setType(Query::TYPE_FILTER); Loading Loading @@ -103,19 +88,46 @@ final class SearchService implements DomainSearchService $request->addMatch('full_search_content', ['query' => $q->query]); } if ($filterKeyword->isEmpty() === false) { $nestedFilterKeyword = new Nested(); $nestedFilterKeyword->setPath('search_data') ->setQuery($filterKeyword); $getKey = static fn (string $type, string $name): string => sprintf('%s_facet_%s', $type, $name); if ($commonQuery->isEmpty() === false) { foreach ($q->filters as $filter) { /** @var Filter $filter */ if ($filter instanceof FilterCategory || $filter instanceof FilterNumber) { continue; } if ($filterNumber->isEmpty() === false) { $nestedFilterNumber = new Nested(); $nestedFilterNumber->setPath('search_data') ->setQuery($filterNumber); $oFilters = new FilterCollection(); if ($filter instanceof FilterKeyword) { foreach ($q->filters as $filter2) { if (!($filter2 instanceof Filter) || $filter2 instanceof FilterCategory) { continue; } if ($filter->key() === $filter2->key()) { continue; } $oFilters->add($filter2); } } $aggsFiltered = new Aggs($getKey('keyword', $filter->key())); $aggsFiltered->addAggs( AggsKeyWordFacet::create( 'agg_special', 'keyword_facet' ) ); if (false === $oFilters->isEmpty()) { $aggsFiltered->setQuery($this->getQuery($oFilters)); } else { $aggsFiltered->setNested((new Nested())->setPath('search_data')); } $request->getAggs()->add($aggsFiltered); } if ($commonQuery->isEmpty() === false) { $nestedFilter = new Nested(); $nestedFilter->setPath('search_data') ->setQuery($commonQuery); Loading Loading @@ -148,4 +160,24 @@ final class SearchService implements DomainSearchService return SearchResultFactory::createFromResponse($response, $request); } private function getQuery(FilterCollection $filters): Query { $commonQuery = new Query(); foreach ($filters as $filter) { if ($filter instanceof FilterNumber) { $oFacet = new FilterNumberFacet($filter->key, $filter->min, $filter->max); $commonQuery->filter($oFacet); continue; } if ($filter instanceof FilterKeyword) { $oFacet = new FilterKeywordFacet($filter->key, $filter->value); $commonQuery->filter($oFacet); continue; } } return $commonQuery; } }
src/ElasticSearch/Indexer/BaseIndexProvider.php 0 → 100644 +44 −0 Original line number Diff line number Diff line <?php namespace IQDEV\ElasticSearch\Indexer; use IQDEV\ElasticSearch\Configuration; use IQDEV\ElasticSearch\Document\ProductDocument; use IQDEV\ElasticSearch\Facet\FacetCategory; use IQDEV\ElasticSearch\Facet\FacetKeyword; use IQDEV\ElasticSearch\Facet\FacetNumber; class BaseIndexProvider implements IndexProvider { private array $products; private Configuration $configuration; public function __construct($products, $configuration) { $this->configuration = $configuration; $this->products = $products; } public function get(): \Generator { foreach ($this->products as $product) { $document = new ProductDocument(new FacetCategory($product['category']), $product['data'] ?? []); foreach ($product['properties'] as $type => $values) { foreach ($values as $key => $prop) { if ($type === 'number') { $document->getNumberFacets()->add(new FacetNumber($key, $prop)); } else { $document->getKeywordFacets()->add(new FacetKeyword($key, $prop)); } } } $document->setFullSearchContent($product['name']); yield new Index( $this->configuration->getIndexName(), $document, $product['id'] ); } } } No newline at end of file
src/ElasticSearch/Search/Aggs/AggsNumberFacet.php +1 −9 Original line number Diff line number Diff line Loading @@ -18,17 +18,9 @@ final class AggsNumberFacet (new Terms("{$path}.{$facet}.facet_code")) ); $aggFacetValue = new Aggs("agg_{$facet}_min_value"); $aggFacetValue = new Aggs("agg_{$facet}_value"); $aggFacetValue->setExtremumTerms( (new ExtremumTerms("{$path}.{$facet}.facet_value")) ->setOperation('min') ); $aggFacetCode->addAggs($aggFacetValue); $aggFacetValue = new Aggs("agg_{$facet}_max_value"); $aggFacetValue->setExtremumTerms( (new ExtremumTerms("{$path}.{$facet}.facet_value")) ->setOperation('max') ); $aggFacetCode->addAggs($aggFacetValue); Loading