Skip to content

Commit 259c03a

Browse files
committed
MC-31304: [ElasticSearch] Exception on catalog search result page
1 parent e0ccc3c commit 259c03a

File tree

9 files changed

+170
-84
lines changed

9 files changed

+170
-84
lines changed

app/code/Magento/Elasticsearch/Model/Adapter/Elasticsearch.php

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
namespace Magento\Elasticsearch\Model\Adapter;
88

9+
use Magento\Catalog\Api\Data\ProductAttributeInterface;
10+
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
11+
use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProvider\StaticField;
912
use Magento\Framework\App\ObjectManager;
1013
use Magento\Framework\Stdlib\ArrayManager;
1114

@@ -82,6 +85,16 @@ class Elasticsearch
8285
*/
8386
private $indexByCode = [];
8487

88+
/**
89+
* @var ProductAttributeRepositoryInterface
90+
*/
91+
private $productAttributeRepository;
92+
93+
/**
94+
* @var StaticField
95+
*/
96+
private $staticFieldProvider;
97+
8598
/**
8699
* @var ArrayManager
87100
*/
@@ -96,8 +109,11 @@ class Elasticsearch
96109
* @param Index\IndexNameResolver $indexNameResolver
97110
* @param BatchDataMapperInterface $batchDocumentDataMapper
98111
* @param array $options
112+
* @param ProductAttributeRepositoryInterface|null $productAttributeRepository
113+
* @param StaticField|null $staticFieldProvider
99114
* @param ArrayManager|null $arrayManager
100115
* @throws \Magento\Framework\Exception\LocalizedException
116+
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
101117
*/
102118
public function __construct(
103119
\Magento\Elasticsearch\SearchAdapter\ConnectionManager $connectionManager,
@@ -108,6 +124,8 @@ public function __construct(
108124
\Magento\Elasticsearch\Model\Adapter\Index\IndexNameResolver $indexNameResolver,
109125
BatchDataMapperInterface $batchDocumentDataMapper,
110126
$options = [],
127+
ProductAttributeRepositoryInterface $productAttributeRepository = null,
128+
StaticField $staticFieldProvider = null,
111129
ArrayManager $arrayManager = null
112130
) {
113131
$this->connectionManager = $connectionManager;
@@ -117,6 +135,10 @@ public function __construct(
117135
$this->logger = $logger;
118136
$this->indexNameResolver = $indexNameResolver;
119137
$this->batchDocumentDataMapper = $batchDocumentDataMapper;
138+
$this->productAttributeRepository = $productAttributeRepository ?:
139+
ObjectManager::getInstance()->get(ProductAttributeRepositoryInterface::class);
140+
$this->staticFieldProvider = $staticFieldProvider ?:
141+
ObjectManager::getInstance()->get(StaticField::class);
120142
$this->arrayManager = $arrayManager ?:
121143
ObjectManager::getInstance()->get(ArrayManager::class);
122144

@@ -355,25 +377,25 @@ public function updateAlias($storeId, $mappedIndexerId)
355377
*
356378
* @param int $storeId
357379
* @param string $mappedIndexerId
358-
*
380+
* @param string $attributeCode
359381
* @return $this
360382
*/
361-
public function updateIndexMapping(int $storeId, string $mappedIndexerId): self
383+
public function updateIndexMapping(int $storeId, string $mappedIndexerId, string $attributeCode): self
362384
{
363385
$indexName = $this->getIndexFromAlias($storeId, $mappedIndexerId);
364386
if (empty($indexName)) {
365387
return $this;
366388
}
367389

368-
$allAttributeTypes = $this->fieldMapper->getAllAttributesTypes([
369-
'entityType' => $mappedIndexerId,
370-
'websiteId' => $storeId,
371-
]);
390+
/** @var ProductAttributeInterface $attribute */
391+
$attribute = $this->productAttributeRepository->get($attributeCode);
392+
$newAttributeMapping = $this->staticFieldProvider->getField($attribute);
393+
$mappedAttributes = $this->getMappedAttributes($indexName);
372394

373-
$attrToUpdate = array_diff_key($allAttributeTypes, $this->getMappedAttributes($indexName));
395+
$attrToUpdate = array_diff_key($newAttributeMapping, $mappedAttributes);
374396
if (!empty($attrToUpdate)) {
375397
$settings['index']['mapping']['total_fields']['limit'] = $this
376-
->getMappingTotalFieldsLimit($allAttributeTypes);
398+
->getMappingTotalFieldsLimit(array_merge($mappedAttributes, $attrToUpdate));
377399
$this->client->putIndexSettings($indexName, ['settings' => $settings]);
378400

379401
$this->client->addFieldsMapping(

app/code/Magento/Elasticsearch/Model/Adapter/FieldMapper/Product/FieldProvider/StaticField.php

Lines changed: 68 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -105,71 +105,87 @@ public function __construct(
105105
*/
106106
public function getFields(array $context = []): array
107107
{
108+
/** @var ProductAttributeInterface[] $attributes */
108109
$attributes = $this->eavConfig->getEntityAttributes(ProductAttributeInterface::ENTITY_TYPE_CODE);
109110
$allAttributes = [];
110111

111112
foreach ($attributes as $attribute) {
112-
if (in_array($attribute->getAttributeCode(), $this->excludedAttributes, true)) {
113-
continue;
114-
}
115-
$attributeAdapter = $this->attributeAdapterProvider->getByAttributeCode($attribute->getAttributeCode());
116-
$fieldName = $this->fieldNameResolver->getFieldName($attributeAdapter);
113+
$allAttributes += $this->getField($attribute);
114+
}
117115

118-
$allAttributes[$fieldName] = [
119-
'type' => $this->fieldTypeResolver->getFieldType($attributeAdapter),
120-
];
116+
$allAttributes['store_id'] = [
117+
'type' => $this->fieldTypeConverter->convert(FieldTypeConverterInterface::INTERNAL_DATA_TYPE_STRING),
118+
'index' => $this->indexTypeConverter->convert(IndexTypeConverterInterface::INTERNAL_NO_INDEX_VALUE),
119+
];
121120

122-
$index = $this->fieldIndexResolver->getFieldIndex($attributeAdapter);
123-
if (null !== $index) {
124-
$allAttributes[$fieldName]['index'] = $index;
125-
}
121+
return $allAttributes;
122+
}
126123

127-
if ($attributeAdapter->isSortable()) {
128-
$sortFieldName = $this->fieldNameResolver->getFieldName(
129-
$attributeAdapter,
130-
['type' => FieldMapperInterface::TYPE_SORT]
131-
);
132-
$allAttributes[$fieldName]['fields'][$sortFieldName] = [
133-
'type' => $this->fieldTypeConverter->convert(
134-
FieldTypeConverterInterface::INTERNAL_DATA_TYPE_KEYWORD
135-
),
136-
'index' => $this->indexTypeConverter->convert(
137-
IndexTypeConverterInterface::INTERNAL_NO_ANALYZE_VALUE
138-
)
139-
];
140-
}
124+
/**
125+
* Get field mapping for specific attribute.
126+
*
127+
* @param ProductAttributeInterface $attribute
128+
* @return array
129+
*/
130+
public function getField(ProductAttributeInterface $attribute): array
131+
{
132+
$fieldMapping = [];
133+
if (in_array($attribute->getAttributeCode(), $this->excludedAttributes, true)) {
134+
return $fieldMapping;
135+
}
141136

142-
if ($attributeAdapter->isTextType()) {
143-
$keywordFieldName = FieldTypeConverterInterface::INTERNAL_DATA_TYPE_KEYWORD;
144-
$index = $this->indexTypeConverter->convert(
137+
$attributeAdapter = $this->attributeAdapterProvider->getByAttributeCode($attribute->getAttributeCode());
138+
$fieldName = $this->fieldNameResolver->getFieldName($attributeAdapter);
139+
140+
$fieldMapping[$fieldName] = [
141+
'type' => $this->fieldTypeResolver->getFieldType($attributeAdapter),
142+
];
143+
144+
$index = $this->fieldIndexResolver->getFieldIndex($attributeAdapter);
145+
if (null !== $index) {
146+
$fieldMapping[$fieldName]['index'] = $index;
147+
}
148+
149+
if ($attributeAdapter->isSortable()) {
150+
$sortFieldName = $this->fieldNameResolver->getFieldName(
151+
$attributeAdapter,
152+
['type' => FieldMapperInterface::TYPE_SORT]
153+
);
154+
$fieldMapping[$fieldName]['fields'][$sortFieldName] = [
155+
'type' => $this->fieldTypeConverter->convert(
156+
FieldTypeConverterInterface::INTERNAL_DATA_TYPE_KEYWORD
157+
),
158+
'index' => $this->indexTypeConverter->convert(
145159
IndexTypeConverterInterface::INTERNAL_NO_ANALYZE_VALUE
146-
);
147-
$allAttributes[$fieldName]['fields'][$keywordFieldName] = [
148-
'type' => $this->fieldTypeConverter->convert(
149-
FieldTypeConverterInterface::INTERNAL_DATA_TYPE_KEYWORD
150-
)
151-
];
152-
if ($index) {
153-
$allAttributes[$fieldName]['fields'][$keywordFieldName]['index'] = $index;
154-
}
155-
}
160+
)
161+
];
162+
}
156163

157-
if ($attributeAdapter->isComplexType()) {
158-
$childFieldName = $this->fieldNameResolver->getFieldName(
159-
$attributeAdapter,
160-
['type' => FieldMapperInterface::TYPE_QUERY]
161-
);
162-
$allAttributes[$childFieldName] = [
163-
'type' => $this->fieldTypeConverter->convert(FieldTypeConverterInterface::INTERNAL_DATA_TYPE_STRING)
164-
];
164+
if ($attributeAdapter->isTextType()) {
165+
$keywordFieldName = FieldTypeConverterInterface::INTERNAL_DATA_TYPE_KEYWORD;
166+
$index = $this->indexTypeConverter->convert(
167+
IndexTypeConverterInterface::INTERNAL_NO_ANALYZE_VALUE
168+
);
169+
$fieldMapping[$fieldName]['fields'][$keywordFieldName] = [
170+
'type' => $this->fieldTypeConverter->convert(
171+
FieldTypeConverterInterface::INTERNAL_DATA_TYPE_KEYWORD
172+
)
173+
];
174+
if ($index) {
175+
$fieldMapping[$fieldName]['fields'][$keywordFieldName]['index'] = $index;
165176
}
166177
}
167178

168-
$allAttributes['store_id'] = [
169-
'type' => $this->fieldTypeConverter->convert(FieldTypeConverterInterface::INTERNAL_DATA_TYPE_STRING),
170-
'index' => $this->indexTypeConverter->convert(IndexTypeConverterInterface::INTERNAL_NO_INDEX_VALUE),
171-
];
179+
if ($attributeAdapter->isComplexType()) {
180+
$childFieldName = $this->fieldNameResolver->getFieldName(
181+
$attributeAdapter,
182+
['type' => FieldMapperInterface::TYPE_QUERY]
183+
);
184+
$fieldMapping[$childFieldName] = [
185+
'type' => $this->fieldTypeConverter->convert(FieldTypeConverterInterface::INTERNAL_DATA_TYPE_STRING)
186+
];
187+
}
172188

173-
return $allAttributes;
189+
return $fieldMapping;
174190
}
175191
}

app/code/Magento/Elasticsearch/Model/Indexer/Fulltext/Plugin/Category/Product/Attribute.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ class Attribute
4646
*/
4747
private $isNewObject;
4848

49+
/**
50+
* @var string
51+
*/
52+
private $attributeCode;
53+
4954
/**
5055
* @param Config $config
5156
* @param Processor $indexerProcessor
@@ -89,7 +94,7 @@ public function afterSave(
8994
);
9095
}
9196
foreach ($this->dimensionProvider->getIterator() as $dimension) {
92-
$indexerHandler->updateIndex($dimension);
97+
$indexerHandler->updateIndex($dimension, $this->attributeCode);
9398
}
9499
}
95100

@@ -109,5 +114,6 @@ public function beforeSave(
109114
AbstractModel $attribute
110115
): void {
111116
$this->isNewObject = $attribute->isObjectNew();
117+
$this->attributeCode = $attribute->getAttributeCode();
112118
}
113119
}

app/code/Magento/Elasticsearch/Model/Indexer/IndexerHandler.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,14 @@ public function isAvailable($dimensions = [])
137137
* Update mapping data for index.
138138
*
139139
* @param Dimension[] $dimensions
140+
* @param string $attributeCode
140141
* @return IndexerInterface
141142
*/
142-
public function updateIndex(array $dimensions): IndexerInterface
143+
public function updateIndex(array $dimensions, string $attributeCode): IndexerInterface
143144
{
144145
$dimension = current($dimensions);
145146
$scopeId = (int)$this->scopeResolver->getScope($dimension->getValue())->getId();
146-
$this->adapter->updateIndexMapping($scopeId, $this->getIndexerId());
147+
$this->adapter->updateIndexMapping($scopeId, $this->getIndexerId(), $attributeCode);
147148

148149
return $this;
149150
}

0 commit comments

Comments
 (0)