Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
No results found
Show changes
Commits on Source (9)
Showing
with 201 additions and 693 deletions
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
], ],
"require": { "require": {
"php": ">=8.1", "php": ">=8.1",
"ramsey/collection": "^1.2", "ramsey/collection": "^2",
"elasticsearch/elasticsearch": "^8.5", "elasticsearch/elasticsearch": "^8.5",
"vlucas/phpdotenv": "^5.4.1" "vlucas/phpdotenv": "^5.4.1"
}, },
......
...@@ -3,23 +3,17 @@ ...@@ -3,23 +3,17 @@
namespace IQDEV\ElasticSearch\Config; namespace IQDEV\ElasticSearch\Config;
use IQDEV\ElasticSearch\Configuration; use IQDEV\ElasticSearch\Configuration;
use IQDEV\ElasticSearch\Mapping;
class BaseConfiguration implements Configuration class BaseConfiguration implements Configuration
{ {
public function __construct(
private readonly Mapping $mapping,
) {
}
public function getIndexName(): string public function getIndexName(): string
{ {
return $_ENV['IQ_ES_PRODUCT_SEARCH_INDEX']; return $_ENV['IQ_ES_PRODUCT_SEARCH_INDEX'];
} }
public function getMapping(): Mapping public function getMapping(): array
{ {
return $this->mapping; return include __DIR__.'/product.mappings.php';
} }
public function getSettings(): array public function getSettings(): array
......
<?php
declare(strict_types=1);
namespace IQDEV\ElasticSearch\Config\Mapping;
use IQDEV\ElasticSearch\Mapping;
class ProductMapping extends Mapping
{
public function getPropertiesMap(): array
{
return [
'data' => [
'type' => 'object',
'enabled' => false,
],
'full_search_content' => [
'type' => 'text',
],
'suggest_search_content' => [
'type' => 'text',
'analyzer' => 'autocomplete',
'search_analyzer' => 'standard',
],
'category_id' => [
'type' => 'keyword',
'index' => false,
],
'rating' => [
'type' => 'double',
'index' => false,
],
'popular' => [
'type' => 'double',
'index' => false,
],
];
}
}
...@@ -16,7 +16,7 @@ class MappingValidator ...@@ -16,7 +16,7 @@ class MappingValidator
*/ */
public static function isPropertyExists(Configuration $configuration, string $property): bool public static function isPropertyExists(Configuration $configuration, string $property): bool
{ {
$properties = array_keys($configuration->getMapping()->es()['properties'] ?? []); $properties = array_keys($configuration->getMapping()['properties'] ?? []);
return in_array($property, $properties, true); return in_array($property, $properties, true);
} }
......
...@@ -20,7 +20,11 @@ return [ ...@@ -20,7 +20,11 @@ return [
], ],
'rating' => [ 'rating' => [
'type' => 'double', 'type' => 'double',
'index' => false, 'index' => true,
],
'new' => [
'type' => 'boolean',
'index' => true
], ],
'popular' => [ 'popular' => [
'type' => 'double', 'type' => 'double',
......
...@@ -6,7 +6,7 @@ interface Configuration ...@@ -6,7 +6,7 @@ interface Configuration
{ {
public function getIndexName(): string; public function getIndexName(): string;
public function getMapping(): Mapping; public function getMapping(): array;
public function getSettings(): array; public function getSettings(): array;
} }
<?php
namespace IQDEV\ElasticSearch\Converter;
use IQDEV\ElasticSearch\Config\MappingValidator;
use IQDEV\ElasticSearch\Configuration;
use IQDEV\ElasticSearch\Criteria;
use IQDEV\ElasticSearch\Document\Property\PropertyType;
use IQDEV\ElasticSearch\Request\Filter\Collection\FilterCollection;
use IQDEV\ElasticSearch\Request\Filter\Collection\FilterGroupCollection;
use IQDEV\ElasticSearch\Request\Filter\Collection\PostFilterCollection;
use IQDEV\ElasticSearch\Request\Filter\Collection\QueryFilterCollection;
use IQDEV\ElasticSearch\Request\Filter\Filter;
use IQDEV\ElasticSearch\Request\Filter\FilterOperator;
use IQDEV\ElasticSearch\Request\Filter\FilterType;
use IQDEV\ElasticSearch\Request\Filter\LogicOperator;
use IQDEV\ElasticSearch\Request\Filter\Value\FilterKeyword;
use IQDEV\ElasticSearch\Request\Filter\Value\FilterNumber;
use IQDEV\ElasticSearch\Request\Order\Order;
use IQDEV\ElasticSearch\Request\Search\Search;
use IQDEV\ElasticSearch\Request\Search\SearchQuery;
use IQDEV\ElasticSearch\Search\Aggs\Aggs;
use IQDEV\ElasticSearch\Search\Aggs\AggsFacetStats;
use IQDEV\ElasticSearch\Search\Aggs\AggsFacetTerms;
use IQDEV\ElasticSearch\Search\BoolQuery\FilterKeywordFacet;
use IQDEV\ElasticSearch\Search\BoolQuery\FilterNumberFacet;
use IQDEV\ElasticSearch\Search\BoolQuery\Query;
use IQDEV\ElasticSearch\Search\BoolQuery\Stats;
use IQDEV\ElasticSearch\Search\BoolQuery\Terms;
use IQDEV\ElasticSearch\Search\Nested;
use IQDEV\ElasticSearch\Search\Pagination;
use IQDEV\ElasticSearch\Search\Request;
final class CriteriaToEsRequest
{
public function __construct(
private readonly Configuration $configuration,
) {
}
public function fromCriteria(Criteria $criteria): Request
{
$request = new Request();
$request = $this->pagination($request, $criteria);
$request = $this->order($request, $criteria);
$request = $this->search($request, $criteria);
$request = $this->filter($request, $criteria);
$request = $this->aggs($request, $criteria);
return $request;
}
private function pagination(Request $request, Criteria $criteria): Request
{
$request = clone $request;
$request->setPagination(new Pagination($criteria->getPagination()->limit, $criteria->getPagination()->offset));
return $request;
}
private function order(Request $request, Criteria $criteria): Request
{
$request = clone $request;
if (true === $criteria->getSorting()->isEmpty()) {
return $request;
}
foreach ($criteria->getSorting() as $order) {
/** @var Order $order */
$request->getSort()->add($order);
}
return $request;
}
private function search(Request $request, Criteria $criteria): Request
{
$request = clone $request;
foreach ($criteria->getSearch() as $search) {
/** @var Search $search */
$searchQuery = new SearchQuery($search);
if ($search->getProperty()->getType() === PropertyType::TEXT) {
$request->getQueryMatch()->add($searchQuery->toQueryMatch());
} else {
$request->getQuery()->getMust()->add($searchQuery->toMust($this->configuration));
}
}
return $request;
}
private function filter(Request $request, Criteria $criteria): Request
{
$request = clone $request;
if ($criteria->getFilters()->isEmpty()) {
return $request;
}
$queryFilters = $criteria->getFilters()->getFilterCollectionByType(FilterType::QUERY);
$postFilters = $criteria->getFilters()->getFilterCollectionByType(FilterType::POST);
$this->addFilterToRequest($request, $queryFilters);
$this->addPostFilterToRequest($request, $postFilters);
return $request;
}
private function separatePropertyTypes(FilterCollection $filterCollection): array
{
$propertyFilter = new FilterCollection();
$nestedFilter = new FilterCollection();
foreach ($filterCollection as $groupFilter) {
/** @var FilterGroupCollection $groupFilter */
$propertyGroupCollection = new FilterGroupCollection();
$nestedGroupCollection = new FilterGroupCollection();
$propertyGroupCollection->setLogicOperator($groupFilter->getLogicOperator());
$nestedGroupCollection->setLogicOperator($groupFilter->getLogicOperator());
foreach ($groupFilter as $filter) {
/** @var Filter $filter */
if (true === MappingValidator::isPropertyExists($this->configuration, $filter->field()->value())) {
$propertyGroupCollection->add($filter);
} else {
$nestedGroupCollection->add($filter);
}
}
if (false === $propertyGroupCollection->isEmpty()) {
$propertyFilter->add($propertyGroupCollection);
}
if (false === $nestedGroupCollection->isEmpty()) {
$nestedFilter->add($nestedGroupCollection);
}
}
return [$propertyFilter, $nestedFilter];
}
private function addFilterToRequest(Request $request, QueryFilterCollection $filterCollection): void
{
[$propertyFilterCollection, $nestedFilterCollection] = $this->separatePropertyTypes($filterCollection);
$this->addPropertyFilterToRequest($request, $propertyFilterCollection);
$this->addNestedFilterToRequest($request, $nestedFilterCollection);
}
private function addPostFilterToRequest(Request $request, PostFilterCollection $filterCollection): void
{
[$propertyFilterCollection, $nestedFilterCollection] = $this->separatePropertyTypes($filterCollection);
$this->addPropertyPostFilterToRequest($request, $propertyFilterCollection);
$this->addNestedPostFilterToRequest($request, $nestedFilterCollection);
}
private function addPropertyFilterToRequest(Request $request, FilterCollection $filterCollection): void
{
$keywordFilterCollection = $this->getKeywordFilter($filterCollection);
foreach ($keywordFilterCollection->getFilter() as $filter) {
$request->getQuery()->getFilter()->add($filter);
}
foreach ($keywordFilterCollection->getShould() as $should) {
$request->getQuery()->getShould()->add($should);
}
$numberFilterCollection = $this->getNumberFilter($filterCollection);
foreach ($numberFilterCollection->getFilter() as $filter) {
$request->getQuery()->getFilter()->add($filter);
}
foreach ($numberFilterCollection->getShould() as $should) {
$request->getQuery()->getShould()->add($should);
}
}
private function addPropertyPostFilterToRequest(Request $request, FilterCollection $filterCollection): void
{
$keywordFilterCollection = $this->getKeywordFilter($filterCollection);
foreach ($keywordFilterCollection->getFilter() as $filter) {
$request->getPostFilter()->getFilter()->add($filter);
}
foreach ($keywordFilterCollection->getShould() as $should) {
$request->getPostFilter()->getShould()->add($should);
}
$numberFilterCollection = $this->getNumberFilter($filterCollection);
foreach ($numberFilterCollection->getFilter() as $filter) {
$request->getPostFilter()->getFilter()->add($filter);
}
foreach ($numberFilterCollection->getShould() as $should) {
$request->getPostFilter()->getShould()->add($should);
}
}
private function addNestedFilterToRequest(Request $request, FilterCollection $filterCollection): void
{
$keywordFilterCollection = $this->getKeywordFilter($filterCollection);
$keywordFilter = new Nested();
$keywordFilter->setPath('search_data');
if (false === $keywordFilterCollection->isEmpty()) {
$keywordNestedFilterQuery = clone $keywordFilter;
$keywordNestedFilterQuery->setQuery($keywordFilterCollection);
$request->getQuery()->getFilter()->add($keywordNestedFilterQuery);
}
$numberFilterCollection = $this->getNumberFilter($filterCollection);
$numberFilter = new Nested();
$numberFilter->setPath('search_data');
if (false === $numberFilterCollection->isEmpty()) {
$numberNestedFilterQuery = clone $numberFilter;
$numberNestedFilterQuery->setQuery($numberFilterCollection);
$request->getQuery()->getFilter()->add($numberNestedFilterQuery);
}
}
private function addNestedPostFilterToRequest(Request $request, FilterCollection $postFilter): void
{
$keywordFilterCollection = $this->getKeywordFilter($postFilter);
$keywordFilter = new Nested();
$keywordFilter->setPath('search_data');
if (false === $keywordFilterCollection->isEmpty()) {
$keywordNestedFilterQuery = clone $keywordFilter;
$keywordNestedFilterQuery->setQuery($keywordFilterCollection);
$request->getPostFilter()->getFilter()->add($keywordNestedFilterQuery);
}
$numberFilterCollection = $this->getNumberFilter($postFilter);
$numberFilter = new Nested();
$numberFilter->setPath('search_data');
if (false === $numberFilterCollection->isEmpty()) {
$numberNestedFilterQuery = clone $numberFilter;
$numberNestedFilterQuery->setQuery($numberFilterCollection);
$request->getPostFilter()->getFilter()->add($numberNestedFilterQuery);
}
}
private function getNumberFilter(FilterCollection $filterCollection, array $excludeFilter = []): Query
{
$numberFilter = new Query();
if ($filterCollection->isEmpty()) {
return $numberFilter;
}
$ranges = [];
foreach ($filterCollection as $filterGroup) {
/** @var FilterGroupCollection $filterGroup */
if ($filterGroup->isEmpty()) {
continue;
}
$group = $filterGroup->getLogicOperator() === LogicOperator::OR ? count($ranges) + 1 : 0;
if (!isset($ranges[$group])) {
$ranges[$group] = [];
}
foreach ($filterGroup as $filter) {
/** @var Filter $filter */
$value = $filter->value()->value();
$field = $filter->field()->value();
if (in_array($field, $excludeFilter, true)) {
continue;
}
if (in_array($filter->operator(), [FilterOperator::LT, FilterOperator::LTE], true)) {
$ranges[$group][$field][$filter->operator()->value] = $value;
continue;
}
if (in_array($filter->operator(), [FilterOperator::GT, FilterOperator::GTE], true)) {
$ranges[$group][$field][$filter->operator()->value] = $value;
}
}
}
if (false === empty($ranges)) {
foreach ($ranges as $iGroup => $group) {
foreach ($group as $field => $range) {
$isProperty = MappingValidator::isPropertyExists($this->configuration, $field);
$facet = $isProperty ? new Stats($field, $range) : new FilterNumberFacet(
$field,
$range
);
if ($iGroup === 0) {
$numberFilter->getFilter()->add($facet);
} else {
$numberFilter->getShould()->add($facet);
}
}
}
}
return $numberFilter;
}
private function getKeywordFilter(FilterCollection $filterCollection, array $excludeFilter = []): Query
{
$keywordFilter = new Query();
if ($filterCollection->isEmpty()) {
return $keywordFilter;
}
foreach ($filterCollection as $filterGroup) {
/** @var FilterGroupCollection $filterGroup */
if ($filterGroup->isEmpty()) {
continue;
}
$should = $filterGroup->getLogicOperator() === LogicOperator::OR;
foreach ($filterGroup as $filter) {
/** @var Filter $filter */
$value = $filter->value()->value();
$field = $filter->field()->value();
$isProperty = MappingValidator::isPropertyExists($this->configuration, $field);
if (in_array($field, $excludeFilter, true)) {
continue;
}
if (in_array($filter->operator(), [FilterOperator::LT, FilterOperator::LTE], true)) {
continue;
}
if (in_array($filter->operator(), [FilterOperator::GT, FilterOperator::GTE], true)) {
continue;
}
if (is_array($value)) {
$value = array_map(static fn($v) => (string)$v, $value);
} else {
$value = (string)$value;
}
if ($should) {
$keywordFilter->getShould()->add($isProperty ? new Terms($field, $value) : new FilterKeywordFacet($field, $value));
} else {
$keywordFilter->getFilter()->add($isProperty ? new Terms($field, $value) : new FilterKeywordFacet($field, $value));
}
}
}
return $keywordFilter;
}
private function aggs(Request $request, Criteria $criteria): Request
{
$request = clone $request;
if ($criteria->getFilters()->isEmpty() && $criteria->getSearch()->isEmpty()) {
return $request;
}
$request->getAggs()->add(
AggsFacetTerms::create(
'keyword_facet',
'keyword_facet'
)
);
$request->getAggs()->add(
AggsFacetStats::create(
'number_facet',
'number_facet'
)
);
$postFilters = $criteria->getFilters()->getFilterCollectionByType(FilterType::POST);
$getKey = static fn(string $type, string $name): string => sprintf('%s_facet_%s', $type, $name);
foreach ($postFilters as $filterGroup) {
/** @var FilterGroupCollection $filterGroup */
foreach ($filterGroup as $filter) {
/** @var Filter $filter */
$field = $filter->field()->value();
if ($filter->value() instanceof FilterNumber) {
continue;
}
if (in_array($filter->operator(), [], true)) {
continue;
}
if ($filter->value() instanceof FilterKeyword) {
$aggsFiltered = new Aggs($getKey('keyword', $field));
$aggsFiltered->addAggs(
AggsFacetTerms::create(
'agg_special',
'keyword_facet'
)
);
$queryKeywordFiltered = new Query();
$keywordFilter = $this->getKeywordFilter($postFilters, [$field]);
$numberFilter = $this->getNumberFilter($postFilters);
if (false === $keywordFilter->isEmpty()) {
$nestedFilterKeyword = new Nested();
$nestedFilterKeyword->setPath('search_data')
->setQuery($keywordFilter);
$queryKeywordFiltered->getFilter()->add($nestedFilterKeyword);
}
if (false === $numberFilter->isEmpty()) {
$nestedFilterNumber = new Nested();
$nestedFilterNumber->setPath('search_data')
->setQuery($numberFilter);
$queryKeywordFiltered->getFilter()->add($nestedFilterNumber);
}
if ($queryKeywordFiltered->isEmpty() === false) {
$aggsFiltered->setQuery($queryKeywordFiltered);
} else {
$aggsFiltered->setNested((new Nested())->setPath('search_data'));
}
$request->getAggs()->add($aggsFiltered);
}
}
}
$keywordFilter = $this->getKeywordFilter($postFilters);
$numberFilter = $this->getNumberFilter($postFilters);
$aggsKeywordFiltered = new Aggs('keyword_facet_filtered');
$aggsKeywordFiltered->addAggs(
AggsFacetTerms::create(
'all_keyword_facet_filtered',
'keyword_facet'
)
);
$queryKeywordFiltered = new Query();
$aggsNumberFiltered = new Aggs('number_facet_filtered');
$aggsNumberFiltered->addAggs(
AggsFacetStats::create(
'all_number_facet_filtered',
'number_facet'
)
);
$queryNumberFiltered = new Query();
if (false === $keywordFilter->isEmpty()) {
$nestedFilterKeyword = new Nested();
$nestedFilterKeyword->setPath('search_data')
->setQuery($keywordFilter);
$queryKeywordFiltered->getFilter()->add($nestedFilterKeyword);
$queryNumberFiltered->getFilter()->add($nestedFilterKeyword);
}
if (false === $numberFilter->isEmpty()) {
$nestedFilterNumber = new Nested();
$nestedFilterNumber->setPath('search_data')
->setQuery($numberFilter);
$queryKeywordFiltered->getFilter()->add($nestedFilterNumber);
$queryNumberFiltered->getFilter()->add($nestedFilterNumber);
}
if (false === $queryKeywordFiltered->isEmpty()) {
$aggsKeywordFiltered->setQuery($queryKeywordFiltered);
} else {
$aggsKeywordFiltered->setNested((new Nested())->setPath('search_data'));
}
if (false === $queryNumberFiltered->isEmpty()) {
$aggsNumberFiltered->setQuery($queryNumberFiltered);
} else {
$aggsNumberFiltered->setNested((new Nested())->setPath('search_data'));
}
$request->getAggs()
->add($aggsKeywordFiltered)
->add($aggsNumberFiltered);
return $request;
}
}
...@@ -5,10 +5,8 @@ declare(strict_types=1); ...@@ -5,10 +5,8 @@ declare(strict_types=1);
namespace IQDEV\ElasticSearch\Converter\Request\Aggregation; namespace IQDEV\ElasticSearch\Converter\Request\Aggregation;
use IQDEV\ElasticSearch\Configuration; use IQDEV\ElasticSearch\Configuration;
use IQDEV\ElasticSearch\Criteria; use IQDEV\ElasticSearch\Criteria\Criteria;
use IQDEV\ElasticSearch\Request\Filter\Collection\FilterGroupCollection; use IQDEV\ElasticSearch\Criteria\Filter\FilterType;
use IQDEV\ElasticSearch\Request\Filter\Filter;
use IQDEV\ElasticSearch\Request\Filter\FilterType;
use IQDEV\ElasticSearch\Search\Aggs\AggsCollection; use IQDEV\ElasticSearch\Search\Aggs\AggsCollection;
use IQDEV\ElasticSearch\Search\Aggs\AggsFacetStats; use IQDEV\ElasticSearch\Search\Aggs\AggsFacetStats;
use IQDEV\ElasticSearch\Search\Aggs\AggsFacetTerms; use IQDEV\ElasticSearch\Search\Aggs\AggsFacetTerms;
...@@ -25,39 +23,37 @@ class Aggregation ...@@ -25,39 +23,37 @@ class Aggregation
public function convertToQuery(): void public function convertToQuery(): void
{ {
$this->aggregations->add( $queryFilterCollection = $this->criteria->getFilters()->getFilterCollectionByType(FilterType::QUERY);
AggsFacetTerms::create(
'keyword_facet', if (false === $this->criteria->getSearch()->isEmpty() || false === $this->criteria->getFilters()->isEmpty()) {
'keyword_facet'
) $this->aggregations->add(
); AggsFacetTerms::create(
'keyword_facet', 'keyword_facet'
$this->aggregations->add( )
AggsFacetStats::create( );
'number_facet',
'number_facet' $this->aggregations->add(
) AggsFacetStats::create(
); 'number_facet', 'number_facet'
)
$postFilterCollection = $this->criteria->getFilters()->getFilterCollectionByType(FilterType::POST); );
// foreach ($postFilterCollection as $filterGroup) { $filterAggregation = new FilterAggregation($this->configuration, $queryFilterCollection);
// /** @var FilterGroupCollection $filterGroup */ $filterAggregation->updateRequestAggregation($this->aggregations);
//
// foreach ($filterGroup as $filter) { $fullAggregation = new FullAggregation($this->configuration, $queryFilterCollection);
// /** @var Filter $filter */ $fullAggregation->updateRequestAggregation($this->aggregations);
// }
// $filterAggregation = new FilterAggregation($this->configuration, $filter, $postFilterCollection);
// if (false === $this->criteria->getAggs()->isEmpty()) {
// if ($aggregation = $filterAggregation->getFilterAggregation()) { $propertyAggregation = new PropertyAggregation(
// $this->aggregations->add($aggregation); $this->configuration,
// } $queryFilterCollection,
// } $this->criteria->getAggs(),
// } );
$fullAggregation = new FullAggregation($this->configuration, $postFilterCollection); $propertyAggregation->updateRequestAggregation($this->aggregations);
}
$this->aggregations->add($fullAggregation->getKeywordAggregation());
$this->aggregations->add($fullAggregation->getRangeAggregation());
} }
public function getAggregation(): AggsCollection public function getAggregation(): AggsCollection
......
...@@ -6,12 +6,12 @@ namespace IQDEV\ElasticSearch\Converter\Request\Aggregation; ...@@ -6,12 +6,12 @@ namespace IQDEV\ElasticSearch\Converter\Request\Aggregation;
use IQDEV\ElasticSearch\Configuration; use IQDEV\ElasticSearch\Configuration;
use IQDEV\ElasticSearch\Converter\Request\FilterQuery; use IQDEV\ElasticSearch\Converter\Request\FilterQuery;
use IQDEV\ElasticSearch\Request\Filter\Collection\FilterCollection; use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterCollection;
use IQDEV\ElasticSearch\Request\Filter\Filter; use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterGroupCollection;
use IQDEV\ElasticSearch\Request\Filter\Value\FilterKeyword; use IQDEV\ElasticSearch\Criteria\Filter\Filter;
use IQDEV\ElasticSearch\Search\Aggs\Aggs; use IQDEV\ElasticSearch\Search\Aggs\Aggs;
use IQDEV\ElasticSearch\Search\Aggs\AggsCollection;
use IQDEV\ElasticSearch\Search\Aggs\AggsFacetTerms; use IQDEV\ElasticSearch\Search\Aggs\AggsFacetTerms;
use IQDEV\ElasticSearch\Search\BoolQuery\Query;
use IQDEV\ElasticSearch\Search\Nested; use IQDEV\ElasticSearch\Search\Nested;
class FilterAggregation class FilterAggregation
...@@ -20,57 +20,40 @@ class FilterAggregation ...@@ -20,57 +20,40 @@ class FilterAggregation
public function __construct( public function __construct(
private readonly Configuration $configuration, private readonly Configuration $configuration,
private readonly Filter $filter,
private readonly FilterCollection $filterCollection, private readonly FilterCollection $filterCollection,
) { ) {
if ($filter->value() instanceof FilterKeyword) {
$this->setAggregation();
}
} }
private function setAggregation(): void public function updateRequestAggregation(AggsCollection $original): void
{ {
$this->aggregation = new Aggs( foreach ($this->filterCollection as $filterGroup) {
$this->getKey('keyword', $this->filter->field()->value()) /** @var FilterGroupCollection $filterGroup */
);
$this->aggregation->addAggs( foreach ($filterGroup as $filter) {
AggsFacetTerms::create( /** @var Filter $filter */
'agg_special',
'keyword_facet'
)
);
// $queryKeywordFiltered = new Query(); $field = $filter->field()->value();
//
// $keywordFilterCollection = $this->filterCollection->getKeywordFilters([$this->filter->field()->value()]);
// $rangeFilterCollection = $this->filterCollection->getNumberFilters();
//
// $keywordFilterQuery = (new FilterQuery($this->configuration, $keywordFilterCollection))->getQuery();
// $rangeFilterQuery = (new FilterQuery($this->configuration, $rangeFilterCollection))->getQuery();
//
// if (false === $keywordFilterQuery->isEmpty()) {
// foreach ($keywordFilterQuery->getFilter() as $filter) {
// $queryKeywordFiltered->getFilter()->add($filter);
// }
// }
//
// if (false === $rangeFilterQuery->isEmpty()) {
// foreach ($rangeFilterQuery->getFilter() as $filter) {
// $queryKeywordFiltered->getFilter()->add($filter);
// }
// }
//
// if ($queryKeywordFiltered->isEmpty() === false) {
// $this->aggregation->setQuery($queryKeywordFiltered);
// } else {
// $this->aggregation->setNested((new Nested())->setPath('search_data'));
// }
}
public function getFilterAggregation(): ?Aggs $aggregation = new Aggs($this->getKey('keyword', $field));
{ $aggregation->addAggs(
return $this->aggregation; AggsFacetTerms::create(
'agg_special',
'keyword_facet'
)
);
$queryFilterBuilder = new FilterQuery($this->configuration, $this->filterCollection, [$field]);
$query = $queryFilterBuilder->getQuery();
if (false === $query->isEmpty()) {
$aggregation->setQuery($query);
} else {
$aggregation->setNested((new Nested())->setPath('search_data'));
}
$original->add($aggregation);
}
}
} }
private function getKey(string $type, string $name): string private function getKey(string $type, string $name): string
......
...@@ -6,37 +6,25 @@ namespace IQDEV\ElasticSearch\Converter\Request\Aggregation; ...@@ -6,37 +6,25 @@ namespace IQDEV\ElasticSearch\Converter\Request\Aggregation;
use IQDEV\ElasticSearch\Configuration; use IQDEV\ElasticSearch\Configuration;
use IQDEV\ElasticSearch\Converter\Request\FilterQuery; use IQDEV\ElasticSearch\Converter\Request\FilterQuery;
use IQDEV\ElasticSearch\Request\Filter\Collection\FilterCollection; use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterCollection;
use IQDEV\ElasticSearch\Search\Aggs\Aggs; use IQDEV\ElasticSearch\Search\Aggs\Aggs;
use IQDEV\ElasticSearch\Search\Aggs\AggsCollection;
use IQDEV\ElasticSearch\Search\Aggs\AggsFacetStats; use IQDEV\ElasticSearch\Search\Aggs\AggsFacetStats;
use IQDEV\ElasticSearch\Search\Aggs\AggsFacetTerms; use IQDEV\ElasticSearch\Search\Aggs\AggsFacetTerms;
use IQDEV\ElasticSearch\Search\BoolQuery\Query;
use IQDEV\ElasticSearch\Search\Nested; use IQDEV\ElasticSearch\Search\Nested;
class FullAggregation class FullAggregation
{ {
private Query $queryKeywordFiltered;
private Query $queryNumberFiltered;
public function __construct( public function __construct(
private readonly Configuration $configuration, private readonly Configuration $configuration,
private readonly FilterCollection $filterCollection, private readonly FilterCollection $filterCollection,
) { ) {
$this->queryKeywordFiltered = new Query();
$this->queryNumberFiltered = new Query();
} }
public function getKeywordAggregation(): Aggs public function updateRequestAggregation(AggsCollection $original): void
{ {
$filterCollection = $this->filterCollection->getKeywordFilters(); $keywordQuery = (new FilterQuery($this->configuration, $this->filterCollection->getKeywordFilters()))->getQuery();
$keywordFilter = (new FilterQuery($this->configuration, $filterCollection))->getQuery(); $numberQuery = (new FilterQuery($this->configuration, $this->filterCollection->getNumberFilters()))->getQuery();
if (isset($GLOBALS['DD']) && $GLOBALS['DD'] === true) {
dump($filterCollection);
dd($keywordFilter->es());
}
$aggsKeywordFiltered = new Aggs('keyword_facet_filtered'); $aggsKeywordFiltered = new Aggs('keyword_facet_filtered');
$aggsKeywordFiltered->addAggs( $aggsKeywordFiltered->addAggs(
...@@ -46,13 +34,6 @@ class FullAggregation ...@@ -46,13 +34,6 @@ class FullAggregation
) )
); );
return $aggsKeywordFiltered;
}
public function getRangeAggregation(): Aggs
{
$filterCollection = $this->filterCollection->getNumberFilters();
$aggsNumberFiltered = new Aggs('number_facet_filtered'); $aggsNumberFiltered = new Aggs('number_facet_filtered');
$aggsNumberFiltered->addAggs( $aggsNumberFiltered->addAggs(
AggsFacetStats::create( AggsFacetStats::create(
...@@ -61,6 +42,30 @@ class FullAggregation ...@@ -61,6 +42,30 @@ class FullAggregation
) )
); );
return $aggsNumberFiltered; if (false === $keywordQuery->getFilter()->isEmpty()) {
foreach ($keywordQuery->getFilter() as $item) {
$numberQuery->getFilter()->add($item);
}
}
if (false === $numberQuery->getFilter()->isEmpty()) {
foreach ($numberQuery->getFilter() as $item) {
$keywordQuery->getFilter()->add($item);
}
}
if (false === $keywordQuery->getFilter()->isEmpty()) {
$aggsKeywordFiltered->setQuery($keywordQuery);
} else {
$aggsKeywordFiltered->setNested((new Nested())->setPath('search_data'));
}
if (false === $numberQuery->getFilter()->isEmpty()) {
$aggsNumberFiltered->setQuery($numberQuery);
} else {
$aggsNumberFiltered->setNested((new Nested())->setPath('search_data'));
}
$original->add($aggsKeywordFiltered)->add($aggsNumberFiltered);
} }
} }
<?php
declare(strict_types=1);
namespace IQDEV\ElasticSearch\Converter\Request\Aggregation;
use IQDEV\ElasticSearch\Configuration;
use IQDEV\ElasticSearch\Converter\Request\FilterQuery;
use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterCollection;
use IQDEV\ElasticSearch\Document\Property\PropertyType;
use IQDEV\ElasticSearch\Search\Aggs\Aggs;
use IQDEV\ElasticSearch\Search\Aggs\AggsCollection;
use IQDEV\ElasticSearch\Search\Aggs\Terms;
class PropertyAggregation
{
public function __construct(
private readonly Configuration $configuration,
private readonly FilterCollection $filterCollection,
private readonly \IQDEV\ElasticSearch\Criteria\Aggs\AggsCollection $aggsCollection,
) {
}
public function updateRequestAggregation(AggsCollection $original): void
{
$queryFilterBuilder = new FilterQuery($this->configuration, $this->filterCollection);
$query = $queryFilterBuilder->getQuery();
/** @var \IQDEV\ElasticSearch\Criteria\Aggs\Aggs $aggs */
foreach ($this->aggsCollection as $aggs) {
$property = $aggs->getProperty();
if ($property->getType() !== PropertyType::BASE) {
continue;
}
$aggs = new Aggs($property->getKey());
if (false === $query->isEmpty()) {
$aggs->setQuery($query);
$aggs->addAggs(
(new Aggs($property->getKey()))
->setTerms(new Terms($property->getKey()))
);
} else {
$aggs->setTerms(new Terms($property->getKey()));
}
$aggs->addAggs(
(new Aggs($property->getKey()))
->setTerms(new Terms($property->getKey()))
);
$original->add($aggs);
}
}
}
...@@ -4,7 +4,7 @@ declare(strict_types=1); ...@@ -4,7 +4,7 @@ declare(strict_types=1);
namespace IQDEV\ElasticSearch\Converter\Request\Collection; namespace IQDEV\ElasticSearch\Converter\Request\Collection;
use IQDEV\ElasticSearch\Request\Filter\Collection\FilterCollection; use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterCollection;
class NestedFilterCollection extends FilterCollection class NestedFilterCollection extends FilterCollection
{ {
......
...@@ -4,7 +4,7 @@ declare(strict_types=1); ...@@ -4,7 +4,7 @@ declare(strict_types=1);
namespace IQDEV\ElasticSearch\Converter\Request\Collection; namespace IQDEV\ElasticSearch\Converter\Request\Collection;
use IQDEV\ElasticSearch\Request\Filter\Collection\FilterCollection; use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterCollection;
class PropertyFilterCollection extends FilterCollection class PropertyFilterCollection extends FilterCollection
{ {
......
...@@ -6,14 +6,12 @@ namespace IQDEV\ElasticSearch\Converter\Request; ...@@ -6,14 +6,12 @@ namespace IQDEV\ElasticSearch\Converter\Request;
use IQDEV\ElasticSearch\Configuration; use IQDEV\ElasticSearch\Configuration;
use IQDEV\ElasticSearch\Converter\Request\Aggregation\Aggregation; use IQDEV\ElasticSearch\Converter\Request\Aggregation\Aggregation;
use IQDEV\ElasticSearch\Criteria; use IQDEV\ElasticSearch\Criteria\Criteria;
use IQDEV\ElasticSearch\Criteria\Filter\Collection\PostFilterCollection;
use IQDEV\ElasticSearch\Criteria\Filter\Collection\QueryFilterCollection;
use IQDEV\ElasticSearch\Criteria\Search\Search;
use IQDEV\ElasticSearch\Criteria\Search\SearchQuery;
use IQDEV\ElasticSearch\Document\Property\PropertyType; use IQDEV\ElasticSearch\Document\Property\PropertyType;
use IQDEV\ElasticSearch\Request\Filter\Collection\PostFilterCollection;
use IQDEV\ElasticSearch\Request\Filter\Collection\QueryFilterCollection;
use IQDEV\ElasticSearch\Request\Search\Search;
use IQDEV\ElasticSearch\Request\Search\SearchQuery;
use IQDEV\ElasticSearch\Search\Aggs\AggsFacetStats;
use IQDEV\ElasticSearch\Search\Aggs\AggsFacetTerms;
use IQDEV\ElasticSearch\Search\Pagination; use IQDEV\ElasticSearch\Search\Pagination;
class CriteriaRequestBuilder extends RequestBuilder class CriteriaRequestBuilder extends RequestBuilder
...@@ -42,9 +40,7 @@ class CriteriaRequestBuilder extends RequestBuilder ...@@ -42,9 +40,7 @@ class CriteriaRequestBuilder extends RequestBuilder
$this->setFilter(); $this->setFilter();
} }
if (false === $this->criteria->getSearch()->isEmpty() || false === $this->criteria->getFilters()->isEmpty()) { $this->setAggregations();
$this->setAggregations();
}
} }
public function setPagination(): void public function setPagination(): void
...@@ -106,7 +102,7 @@ class CriteriaRequestBuilder extends RequestBuilder ...@@ -106,7 +102,7 @@ class CriteriaRequestBuilder extends RequestBuilder
$request = clone $this->request; $request = clone $this->request;
$filterQuery = new FilterQuery($this->configuration, $filterCollection); $filterQuery = new FilterQuery($this->configuration, $filterCollection);
$request->setQuery($filterQuery->getQuery()); $request->getQuery()->modify($filterQuery->getQuery());
$this->request = $request; $this->request = $request;
} }
...@@ -116,7 +112,7 @@ class CriteriaRequestBuilder extends RequestBuilder ...@@ -116,7 +112,7 @@ class CriteriaRequestBuilder extends RequestBuilder
$request = clone $this->request; $request = clone $this->request;
$filterQuery = new FilterQuery($this->configuration, $filterCollection); $filterQuery = new FilterQuery($this->configuration, $filterCollection);
$request->setPostFilter($filterQuery->getQuery()); $request->getPostFilter()->modify($filterQuery->getQuery());
$this->request = $request; $this->request = $request;
} }
......
...@@ -2,11 +2,10 @@ ...@@ -2,11 +2,10 @@
declare(strict_types=1); declare(strict_types=1);
namespace IQDEV\ElasticSearch\Converter; namespace IQDEV\ElasticSearch\Converter\Request;
use IQDEV\ElasticSearch\Configuration; use IQDEV\ElasticSearch\Configuration;
use IQDEV\ElasticSearch\Converter\Request\CriteriaRequestBuilder; use IQDEV\ElasticSearch\Criteria\Criteria;
use IQDEV\ElasticSearch\Criteria;
use IQDEV\ElasticSearch\Search\Request; use IQDEV\ElasticSearch\Search\Request;
final class CriteriaToRequest final class CriteriaToRequest
......
...@@ -5,8 +5,8 @@ declare(strict_types=1); ...@@ -5,8 +5,8 @@ declare(strict_types=1);
namespace IQDEV\ElasticSearch\Converter\Request\Filter; namespace IQDEV\ElasticSearch\Converter\Request\Filter;
use IQDEV\ElasticSearch\Esable; use IQDEV\ElasticSearch\Esable;
use IQDEV\ElasticSearch\Request\Filter\Collection\FilterGroupCollection; use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterGroupCollection;
use IQDEV\ElasticSearch\Request\Filter\LogicOperator; use IQDEV\ElasticSearch\Criteria\Filter\LogicOperator;
use IQDEV\ElasticSearch\Search\BoolQuery\Query; use IQDEV\ElasticSearch\Search\BoolQuery\Query;
use IQDEV\ElasticSearch\Search\Nested; use IQDEV\ElasticSearch\Search\Nested;
...@@ -18,14 +18,14 @@ abstract class AbstractFilterQuery ...@@ -18,14 +18,14 @@ abstract class AbstractFilterQuery
$this->query = new Query(); $this->query = new Query();
} }
protected function setFilterByLogic(LogicOperator $logicOperator, Esable $filter): void protected function setFilterByLogic(Query $query, LogicOperator $logicOperator, Esable $filter): void
{ {
match ($logicOperator) { match ($logicOperator) {
LogicOperator::AND => $this->query->getFilter()->add($filter), LogicOperator::AND => $query->getFilter()->add($filter),
LogicOperator::OR => $this->query->getShould()->add($filter), LogicOperator::OR => $query->getShould()->add($filter),
LogicOperator::NOT => $this->query->getMustNot()->add($filter), LogicOperator::NOT => $query->getMustNot()->add($filter),
}; };
} }
abstract public function getQuery(FilterGroupCollection $filterGroupCollection): Query|Nested; abstract public function getQuery(FilterGroupCollection $filterGroupCollection, array $exclude): Query|Nested;
} }
...@@ -6,8 +6,8 @@ namespace IQDEV\ElasticSearch\Converter\Request\Filter; ...@@ -6,8 +6,8 @@ namespace IQDEV\ElasticSearch\Converter\Request\Filter;
use IQDEV\ElasticSearch\Converter\Request\Filter\Type\KeywordFilterType; use IQDEV\ElasticSearch\Converter\Request\Filter\Type\KeywordFilterType;
use IQDEV\ElasticSearch\Converter\Request\Filter\Type\RangeFilterType; use IQDEV\ElasticSearch\Converter\Request\Filter\Type\RangeFilterType;
use IQDEV\ElasticSearch\Request\Filter\Collection\FilterGroupCollection; use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterGroupCollection;
use IQDEV\ElasticSearch\Request\Filter\Filter; use IQDEV\ElasticSearch\Criteria\Filter\Filter;
use IQDEV\ElasticSearch\Search\BoolQuery\Query; use IQDEV\ElasticSearch\Search\BoolQuery\Query;
use IQDEV\ElasticSearch\Search\BoolQuery\Terms; use IQDEV\ElasticSearch\Search\BoolQuery\Terms;
use IQDEV\ElasticSearch\Search\Nested; use IQDEV\ElasticSearch\Search\Nested;
...@@ -17,28 +17,30 @@ class NestedFilter extends AbstractFilterQuery ...@@ -17,28 +17,30 @@ class NestedFilter extends AbstractFilterQuery
public const NESTED_RANGE_PATH = 'search_data.number_facet'; public const NESTED_RANGE_PATH = 'search_data.number_facet';
public const NESTED_KEYWORD_PATH = 'search_data.keyword_facet'; public const NESTED_KEYWORD_PATH = 'search_data.keyword_facet';
public function getQuery(FilterGroupCollection $filterGroupCollection): Nested public function getQuery(FilterGroupCollection $filterGroupCollection, array $exclude): Nested
{ {
$keywordFiltersGroup = $filterGroupCollection->getKeywordFilters(); $query = new Query();
$keywordFiltersGroup = $filterGroupCollection->getKeywordFilters($exclude);
foreach ($keywordFiltersGroup as $keywordFilter) { foreach ($keywordFiltersGroup as $keywordFilter) {
/** @var Filter $keywordFilter */ /** @var Filter $keywordFilter */
$esableFilter = new KeywordFilterType($keywordFilter); $esableFilter = new KeywordFilterType($keywordFilter);
$this->setFilterByLogic($filterGroupCollection->getLogicOperator(), $this->getNested($esableFilter, self::NESTED_KEYWORD_PATH)); $this->setFilterByLogic($query, $filterGroupCollection->getLogicOperator(), $this->getNested($esableFilter, self::NESTED_KEYWORD_PATH));
} }
$rangeFilterGroup = $filterGroupCollection->getRangeFilters(); $rangeFilterGroup = $filterGroupCollection->getRangeFilters($exclude);
$rangesFilter = RangeFilterType::getFiltersByOneProperty($rangeFilterGroup); $rangesFilter = RangeFilterType::getFiltersByOneProperty($rangeFilterGroup);
foreach ($rangesFilter as $filterGroup) { foreach ($rangesFilter as $filterGroup) {
/** @var FilterGroupCollection $filterGroup */ /** @var FilterGroupCollection $filterGroup */
$esableFilter = new RangeFilterType($filterGroup); $esableFilter = new RangeFilterType($filterGroup);
$this->setFilterByLogic($filterGroupCollection->getLogicOperator(), $this->getNested($esableFilter, self::NESTED_RANGE_PATH)); $this->setFilterByLogic($query, $filterGroupCollection->getLogicOperator(), $this->getNested($esableFilter, self::NESTED_RANGE_PATH));
} }
return (new Nested()) return (new Nested())
->setPath('search_data') ->setPath('search_data')
->setQuery($this->query); ->setQuery($query);
} }
private function getNested(RangeFilterType|KeywordFilterType $filter, string $path): Nested private function getNested(RangeFilterType|KeywordFilterType $filter, string $path): Nested
......
...@@ -6,31 +6,33 @@ namespace IQDEV\ElasticSearch\Converter\Request\Filter; ...@@ -6,31 +6,33 @@ namespace IQDEV\ElasticSearch\Converter\Request\Filter;
use IQDEV\ElasticSearch\Converter\Request\Filter\Type\KeywordFilterType; use IQDEV\ElasticSearch\Converter\Request\Filter\Type\KeywordFilterType;
use IQDEV\ElasticSearch\Converter\Request\Filter\Type\RangeFilterType; use IQDEV\ElasticSearch\Converter\Request\Filter\Type\RangeFilterType;
use IQDEV\ElasticSearch\Request\Filter\Collection\FilterGroupCollection; use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterGroupCollection;
use IQDEV\ElasticSearch\Request\Filter\Filter; use IQDEV\ElasticSearch\Criteria\Filter\Filter;
use IQDEV\ElasticSearch\Search\BoolQuery\Query; use IQDEV\ElasticSearch\Search\BoolQuery\Query;
class PropertyFilter extends AbstractFilterQuery class PropertyFilter extends AbstractFilterQuery
{ {
public function getQuery(FilterGroupCollection $filterGroupCollection): Query public function getQuery(FilterGroupCollection $filterGroupCollection, array $exclude = []): Query
{ {
$keywordFiltersGroup = $filterGroupCollection->getKeywordFilters(); $query = new Query();
$keywordFiltersGroup = $filterGroupCollection->getKeywordFilters($exclude);
foreach ($keywordFiltersGroup as $keywordFilter) { foreach ($keywordFiltersGroup as $keywordFilter) {
/** @var Filter $keywordFilter */ /** @var Filter $keywordFilter */
$esableFilter = new KeywordFilterType($keywordFilter); $esableFilter = new KeywordFilterType($keywordFilter);
$this->setFilterByLogic($filterGroupCollection->getLogicOperator(), $esableFilter->getEsable()); $this->setFilterByLogic($query, $filterGroupCollection->getLogicOperator(), $esableFilter->getEsable());
} }
$rangeFilterGroup = $filterGroupCollection->getRangeFilters(); $rangeFilterGroup = $filterGroupCollection->getRangeFilters($exclude);
$rangesFilter = RangeFilterType::getFiltersByOneProperty($rangeFilterGroup); $rangesFilter = RangeFilterType::getFiltersByOneProperty($rangeFilterGroup);
foreach ($rangesFilter as $filterGroup) { foreach ($rangesFilter as $filterGroup) {
/** @var FilterGroupCollection $filterGroup */ /** @var FilterGroupCollection $filterGroup */
$esableFilter = new RangeFilterType($filterGroup); $esableFilter = new RangeFilterType($filterGroup);
$this->setFilterByLogic($filterGroupCollection->getLogicOperator(), $esableFilter->getEsable()); $this->setFilterByLogic($query, $filterGroupCollection->getLogicOperator(), $esableFilter->getEsable());
} }
return $this->query; return $query;
} }
} }
...@@ -5,7 +5,7 @@ declare(strict_types=1); ...@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace IQDEV\ElasticSearch\Converter\Request\Filter\Type; namespace IQDEV\ElasticSearch\Converter\Request\Filter\Type;
use IQDEV\ElasticSearch\Esable; use IQDEV\ElasticSearch\Esable;
use IQDEV\ElasticSearch\Request\Filter\Filter; use IQDEV\ElasticSearch\Criteria\Filter\Filter;
use IQDEV\ElasticSearch\Search\BoolQuery\Terms; use IQDEV\ElasticSearch\Search\BoolQuery\Terms;
class KeywordFilterType extends AbstractFilterType class KeywordFilterType extends AbstractFilterType
......
...@@ -5,9 +5,9 @@ declare(strict_types=1); ...@@ -5,9 +5,9 @@ declare(strict_types=1);
namespace IQDEV\ElasticSearch\Converter\Request\Filter\Type; namespace IQDEV\ElasticSearch\Converter\Request\Filter\Type;
use IQDEV\ElasticSearch\Esable; use IQDEV\ElasticSearch\Esable;
use IQDEV\ElasticSearch\Request\Filter\Collection\FilterCollection; use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterCollection;
use IQDEV\ElasticSearch\Request\Filter\Collection\FilterGroupCollection; use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterGroupCollection;
use IQDEV\ElasticSearch\Request\Filter\Filter; use IQDEV\ElasticSearch\Criteria\Filter\Filter;
use IQDEV\ElasticSearch\Search\BoolQuery\Stats; use IQDEV\ElasticSearch\Search\BoolQuery\Stats;
class RangeFilterType extends AbstractFilterType class RangeFilterType extends AbstractFilterType
......