From 5f2e0f9bc14b47aa820168a65844d0e0219664b5 Mon Sep 17 00:00:00 2001
From: Pavel Piligrimov
Date: Sun, 18 Dec 2022 23:17:21 +0500
Subject: [PATCH] =?UTF-8?q?=D0=BB=D0=BE=D0=B3=D0=B8=D0=BA=D0=B0=20=D0=BF?=
=?UTF-8?q?=D0=BE=D0=BB=D0=BD=D0=BE=D0=B9=20=D1=84=D0=B0=D1=81=D0=B5=D1=82?=
=?UTF-8?q?=D0=BD=D0=BE=D0=B9=20=D1=84=D0=B8=D0=BB=D1=8C=D1=82=D1=80=D0=B0?=
=?UTF-8?q?=D1=86=D0=B8=D0=B8,=20=D0=B1=D0=B0=D0=B7=D0=BE=D0=B2=D1=8B?=
=?UTF-8?q?=D0=B9=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20=D0=B4=D0=BB=D1=8F=20?=
=?UTF-8?q?=D0=B8=D0=BD=D0=B4=D0=B5=D0=BA=D1=81=D0=B0=D1=86=D0=B8=D0=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Document/ProductDocument.php | 5 +-
.../Domain/SearchResultFactory.php | 26 +++--
src/ElasticSearch/Domain/SearchService.php | 98 ++++++++++++-------
.../Indexer/BaseIndexProvider.php | 44 +++++++++
.../Search/Aggs/AggsNumberFacet.php | 10 +-
.../Search/Aggs/ExtremumTerms.php | 15 +--
src/ElasticSearch/Search/Request.php | 2 +-
7 files changed, 139 insertions(+), 61 deletions(-)
create mode 100644 src/ElasticSearch/Indexer/BaseIndexProvider.php
diff --git a/src/ElasticSearch/Document/ProductDocument.php b/src/ElasticSearch/Document/ProductDocument.php
index 6ae448a..d6071e8 100644
--- a/src/ElasticSearch/Document/ProductDocument.php
+++ b/src/ElasticSearch/Document/ProductDocument.php
@@ -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;
}
/**
@@ -60,6 +62,7 @@ class ProductDocument implements Document
'keyword_facet' => $this->getKeywordFacets()->es(),
'number_facet' => $this->getNumberFacets()->es()
],
+ 'data' => $this->info
];
if ($this->fullSearchContent) {
diff --git a/src/ElasticSearch/Domain/SearchResultFactory.php b/src/ElasticSearch/Domain/SearchResultFactory.php
index a9a132a..363abe4 100644
--- a/src/ElasticSearch/Domain/SearchResultFactory.php
+++ b/src/ElasticSearch/Domain/SearchResultFactory.php
@@ -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'];
@@ -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']
];
}
}
@@ -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
diff --git a/src/ElasticSearch/Domain/SearchService.php b/src/ElasticSearch/Domain/SearchService.php
index 277c171..ffa88f7 100644
--- a/src/ElasticSearch/Domain/SearchService.php
+++ b/src/ElasticSearch/Domain/SearchService.php
@@ -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,
@@ -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;
@@ -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) {
@@ -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);
@@ -80,7 +65,7 @@ final class SearchService implements DomainSearchService
new Pagination($q->pagination->limit, $q->pagination->page)
);
}
-
+
if ($q->sorting && !$q->sorting->isEmpty()) {
$oSortingCollection = new SortingCollection();
foreach ($q->sorting as $sorting) {
@@ -103,30 +88,57 @@ 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);
-
+
$request->getPostFilter()->filter($nestedFilter);
$aggsKeywordFiltered = new Aggs('keyword_facet_filtered');
$aggsKeywordFiltered->addAggs(AggsKeyWordFacet::create('all_keyword_facet_filtered', 'keyword_facet'))
->setQuery($commonFilter);
$request->getAggs()->add($aggsKeywordFiltered);
-
+
$aggsNumberFiltered = new Aggs('number_facet_filtered');
$aggsNumberFiltered->addAggs(AggsNumberFacet::create('all_number_facet_filtered', 'number_facet'))
->setQuery($commonFilter);
@@ -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;
+ }
}
diff --git a/src/ElasticSearch/Indexer/BaseIndexProvider.php b/src/ElasticSearch/Indexer/BaseIndexProvider.php
new file mode 100644
index 0000000..d8bafd1
--- /dev/null
+++ b/src/ElasticSearch/Indexer/BaseIndexProvider.php
@@ -0,0 +1,44 @@
+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
diff --git a/src/ElasticSearch/Search/Aggs/AggsNumberFacet.php b/src/ElasticSearch/Search/Aggs/AggsNumberFacet.php
index 2c67ab8..16d0b01 100644
--- a/src/ElasticSearch/Search/Aggs/AggsNumberFacet.php
+++ b/src/ElasticSearch/Search/Aggs/AggsNumberFacet.php
@@ -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);
diff --git a/src/ElasticSearch/Search/Aggs/ExtremumTerms.php b/src/ElasticSearch/Search/Aggs/ExtremumTerms.php
index 629ef18..9de2a5c 100644
--- a/src/ElasticSearch/Search/Aggs/ExtremumTerms.php
+++ b/src/ElasticSearch/Search/Aggs/ExtremumTerms.php
@@ -7,7 +7,6 @@ use IQDEV\ElasticSearch\Esable;
final class ExtremumTerms implements Esable
{
- private string $sOperation;
private string $field;
/**
@@ -18,18 +17,12 @@ final class ExtremumTerms implements Esable
$this->field = $field;
}
- public function setOperation($sOperation): self
- {
- $this->sOperation = $sOperation;
- return $this;
- }
-
public function es(): array
{
- $data = [
- 'field' => $this->field
+ return [
+ 'stats' => [
+ 'field' => $this->field,
+ ],
];
-
- return [$this->sOperation => $data];
}
}
\ No newline at end of file
diff --git a/src/ElasticSearch/Search/Request.php b/src/ElasticSearch/Search/Request.php
index 19d8e84..ab423a9 100644
--- a/src/ElasticSearch/Search/Request.php
+++ b/src/ElasticSearch/Search/Request.php
@@ -94,7 +94,7 @@ final class Request implements Esable
public function es(): array
{
$request = [
- '_source' => ['id']
+ '_source' => ['id', 'data.*']
];
if (isset($this->postFilter) && $this->postFilter->isEmpty() === false) {
--
GitLab