diff --git a/vendor/magento/module-catalog-graph-ql/DataProvider/Product/SearchCriteriaBuilder.php b/vendor/magento/module-catalog-graph-ql/DataProvider/Product/SearchCriteriaBuilder.php
index e05a5ec1c8141..e0fd89c978f40 100644
--- a/vendor/magento/module-catalog-graph-ql/DataProvider/Product/SearchCriteriaBuilder.php
+++ b/vendor/magento/module-catalog-graph-ql/DataProvider/Product/SearchCriteriaBuilder.php
@@ -153,7 +153,7 @@ public function build(array $args, bool $includeAggregation): SearchCriteriaInte
$this->addEntityIdSort($searchCriteria);
$this->addVisibilityFilter($searchCriteria, $isSearch, !empty($args['filter']['category_id']));
- $searchCriteria->setCurrentPage($args['currentPage']);
+ $searchCriteria->setCurrentPage($args['currentPage'] - 1);
$searchCriteria->setPageSize($args['pageSize']);
return $searchCriteria;
@@ -254,7 +254,7 @@ private function addEntityIdSort(SearchCriteriaInterface $searchCriteria): void
}
$sortOrderArray[] = $this->sortOrderBuilder
- ->setField('_id')
+ ->setField('entity_id')
->setDirection($sortDir)
->create();
$searchCriteria->setSortOrders($sortOrderArray);
diff --git a/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/DataProvider/ProductSearch.php b/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/DataProvider/ProductSearch.php
index f1d30ab942aab..5c170f428bc94 100644
--- a/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/DataProvider/ProductSearch.php
+++ b/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/DataProvider/ProductSearch.php
@@ -8,18 +8,15 @@
namespace Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider;
use Magento\Catalog\Api\Data\ProductSearchResultsInterfaceFactory;
-use Magento\Catalog\Model\Product\Visibility;
use Magento\Catalog\Model\ResourceModel\Product\Collection;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\Product\CollectionProcessorInterface;
use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\Product\CollectionPostProcessorInterface;
-use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\ProductSearch\ProductCollectionSearchCriteriaBuilder;
use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplierFactory;
-use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplierInterface;
+use Magento\Framework\Api\Search\SearchCriteriaInterfaceFactory as SearchCriteriaFactory;
use Magento\Framework\Api\Search\SearchResultInterface;
use Magento\Framework\Api\SearchCriteriaInterface;
use Magento\Framework\Api\SearchResultsInterface;
-use Magento\Framework\App\ObjectManager;
use Magento\GraphQl\Model\Query\ContextInterface;
/**
@@ -53,14 +50,9 @@ class ProductSearch
private $searchResultApplierFactory;
/**
- * @var ProductCollectionSearchCriteriaBuilder
+ * @var SearchCriteriaFactory
*/
- private $searchCriteriaBuilder;
-
- /**
- * @var Visibility
- */
- private $catalogProductVisibility;
+ private $searchCriteriaFactory;
/**
* @param CollectionFactory $collectionFactory
@@ -68,8 +60,7 @@ class ProductSearch
* @param CollectionProcessorInterface $collectionPreProcessor
* @param CollectionPostProcessorInterface $collectionPostProcessor
* @param SearchResultApplierFactory $searchResultsApplierFactory
- * @param ProductCollectionSearchCriteriaBuilder $searchCriteriaBuilder
- * @param Visibility $catalogProductVisibility
+ * @param SearchCriteriaFactory $searchCriteriaFactory
*/
public function __construct(
CollectionFactory $collectionFactory,
@@ -77,16 +68,14 @@ public function __construct(
CollectionProcessorInterface $collectionPreProcessor,
CollectionPostProcessorInterface $collectionPostProcessor,
SearchResultApplierFactory $searchResultsApplierFactory,
- ProductCollectionSearchCriteriaBuilder $searchCriteriaBuilder,
- Visibility $catalogProductVisibility
+ SearchCriteriaFactory $searchCriteriaFactory
) {
$this->collectionFactory = $collectionFactory;
$this->searchResultsFactory = $searchResultsFactory;
$this->collectionPreProcessor = $collectionPreProcessor;
$this->collectionPostProcessor = $collectionPostProcessor;
$this->searchResultApplierFactory = $searchResultsApplierFactory;
- $this->searchCriteriaBuilder = $searchCriteriaBuilder;
- $this->catalogProductVisibility = $catalogProductVisibility;
+ $this->searchCriteriaFactory = $searchCriteriaFactory;
}
/**
@@ -107,75 +96,27 @@ public function getList(
/** @var Collection $collection */
$collection = $this->collectionFactory->create();
- //Create a copy of search criteria without filters to preserve the results from search
- $searchCriteriaForCollection = $this->searchCriteriaBuilder->build($searchCriteria);
//Apply CatalogSearch results from search and join table
- $this->getSearchResultsApplier(
- $searchResult,
- $collection,
- $this->getSortOrderArray($searchCriteriaForCollection)
- )->apply();
-
- $collection->setFlag('search_resut_applied', true);
-
- $collection->setVisibility($this->catalogProductVisibility->getVisibleInSiteIds());
- $this->collectionPreProcessor->process($collection, $searchCriteriaForCollection, $attributes, $context);
- $collection->load();
- $this->collectionPostProcessor->process($collection, $attributes, $context);
-
- $searchResults = $this->searchResultsFactory->create();
- $searchResults->setSearchCriteria($searchCriteriaForCollection);
- $searchResults->setItems($collection->getItems());
- $searchResults->setTotalCount($collection->getSize());
- return $searchResults;
- }
-
- /**
- * Create searchResultApplier
- *
- * @param SearchResultInterface $searchResult
- * @param Collection $collection
- * @param array $orders
- * @return SearchResultApplierInterface
- */
- private function getSearchResultsApplier(
- SearchResultInterface $searchResult,
- Collection $collection,
- array $orders
- ): SearchResultApplierInterface {
- return $this->searchResultApplierFactory->create(
+ $searchResultsApplier = $this->searchResultApplierFactory->create(
[
'collection' => $collection,
'searchResult' => $searchResult,
- 'orders' => $orders
]
);
- }
+ $searchResultsApplier->apply();
- /**
- * Format sort orders into associative array
- *
- * E.g. ['field1' => 'DESC', 'field2' => 'ASC", ...]
- *
- * @param SearchCriteriaInterface $searchCriteria
- * @return array
- */
- private function getSortOrderArray(SearchCriteriaInterface $searchCriteria)
- {
- $ordersArray = [];
- $sortOrders = $searchCriteria->getSortOrders();
- if (is_array($sortOrders)) {
- foreach ($sortOrders as $sortOrder) {
- // I am replacing _id with entity_id because in ElasticSearch _id is required for sorting by ID.
- // Where as entity_id is required when using ID as the sort in $collection->load();.
- // @see \Magento\CatalogGraphQl\Model\Resolver\Products\Query\Search::getResult
- if ($sortOrder->getField() === '_id') {
- $sortOrder->setField('entity_id');
- }
- $ordersArray[$sortOrder->getField()] = $sortOrder->getDirection();
- }
- }
+ //Empty search criteria for backward compatibility.
+ //Search criteria must be already applied to the search result.
+ $emptySearchCriteria = $this->searchCriteriaFactory->create();
+ $this->collectionPreProcessor->process($collection, $emptySearchCriteria, $attributes, $context);
+ $collection->load();
+ $this->collectionPostProcessor->process($collection, $attributes, $context);
- return $ordersArray;
+ $searchResults = $this->searchResultsFactory->create();
+ $searchResults->setSearchCriteria($searchCriteria);
+ $searchResults->setItems($collection->getItems());
+ $searchResults->setTotalCount($searchResult->getTotalCount());
+
+ return $searchResults;
}
}
diff --git a/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/DataProvider/ProductSearch/ProductCollectionSearchCriteriaBuilder.php b/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/DataProvider/ProductSearch/ProductCollectionSearchCriteriaBuilder.php
index 03e8358b1ee7a..e69de29bb2d1d 100644
--- a/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/DataProvider/ProductSearch/ProductCollectionSearchCriteriaBuilder.php
+++ b/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/DataProvider/ProductSearch/ProductCollectionSearchCriteriaBuilder.php
@@ -1,77 +0,0 @@
-searchCriteriaFactory = $searchCriteriaFactory;
- $this->filterBuilder = $filterBuilder;
- $this->filterGroupBuilder = $filterGroupBuilder;
- }
-
- /**
- * Build searchCriteria from search for product collection
- *
- * @param SearchCriteriaInterface $searchCriteria
- * @return SearchCriteriaInterface
- */
- public function build(SearchCriteriaInterface $searchCriteria): SearchCriteriaInterface
- {
- //Create a copy of search criteria without filters to preserve the results from search
- $searchCriteriaForCollection = $this->searchCriteriaFactory->create()
- ->setSortOrders($searchCriteria->getSortOrders())
- ->setPageSize($searchCriteria->getPageSize())
- ->setCurrentPage($searchCriteria->getCurrentPage());
-
- //Add category id to enable sorting by position
- foreach ($searchCriteria->getFilterGroups() as $filterGroup) {
- foreach ($filterGroup->getFilters() as $filter) {
- if ($filter->getField() == CategoryProductLink::KEY_CATEGORY_ID) {
- $categoryFilter = $this->filterBuilder
- ->setField(CategoryProductLink::KEY_CATEGORY_ID)
- ->setValue($filter->getValue())
- ->setConditionType($filter->getConditionType())
- ->create();
-
- $this->filterGroupBuilder->addFilter($categoryFilter);
- $categoryGroup = $this->filterGroupBuilder->create();
- $searchCriteriaForCollection->setFilterGroups([$categoryGroup]);
- }
- }
- }
- return $searchCriteriaForCollection;
- }
-}
diff --git a/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/Query/Search.php b/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/Query/Search.php
index c4d189cd7cb0c..fcc134649352a 100644
--- a/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/Query/Search.php
+++ b/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/Query/Search.php
@@ -13,13 +13,11 @@
use Magento\CatalogGraphQl\Model\Resolver\Products\SearchResult;
use Magento\CatalogGraphQl\Model\Resolver\Products\SearchResultFactory;
use Magento\Framework\Api\Search\SearchCriteriaInterface;
-use Magento\Framework\App\ObjectManager;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Query\Resolver\ArgumentsProcessorInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\GraphQl\Model\Query\ContextInterface;
use Magento\Search\Api\SearchInterface;
-use Magento\Search\Model\Search\PageSizeProvider;
/**
* Full text search for catalog using given search criteria.
@@ -38,11 +36,6 @@ class Search implements ProductQueryInterface
*/
private $searchResultFactory;
- /**
- * @var PageSizeProvider
- */
- private $pageSizeProvider;
-
/**
* @var FieldSelection
*/
@@ -76,36 +69,31 @@ class Search implements ProductQueryInterface
/**
* @param SearchInterface $search
* @param SearchResultFactory $searchResultFactory
- * @param PageSizeProvider $pageSize
* @param FieldSelection $fieldSelection
* @param ProductSearch $productsProvider
* @param SearchCriteriaBuilder $searchCriteriaBuilder
- * @param ArgumentsProcessorInterface|null $argsSelection
- * @param Suggestions|null $suggestions
- * @param QueryPopularity|null $queryPopularity
+ * @param ArgumentsProcessorInterface $argsSelection
+ * @param Suggestions $suggestions
+ * @param QueryPopularity $queryPopularity
*/
public function __construct(
SearchInterface $search,
SearchResultFactory $searchResultFactory,
- PageSizeProvider $pageSize,
FieldSelection $fieldSelection,
ProductSearch $productsProvider,
SearchCriteriaBuilder $searchCriteriaBuilder,
- ArgumentsProcessorInterface $argsSelection = null,
- Suggestions $suggestions = null,
- QueryPopularity $queryPopularity = null
+ ArgumentsProcessorInterface $argsSelection,
+ Suggestions $suggestions,
+ QueryPopularity $queryPopularity
) {
$this->search = $search;
$this->searchResultFactory = $searchResultFactory;
- $this->pageSizeProvider = $pageSize;
$this->fieldSelection = $fieldSelection;
$this->productsProvider = $productsProvider;
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
- $this->argsSelection = $argsSelection ?: ObjectManager::getInstance()
- ->get(ArgumentsProcessorInterface::class);
- $this->suggestions = $suggestions ?: ObjectManager::getInstance()
- ->get(Suggestions::class);
- $this->queryPopularity = $queryPopularity ?: ObjectManager::getInstance()->get(QueryPopularity::class);
+ $this->argsSelection = $argsSelection;
+ $this->suggestions = $suggestions;
+ $this->queryPopularity = $queryPopularity;
}
/**
@@ -123,18 +111,7 @@ public function getResult(
ContextInterface $context
): SearchResult {
$searchCriteria = $this->buildSearchCriteria($args, $info);
-
- $realPageSize = $searchCriteria->getPageSize();
- $realCurrentPage = $searchCriteria->getCurrentPage();
- //Because of limitations of sort and pagination on search API we will query all IDS
- $pageSize = $this->pageSizeProvider->getMaxPageSize();
- $searchCriteria->setPageSize($pageSize);
- $searchCriteria->setCurrentPage(0);
$itemsResults = $this->search->search($searchCriteria);
-
- //Address limitations of sort and pagination on search API apply original pagination from GQL query
- $searchCriteria->setPageSize($realPageSize);
- $searchCriteria->setCurrentPage($realCurrentPage);
$searchResults = $this->productsProvider->getList(
$searchCriteria,
$itemsResults,
@@ -142,7 +119,9 @@ public function getResult(
$context
);
- $totalPages = $realPageSize ? ((int)ceil($searchResults->getTotalCount() / $realPageSize)) : 0;
+ $totalPages = $searchCriteria->getPageSize()
+ ? ((int)ceil($searchResults->getTotalCount() / $searchCriteria->getPageSize()))
+ : 0;
// add query statistics data
if (!empty($args['search'])) {
@@ -167,8 +146,8 @@ public function getResult(
'totalCount' => $totalCount,
'productsSearchResult' => $productArray,
'searchAggregation' => $itemsResults->getAggregations(),
- 'pageSize' => $realPageSize,
- 'currentPage' => $realCurrentPage,
+ 'pageSize' => $searchCriteria->getPageSize(),
+ 'currentPage' => $searchCriteria->getCurrentPage() + 1, //search criteria pagination starts with 0
'totalPages' => $totalPages,
'suggestions' => $suggestions,
]
diff --git a/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/SearchCriteria/CollectionProcessor/FilterProcessor/CategoryFilter.php b/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/SearchCriteria/CollectionProcessor/FilterProcessor/CategoryFilter.php
index d15c072b9fe4b..e8825b95a9c7c 100644
--- a/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/SearchCriteria/CollectionProcessor/FilterProcessor/CategoryFilter.php
+++ b/vendor/magento/module-catalog-graph-ql/Model/Resolver/Products/SearchCriteria/CollectionProcessor/FilterProcessor/CategoryFilter.php
@@ -105,14 +105,11 @@ public function apply(Filter $filter, AbstractDb $collection)
} elseif ($conditionType === self::CONDITION_TYPE_IN) {
$this->joinMinimalPosition->execute($collection, $ids);
}
- /** Prevent filtering duplication as the filter should be already applied to the search result */
- if (!$collection->getFlag('search_resut_applied')) {
- $collection->addCategoriesFilter(
- [
- $conditionType => array_map('intval', $this->getCategoryIds($ids))
- ]
- );
- }
+ $collection->addCategoriesFilter(
+ [
+ $conditionType => array_map('intval', $this->getCategoryIds($ids))
+ ]
+ );
}
return true;
diff --git a/vendor/magento/module-catalog-search/Model/ResourceModel/Fulltext/Collection.php b/vendor/magento/module-catalog-search/Model/ResourceModel/Fulltext/Collection.php
index d8d4f158ecaa2..237b5a1bb6841 100644
--- a/vendor/magento/module-catalog-search/Model/ResourceModel/Fulltext/Collection.php
+++ b/vendor/magento/module-catalog-search/Model/ResourceModel/Fulltext/Collection.php
@@ -581,7 +581,7 @@ protected function _beforeLoad()
* for the same requests and products with the same relevance
* NOTE: this does not replace existing orders but ADDs one more
*/
- $this->setOrder('entity_id');
+ $this->setOrder('entity_id', Select::SQL_ASC);
return parent::_beforeLoad();
}
diff --git a/vendor/magento/module-catalog-search/Model/ResourceModel/Fulltext/Collection/SearchResultApplier.php b/vendor/magento/module-catalog-search/Model/ResourceModel/Fulltext/Collection/SearchResultApplier.php
index 36e0a85fa4307..49676b7c3b208 100644
--- a/vendor/magento/module-catalog-search/Model/ResourceModel/Fulltext/Collection/SearchResultApplier.php
+++ b/vendor/magento/module-catalog-search/Model/ResourceModel/Fulltext/Collection/SearchResultApplier.php
@@ -27,24 +27,16 @@ class SearchResultApplier implements SearchResultApplierInterface
*/
private $searchResult;
- /**
- * @var array
- */
- private $orders;
-
/**
* @param Collection $collection
* @param SearchResultInterface $searchResult
- * @param array $orders
*/
public function __construct(
Collection $collection,
- SearchResultInterface $searchResult,
- array $orders
+ SearchResultInterface $searchResult
) {
$this->collection = $collection;
$this->searchResult = $searchResult;
- $this->orders = $orders;
}
/**
@@ -56,18 +48,16 @@ public function apply()
$this->collection->getSelect()->where('NULL');
return;
}
+
$ids = [];
foreach ($this->searchResult->getItems() as $item) {
$ids[] = (int)$item->getId();
}
$orderList = implode(',', $ids);
- $this->collection->getSelect()->where('e.entity_id IN (?)', $ids);
-
- if (isset($this->orders['relevance'])) {
- $this->collection->getSelect()
- ->reset(\Magento\Framework\DB\Select::ORDER)
- ->order(new \Magento\Framework\DB\Sql\Expression("FIELD(e.entity_id, $orderList)"));
- }
+ $this->collection->getSelect()
+ ->where('e.entity_id IN (?)', $ids)
+ ->reset(\Magento\Framework\DB\Select::ORDER)
+ ->order(new \Magento\Framework\DB\Sql\Expression("FIELD(e.entity_id, $orderList)"));
}
}
diff --git a/vendor/magento/module-elasticsearch/Model/Adapter/BatchDataMapper/ProductDataMapper.php b/vendor/magento/module-elasticsearch/Model/Adapter/BatchDataMapper/ProductDataMapper.php
index c1772086d7ba3..6289ec15456d1 100644
--- a/vendor/magento/module-elasticsearch/Model/Adapter/BatchDataMapper/ProductDataMapper.php
+++ b/vendor/magento/module-elasticsearch/Model/Adapter/BatchDataMapper/ProductDataMapper.php
@@ -313,7 +313,7 @@ function (string $valueId) {
&& in_array($attribute->getAttributeCode(), $this->sortableAttributesValuesToImplode)
&& count($attributeValues) > 1
) {
- $attributeValues = [$productId => implode(' ', $attributeValues)];
+ $attributeValues = [$productId => implode("\n", $attributeValues)];
}
if (in_array($attribute->getAttributeCode(), $this->sortableCaseSensitiveAttributes)) {
diff --git a/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort.php b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort.php
index 7d41d54fb22a5..9721c66522086 100644
--- a/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort.php
+++ b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort.php
@@ -7,9 +7,7 @@
namespace Magento\Elasticsearch\SearchAdapter\Query\Builder;
use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\AttributeProvider;
-use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProvider\FieldName\ResolverInterface
- as FieldNameResolver;
-use Magento\Elasticsearch\Model\Adapter\FieldMapperInterface;
+use Magento\Elasticsearch\SearchAdapter\Query\Builder\Sort\ExpressionBuilderInterface as SortExpressionBuilder;
use Magento\Framework\Search\RequestInterface;
/**
@@ -17,56 +15,26 @@
*/
class Sort
{
- /**
- * List of fields that need to skipp by default.
- */
- private const DEFAULT_SKIPPED_FIELDS = [
- 'entity_id',
- ];
-
- /**
- * Default mapping for special fields.
- */
- private const DEFAULT_MAP = [
- 'relevance' => '_score',
- ];
-
/**
* @var AttributeProvider
*/
private $attributeAdapterProvider;
/**
- * @var FieldNameResolver
- */
- private $fieldNameResolver;
-
- /**
- * @var array
+ * @var SortExpressionBuilder
*/
- private $skippedFields;
-
- /**
- * @var array
- */
- private $map;
+ private $sortExpressionBuilder;
/**
* @param AttributeProvider $attributeAdapterProvider
- * @param FieldNameResolver $fieldNameResolver
- * @param array $skippedFields
- * @param array $map
+ * @param SortExpressionBuilder $sortExpressionBuilder
*/
public function __construct(
AttributeProvider $attributeAdapterProvider,
- FieldNameResolver $fieldNameResolver,
- array $skippedFields = [],
- array $map = []
+ SortExpressionBuilder $sortExpressionBuilder
) {
$this->attributeAdapterProvider = $attributeAdapterProvider;
- $this->fieldNameResolver = $fieldNameResolver;
- $this->skippedFields = array_merge(self::DEFAULT_SKIPPED_FIELDS, $skippedFields);
- $this->map = array_merge(self::DEFAULT_MAP, $map);
+ $this->sortExpressionBuilder = $sortExpressionBuilder;
}
/**
@@ -74,9 +42,6 @@ public function __construct(
*
* @param RequestInterface $request
* @return array
- *
- * @SuppressWarnings(PHPMD.CyclomaticComplexity)
- * @SuppressWarnings(PHPMD.NPathComplexity)
*/
public function getSort(RequestInterface $request)
{
@@ -88,38 +53,11 @@ public function getSort(RequestInterface $request)
if (!method_exists($request, 'getSort')) {
return $sorts;
}
+
foreach ($request->getSort() as $item) {
- if (in_array($item['field'], $this->skippedFields)) {
- continue;
- }
$attribute = $this->attributeAdapterProvider->getByAttributeCode((string)$item['field']);
- $fieldName = $this->fieldNameResolver->getFieldName($attribute);
- if (isset($this->map[$fieldName])) {
- $fieldName = $this->map[$fieldName];
- }
- if ($attribute->isSortable() &&
- !$attribute->isComplexType() &&
- !($attribute->isFloatType() || $attribute->isIntegerType())
- ) {
- $suffix = $this->fieldNameResolver->getFieldName(
- $attribute,
- ['type' => FieldMapperInterface::TYPE_SORT]
- );
- $fieldName .= '.' . $suffix;
- }
- if ($attribute->isComplexType() && $attribute->isSortable()) {
- $fieldName .= '_value';
- $suffix = $this->fieldNameResolver->getFieldName(
- $attribute,
- ['type' => FieldMapperInterface::TYPE_SORT]
- );
- $fieldName .= '.' . $suffix;
- }
- $sorts[] = [
- $fieldName => [
- 'order' => strtolower($item['direction'] ?? '')
- ]
- ];
+ $direction = strtolower($item['direction'] ?? '');
+ $sorts[] = $this->sortExpressionBuilder->build($attribute, $direction, $request);
}
return $sorts;
diff --git a/vendor/magento/module-elasticsearch/etc/di.xml b/vendor/magento/module-elasticsearch/etc/di.xml
index ef917e5492097..24351f5348641 100644
--- a/vendor/magento/module-elasticsearch/etc/di.xml
+++ b/vendor/magento/module-elasticsearch/etc/di.xml
@@ -398,4 +398,24 @@
+
+
+ Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProvider\FieldName\Resolver\Position
+
+
+
+
+ Magento\Elasticsearch\SearchAdapter\Query\Builder\Sort\DefaultExpression
+
+ - Magento\Elasticsearch\SearchAdapter\Query\Builder\Sort\EntityId
+ - Magento\Elasticsearch\SearchAdapter\Query\Builder\Sort\Relevance
+ - Magento\Elasticsearch\SearchAdapter\Query\Builder\Sort\Position
+
+
+
+
+
+ Magento\Elasticsearch\SearchAdapter\Query\Builder\Sort\ExpressionBuilder
+
+
diff --git a/vendor/magento/module-elasticsearch-7/Model/Client/Elasticsearch.php b/vendor/magento/module-elasticsearch-7/Model/Client/Elasticsearch.php
index dd41d6e56a019..5180b5f975ba2 100644
--- a/vendor/magento/module-elasticsearch-7/Model/Client/Elasticsearch.php
+++ b/vendor/magento/module-elasticsearch-7/Model/Client/Elasticsearch.php
@@ -381,4 +381,26 @@ private function applyFieldsMappingPreprocessors(array $properties): array
}
return $properties;
}
+
+ /**
+ * Open point in time
+ *
+ * @param array $params
+ * @return array
+ */
+ public function openPointInTime(array $params = []): array
+ {
+ return $this->getElasticsearchClient()->openPointInTime($params);
+ }
+
+ /**
+ * Close point in time
+ *
+ * @param array $params
+ * @return array
+ */
+ public function closePointInTime(array $params = []): array
+ {
+ return $this->getElasticsearchClient()->closePointInTime($params);
+ }
}
diff --git a/vendor/magento/module-elasticsearch-7/SearchAdapter/Adapter.php b/vendor/magento/module-elasticsearch-7/SearchAdapter/Adapter.php
index 41f8178bd9fac..08fd835b287df 100644
--- a/vendor/magento/module-elasticsearch-7/SearchAdapter/Adapter.php
+++ b/vendor/magento/module-elasticsearch-7/SearchAdapter/Adapter.php
@@ -7,10 +7,12 @@
namespace Magento\Elasticsearch7\SearchAdapter;
+use Magento\Elasticsearch7\Model\Client\Elasticsearch as ElasticsearchClient;
use Magento\Elasticsearch\SearchAdapter\Aggregation\Builder as AggregationBuilder;
use Magento\Elasticsearch\SearchAdapter\ConnectionManager;
use Magento\Elasticsearch\SearchAdapter\QueryContainerFactory;
use Magento\Elasticsearch\SearchAdapter\ResponseFactory;
+use Magento\Search\Model\Search\PageSizeProvider;
use Magento\Framework\Search\AdapterInterface;
use Magento\Framework\Search\RequestInterface;
use Magento\Framework\Search\Response\QueryResponse;
@@ -24,8 +26,6 @@
class Adapter implements AdapterInterface
{
/**
- * Mapper instance
- *
* @var Mapper
*/
private $mapper;
@@ -73,6 +73,11 @@ class Adapter implements AdapterInterface
*/
private $logger;
+ /**
+ * @var PageSizeProvider
+ */
+ private $pageSizeProvider;
+
/**
* @param ConnectionManager $connectionManager
* @param Mapper $mapper
@@ -80,6 +85,7 @@ class Adapter implements AdapterInterface
* @param AggregationBuilder $aggregationBuilder
* @param QueryContainerFactory $queryContainerFactory
* @param LoggerInterface $logger
+ * @param PageSizeProvider $pageSizeProvider
*/
public function __construct(
ConnectionManager $connectionManager,
@@ -87,7 +93,8 @@ public function __construct(
ResponseFactory $responseFactory,
AggregationBuilder $aggregationBuilder,
QueryContainerFactory $queryContainerFactory,
- LoggerInterface $logger
+ LoggerInterface $logger,
+ PageSizeProvider $pageSizeProvider
) {
$this->connectionManager = $connectionManager;
$this->mapper = $mapper;
@@ -95,6 +102,7 @@ public function __construct(
$this->aggregationBuilder = $aggregationBuilder;
$this->queryContainerFactory = $queryContainerFactory;
$this->logger = $logger;
+ $this->pageSizeProvider = $pageSizeProvider;
}
/**
@@ -105,27 +113,56 @@ public function __construct(
*/
public function query(RequestInterface $request) : QueryResponse
{
+ /** @var ElasticsearchClient $client */
$client = $this->connectionManager->getConnection();
- $aggregationBuilder = $this->aggregationBuilder;
- $query = $this->mapper->buildQuery($request);
- $aggregationBuilder->setQuery($this->queryContainerFactory->create(['query' => $query]));
+ $query = $this->mapper->buildQuery($request);
try {
+ $maxPageSize = $this->pageSizeProvider->getMaxPageSize();
+ if ($request->getFrom() + $request->getSize() > $maxPageSize) {
+ $pit = $client->openPointInTime(
+ [
+ 'index' => $query['index'],
+ 'keep_alive' => '1m',
+ ]
+ );
+ $query['body']['pit'] = $pit;
+ unset($query['index']);
+
+ $query['body']['from'] = 0;
+ $processed = 0;
+ while ($processed < $request->getFrom()) {
+ $query['body']['size'] = min($request->getFrom() - $processed, $maxPageSize);
+ $processed += $query['body']['size'];
+ $rawResponse = $client->query($query);
+ $lastHit = end($rawResponse['hits']['hits']);
+ $query['body']['search_after'] = $lastHit['sort'];
+ }
+ $query['body']['size'] = $request->getSize();
+ }
+
$rawResponse = $client->query($query);
} catch (\Exception $e) {
$this->logger->critical($e);
// return empty search result in case an exception is thrown from Elasticsearch
$rawResponse = self::$emptyRawResponse;
+ } finally {
+ if (isset($pit)) {
+ $client->closePointInTime(['body' => $pit]);
+ }
}
$rawDocuments = $rawResponse['hits']['hits'] ?? [];
+ $this->aggregationBuilder->setQuery($this->queryContainerFactory->create(['query' => $query]));
+ $aggregations = $this->aggregationBuilder->build($request, $rawResponse);
$queryResponse = $this->responseFactory->create(
[
'documents' => $rawDocuments,
- 'aggregations' => $aggregationBuilder->build($request, $rawResponse),
+ 'aggregations' => $aggregations,
'total' => $rawResponse['hits']['total']['value'] ?? 0
]
);
+
return $queryResponse;
}
}
diff --git a/vendor/magento/module-open-search/Model/SearchClient.php b/vendor/magento/module-open-search/Model/SearchClient.php
index dbce79c2496bb..beb525482f3da 100644
--- a/vendor/magento/module-open-search/Model/SearchClient.php
+++ b/vendor/magento/module-open-search/Model/SearchClient.php
@@ -378,4 +378,26 @@ public function applyFieldsMappingPreprocessors(array $properties): array
}
return $properties;
}
+
+ /**
+ * Open point in time
+ *
+ * @param array $params
+ * @return array
+ */
+ public function openPointInTime(array $params = []): array
+ {
+ return $this->getOpenSearchClient()->createPointInTime($params);
+ }
+
+ /**
+ * Close point in time
+ *
+ * @param array $params
+ * @return array
+ */
+ public function closePointInTime(array $params = []): array
+ {
+ return $this->getOpenSearchClient()->deletePointInTime($params);
+ }
}
diff --git a/vendor/magento/module-open-search/SearchAdapter/Adapter.php b/vendor/magento/module-open-search/SearchAdapter/Adapter.php
index 03fb9977b0d25..d0b2a8fc767ac 100644
--- a/vendor/magento/module-open-search/SearchAdapter/Adapter.php
+++ b/vendor/magento/module-open-search/SearchAdapter/Adapter.php
@@ -14,6 +14,7 @@
use Magento\Framework\Search\AdapterInterface;
use Magento\Framework\Search\RequestInterface;
use Magento\Framework\Search\Response\QueryResponse;
+use Magento\Search\Model\Search\PageSizeProvider;
use Psr\Log\LoggerInterface;
/**
@@ -70,6 +71,11 @@ class Adapter implements AdapterInterface
*/
private $logger;
+ /**
+ * @var PageSizeProvider
+ */
+ private $pageSizeProvider;
+
/**
* @param ConnectionManager $connectionManager
* @param Mapper $mapper
@@ -77,6 +83,7 @@ class Adapter implements AdapterInterface
* @param AggregationBuilder $aggregationBuilder
* @param QueryContainerFactory $queryContainerFactory
* @param LoggerInterface $logger
+ * @param PageSizeProvider $pageSizeProvider
*/
public function __construct(
ConnectionManager $connectionManager,
@@ -84,7 +91,8 @@ public function __construct(
ResponseFactory $responseFactory,
AggregationBuilder $aggregationBuilder,
QueryContainerFactory $queryContainerFactory,
- LoggerInterface $logger
+ LoggerInterface $logger,
+ PageSizeProvider $pageSizeProvider
) {
$this->connectionManager = $connectionManager;
$this->mapper = $mapper;
@@ -92,6 +100,7 @@ public function __construct(
$this->aggregationBuilder = $aggregationBuilder;
$this->queryContainerFactory = $queryContainerFactory;
$this->logger = $logger;
+ $this->pageSizeProvider = $pageSizeProvider;
}
/**
@@ -103,23 +112,54 @@ public function __construct(
public function query(RequestInterface $request) : QueryResponse
{
$client = $this->connectionManager->getConnection();
- $aggregationBuilder = $this->aggregationBuilder;
+
$query = $this->mapper->buildQuery($request);
- $aggregationBuilder->setQuery($this->queryContainerFactory->create(['query' => $query]));
try {
+ $maxPageSize = $this->pageSizeProvider->getMaxPageSize();
+ if ($request->getFrom() + $request->getSize() > $maxPageSize) {
+ $pit = $client->openPointInTime(
+ [
+ 'index' => $query['index'],
+ 'keep_alive' => '1m',
+ ]
+ );
+ $pitId = $pit['pit_id'];
+ $query['body']['pit'] = [
+ 'id' => $pitId,
+ ];
+ unset($query['index']);
+
+ $query['body']['from'] = 0;
+ $processed = 0;
+ while ($processed < $request->getFrom()) {
+ $query['body']['size'] = min($request->getFrom() - $processed, $maxPageSize);
+ $processed += $query['body']['size'];
+ $rawResponse = $client->query($query);
+ $lastHit = end($rawResponse['hits']['hits']);
+ $query['body']['search_after'] = $lastHit['sort'];
+ }
+ $query['body']['size'] = $request->getSize();
+ }
+
$rawResponse = $client->query($query);
} catch (\Exception $e) {
$this->logger->critical($e);
// return empty search result in case an exception is thrown from OpenSearch
$rawResponse = self::$emptyRawResponse;
+ } finally {
+ if (isset($pitId)) {
+ $client->closePointInTime(['body' => ['pit_id' => [$pitId]]]);
+ }
}
$rawDocuments = $rawResponse['hits']['hits'] ?? [];
+ $this->aggregationBuilder->setQuery($this->queryContainerFactory->create(['query' => $query]));
+ $aggregations = $this->aggregationBuilder->build($request, $rawResponse);
$queryResponse = $this->responseFactory->create(
[
'documents' => $rawDocuments,
- 'aggregations' => $aggregationBuilder->build($request, $rawResponse),
+ 'aggregations' => $aggregations,
'total' => $rawResponse['hits']['total']['value'] ?? 0
]
);
From 268f35af6ea2e6b15d0eb7f40e67ffdcefa295d2 Mon Sep 17 00:00:00 2001
From: awijesooriya
Date: Sat, 5 Oct 2024 11:31:57 +1000
Subject: [PATCH 2/4] ACSD-62272: Catalog Service Adapter returns a different
result from Catalog Service - backported ACP2E-948
[https://github.com/magento-l3/magento2ce/pull/801] fixes to Magento version
2.4.7
---
.../Query/Builder/Sort/DefaultExpression.php | 60 ++++++++++++
.../Query/Builder/Sort/EntityId.php | 31 ++++++
.../Query/Builder/Sort/ExpressionBuilder.php | 46 +++++++++
.../Sort/ExpressionBuilderInterface.php | 24 +++++
.../Query/Builder/Sort/Position.php | 95 +++++++++++++++++++
.../Query/Builder/Sort/Relevance.php | 24 +++++
6 files changed, 280 insertions(+)
create mode 100644 app/code/Magento/Elasticsearch/SearchAdapter/Query/Builder/Sort/DefaultExpression.php
create mode 100644 app/code/Magento/Elasticsearch/SearchAdapter/Query/Builder/Sort/EntityId.php
create mode 100644 app/code/Magento/Elasticsearch/SearchAdapter/Query/Builder/Sort/ExpressionBuilder.php
create mode 100644 app/code/Magento/Elasticsearch/SearchAdapter/Query/Builder/Sort/ExpressionBuilderInterface.php
create mode 100644 app/code/Magento/Elasticsearch/SearchAdapter/Query/Builder/Sort/Position.php
create mode 100644 app/code/Magento/Elasticsearch/SearchAdapter/Query/Builder/Sort/Relevance.php
diff --git a/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/DefaultExpression.php b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/DefaultExpression.php
new file mode 100644
index 0000000000000..f7d19a02d23a1
--- /dev/null
+++ b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/DefaultExpression.php
@@ -0,0 +1,60 @@
+fieldNameResolver = $fieldNameResolver;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function build(AttributeAdapter $attribute, string $direction, RequestInterface $request): array
+ {
+ $fieldName = $this->fieldNameResolver->getFieldName($attribute);
+ if ($attribute->isSortable() &&
+ !$attribute->isComplexType() &&
+ !($attribute->isFloatType() || $attribute->isIntegerType())
+ ) {
+ $suffix = $this->fieldNameResolver->getFieldName(
+ $attribute,
+ ['type' => FieldMapperInterface::TYPE_SORT]
+ );
+ $fieldName .= '.' . $suffix;
+ }
+ if ($attribute->isComplexType() && $attribute->isSortable()) {
+ $fieldName .= '_value';
+ $suffix = $this->fieldNameResolver->getFieldName(
+ $attribute,
+ ['type' => FieldMapperInterface::TYPE_SORT]
+ );
+ $fieldName .= '.' . $suffix;
+ }
+
+ return [
+ $fieldName => ['order' => $direction],
+ ];
+ }
+}
diff --git a/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/EntityId.php b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/EntityId.php
new file mode 100644
index 0000000000000..f0a3b08547701
--- /dev/null
+++ b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/EntityId.php
@@ -0,0 +1,31 @@
+ [
+ 'type' => 'number',
+ 'script' => [
+ 'lang' => 'painless',
+ 'source' => 'Long.parseLong(doc[\'_id\'].value)',
+ ],
+ 'order' => $direction,
+ ],
+ ];
+ }
+}
diff --git a/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/ExpressionBuilder.php b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/ExpressionBuilder.php
new file mode 100644
index 0000000000000..f9f1c8a965cda
--- /dev/null
+++ b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/ExpressionBuilder.php
@@ -0,0 +1,46 @@
+defaultExpressionBuilder = $defaultExpressionBuilder;
+ $this->customExpressionBuilders = $customExpressionBuilders;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function build(AttributeAdapter $attribute, string $direction, RequestInterface $request): array
+ {
+ return isset($this->customExpressionBuilders[$attribute->getAttributeCode()])
+ ? $this->customExpressionBuilders[$attribute->getAttributeCode()]->build($attribute, $direction, $request)
+ : $this->defaultExpressionBuilder->build($attribute, $direction, $request);
+ }
+}
diff --git a/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/ExpressionBuilderInterface.php b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/ExpressionBuilderInterface.php
new file mode 100644
index 0000000000000..50314b5dcd764
--- /dev/null
+++ b/vendor/magento/module-elasticsearch/SearchAdapter/Query/Builder/Sort/ExpressionBuilderInterface.php
@@ -0,0 +1,24 @@
+fieldNameResolver = $fieldNameResolver;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function build(AttributeAdapter $attribute, string $direction, RequestInterface $request): array
+ {
+ $sortParams = ['order' => $direction];
+
+ $categoryIds = $this->getCategoryIdsFromQuery($request->getQuery());
+ if (count($categoryIds) > 1) {
+ $fieldNames = [];
+ foreach ($categoryIds as $categoryId) {
+ $fieldNames[] = $this->fieldNameResolver->getFieldName($attribute, ['categoryId' => $categoryId]);
+ }
+ $fieldName = '_script';
+ $sortParams += [
+ 'type' => 'number',
+ 'script' => [
+ 'lang' => 'painless',
+ 'source' => <<