Skip to content

Commit 53b35ae

Browse files
author
Anna Bukatar
committed
Merge branch 'ACP2E-99' of https://github.com/magento-l3/magento2ce into PR-2022-02-22
2 parents 6be08c2 + d900484 commit 53b35ae

File tree

5 files changed

+237
-34
lines changed

5 files changed

+237
-34
lines changed

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

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
*/
66
namespace Magento\Elasticsearch\Model\Adapter\Index;
77

8+
use Magento\Framework\Exception\LocalizedException;
89
use Magento\Framework\Locale\Resolver as LocaleResolver;
910
use Magento\Elasticsearch\Model\Adapter\Index\Config\EsConfigInterface;
11+
use Magento\Search\Model\ResourceModel\SynonymReader;
1012

1113
/**
1214
* Index Builder
@@ -30,16 +32,24 @@ class Builder implements BuilderInterface
3032
*/
3133
protected $storeId;
3234

35+
/**
36+
* @var SynonymReader
37+
*/
38+
private $synonymReader;
39+
3340
/**
3441
* @param LocaleResolver $localeResolver
3542
* @param EsConfigInterface $esConfig
43+
* @param SynonymReader $synonymReader
3644
*/
3745
public function __construct(
3846
LocaleResolver $localeResolver,
39-
EsConfigInterface $esConfig
47+
EsConfigInterface $esConfig,
48+
SynonymReader $synonymReader
4049
) {
4150
$this->localeResolver = $localeResolver;
4251
$this->esConfig = $esConfig;
52+
$this->synonymReader = $synonymReader;
4353
}
4454

4555
/**
@@ -50,6 +60,7 @@ public function build()
5060
$tokenizer = $this->getTokenizer();
5161
$filter = $this->getFilter();
5262
$charFilter = $this->getCharFilter();
63+
$synonymFilter = $this->getSynonymFilter();
5364

5465
$settings = [
5566
'analysis' => [
@@ -67,7 +78,10 @@ public function build()
6778
'prefix_search' => [
6879
'type' => 'custom',
6980
'tokenizer' => key($tokenizer),
70-
'filter' => ['lowercase', 'asciifolding'],
81+
'filter' => array_merge(
82+
['lowercase', 'asciifolding'],
83+
array_keys($synonymFilter)
84+
),
7185
'char_filter' => array_keys($charFilter)
7286
],
7387
'sku' => [
@@ -82,11 +96,14 @@ public function build()
8296
'sku_prefix_search' => [
8397
'type' => 'custom',
8498
'tokenizer' => 'keyword',
85-
'filter' => ['lowercase', 'asciifolding']
99+
'filter' => array_merge(
100+
['lowercase', 'asciifolding'],
101+
array_keys($synonymFilter)
102+
),
86103
]
87104
],
88105
'tokenizer' => $tokenizer,
89-
'filter' => $filter,
106+
'filter' => array_merge($filter, $synonymFilter),
90107
'char_filter' => $charFilter,
91108
],
92109
];
@@ -170,4 +187,26 @@ protected function getStemmerConfig()
170187
'language' => $stemmerInfo['default'],
171188
];
172189
}
190+
191+
/**
192+
* Get filter based on defined synonyms
193+
*
194+
* @throws LocalizedException
195+
*/
196+
private function getSynonymFilter(): array
197+
{
198+
$synonyms = $this->synonymReader->getAllSynonyms();
199+
$synonymFilter = [];
200+
201+
if ($synonyms) {
202+
$synonymFilter = [
203+
'synonyms' => [
204+
'type' => 'synonym_graph',
205+
'synonyms' => $synonyms
206+
]
207+
];
208+
}
209+
210+
return $synonymFilter;
211+
}
173212
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\Elasticsearch\Model\Indexer\Fulltext\Plugin\Search\Model;
10+
11+
use Magento\CatalogSearch\Model\Indexer\Fulltext;
12+
use Magento\Framework\Indexer\IndexerRegistry;
13+
use Magento\Framework\Model\ResourceModel\Db\AbstractDb;
14+
use Magento\Search\Model\ResourceModel\SynonymGroup;
15+
16+
class SynonymReaderPlugin
17+
{
18+
/**
19+
* @var IndexerRegistry
20+
*/
21+
private $indexerRegistry;
22+
23+
/**
24+
* @param IndexerRegistry $indexerRegistry
25+
*/
26+
public function __construct(IndexerRegistry $indexerRegistry)
27+
{
28+
$this->indexerRegistry = $indexerRegistry;
29+
}
30+
31+
/**
32+
* Invalidate fulltext index after synonyms create/ update
33+
*
34+
* @param SynonymGroup $subject
35+
* @param AbstractDb $synonymGroup
36+
* @return void
37+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
38+
*/
39+
public function afterSave(SynonymGroup $subject, AbstractDb $synonymGroup)
40+
{
41+
$this->invalidateIndexer();
42+
}
43+
44+
/**
45+
* Invalidate fulltext index after synonyms delete
46+
*
47+
* @param SynonymGroup $subject
48+
* @param AbstractDb $synonymGroup
49+
* @return void
50+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
51+
*/
52+
public function afterDelete(SynonymGroup $subject, AbstractDb $synonymGroup)
53+
{
54+
$this->invalidateIndexer();
55+
}
56+
57+
/**
58+
* Invalidate fulltext indexer
59+
*
60+
* @return void
61+
*/
62+
private function invalidateIndexer()
63+
{
64+
$fulltextIndexer = $this->indexerRegistry->get(Fulltext::INDEXER_ID);
65+
$fulltextIndexer->invalidate();
66+
}
67+
}

app/code/Magento/Elasticsearch/Test/Unit/Model/Adapter/Index/BuilderTest.php

Lines changed: 110 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Magento\Elasticsearch\Model\Adapter\Index\Config\EsConfigInterface;
1212
use Magento\Framework\Locale\Resolver as LocaleResolver;
1313
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
14+
use Magento\Search\Model\ResourceModel\SynonymReader;
1415
use PHPUnit\Framework\MockObject\MockObject;
1516
use PHPUnit\Framework\TestCase;
1617

@@ -19,17 +20,22 @@ class BuilderTest extends TestCase
1920
/**
2021
* @var Builder
2122
*/
22-
protected $model;
23+
private $model;
2324

2425
/**
2526
* @var LocaleResolver|MockObject
2627
*/
27-
protected $localeResolver;
28+
private $localeResolver;
2829

2930
/**
3031
* @var EsConfigInterface|MockObject
3132
*/
32-
protected $esConfig;
33+
private $esConfig;
34+
35+
/**
36+
* @var SynonymReader|MockObject
37+
*/
38+
private $synonymReaderMock;
3339

3440
/**
3541
* Setup method
@@ -44,53 +50,138 @@ protected function setUp(): void
4450
'getLocale'
4551
])
4652
->getMock();
53+
4754
$this->esConfig = $this->getMockBuilder(
4855
EsConfigInterface::class
4956
)
5057
->disableOriginalConstructor()
5158
->getMock();
5259

60+
$this->synonymReaderMock = $this->getMockBuilder(
61+
SynonymReader::class
62+
)
63+
->disableOriginalConstructor()
64+
->getMock();
65+
66+
$this->esConfig->expects($this->once())
67+
->method('getStemmerInfo')
68+
->willReturn([
69+
'type' => 'stemmer',
70+
'default' => 'english',
71+
'en_US' => 'english',
72+
]);
73+
5374
$objectManager = new ObjectManagerHelper($this);
5475
$this->model = $objectManager->getObject(
5576
Builder::class,
5677
[
5778
'localeResolver' => $this->localeResolver,
58-
'esConfig' => $this->esConfig
79+
'esConfig' => $this->esConfig,
80+
'synonymReader' => $this->synonymReaderMock
5981
]
6082
);
6183
}
6284

6385
/**
64-
* Test build() method
86+
* Test build() method without provided synonyms.
87+
*
88+
* In this case, synonyms filter must not be created or referenced
89+
* in the prefix_search and sku_prefix_search analyzers.
6590
*
6691
* @param string $locale
6792
* @dataProvider buildDataProvider
6893
*/
69-
public function testBuild($locale)
94+
public function testBuildWithoutSynonymsProvided(string $locale)
7095
{
96+
$synonymsFilterName = 'synonyms';
97+
7198
$this->localeResolver->expects($this->once())
7299
->method('getLocale')
73100
->willReturn($locale);
74-
75-
$this->esConfig->expects($this->once())
76-
->method('getStemmerInfo')
77-
->willReturn([
78-
'type' => 'stemmer',
79-
'default' => 'english',
80-
'en_US' => 'english',
81-
]);
101+
$this->synonymReaderMock->expects($this->once())
102+
->method('getAllSynonyms')
103+
->willReturn([]);
82104

83105
$result = $this->model->build();
84-
$this->assertNotNull($result);
106+
107+
$analysisFilters = $result["analysis"]["filter"];
108+
$prefixSearchAnalyzerFilters = $result["analysis"]["analyzer"]["prefix_search"]["filter"];
109+
$skuPrefixSearchAnalyzerFilters = $result["analysis"]["analyzer"]["sku_prefix_search"]["filter"];
110+
111+
$this->assertArrayNotHasKey(
112+
$synonymsFilterName,
113+
$analysisFilters,
114+
'Analysis filters must not contain synonyms when they are not defined'
115+
);
116+
$this->assertNotContains(
117+
$synonymsFilterName,
118+
$prefixSearchAnalyzerFilters,
119+
'The prefix_search analyzer must not include synonyms filter when it is not present'
120+
);
121+
$this->assertNotContains(
122+
$synonymsFilterName,
123+
$skuPrefixSearchAnalyzerFilters,
124+
'The sku_prefix_search analyzer must include synonyms filter when it is not present'
125+
);
85126
}
86127

87128
/**
88-
* Test setStoreId() method
129+
* Test build() method with synonyms provided.
130+
*
131+
* In this case synonyms filter should be created, populated with the list of available synonyms
132+
* and referenced in the prefix_search and sku_prefix_search analyzers.
133+
*
134+
* @param string $locale
135+
* @dataProvider buildDataProvider
89136
*/
90-
public function testSetStoreId()
137+
public function testBuildWithProvidedSynonyms(string $locale)
91138
{
92-
$result = $this->model->setStoreId(1);
93-
$this->assertNull($result);
139+
$synonymsFilterName = 'synonyms';
140+
141+
$synonyms = [
142+
'mp3,player,sound,audio',
143+
'tv,video,television,screen'
144+
];
145+
146+
$expectedFilter = [
147+
'type' => 'synonym_graph',
148+
'synonyms' => $synonyms
149+
];
150+
151+
$this->localeResolver->expects($this->once())
152+
->method('getLocale')
153+
->willReturn($locale);
154+
155+
$this->synonymReaderMock->expects($this->once())
156+
->method('getAllSynonyms')
157+
->willReturn($synonyms);
158+
159+
$result = $this->model->build();
160+
161+
$analysisFilters = $result["analysis"]["filter"];
162+
$prefixSearchAnalyzerFilters = $result["analysis"]["analyzer"]["prefix_search"]["filter"];
163+
$skuPrefixSearchAnalyzerFilters = $result["analysis"]["analyzer"]["sku_prefix_search"]["filter"];
164+
165+
$this->assertArrayHasKey(
166+
$synonymsFilterName,
167+
$analysisFilters,
168+
'Analysis filters must contain synonyms when defined'
169+
);
170+
$this->assertContains(
171+
$expectedFilter,
172+
$analysisFilters,
173+
'Analysis synonyms filter must match the expected result'
174+
);
175+
$this->assertContains(
176+
$synonymsFilterName,
177+
$prefixSearchAnalyzerFilters,
178+
'The prefix_search analyzer must include synonyms filter'
179+
);
180+
$this->assertContains(
181+
$synonymsFilterName,
182+
$skuPrefixSearchAnalyzerFilters,
183+
'The sku_prefix_search analyzer must include synonyms filter'
184+
);
94185
}
95186

96187
/**

app/code/Magento/Elasticsearch/etc/di.xml

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -304,14 +304,6 @@
304304
<type name="Magento\Framework\Indexer\Config\DependencyInfoProvider">
305305
<plugin name="indexerDependencyUpdaterPlugin" type="Magento\Elasticsearch\Model\Indexer\Plugin\DependencyUpdaterPlugin"/>
306306
</type>
307-
<type name="Magento\Elasticsearch\SearchAdapter\Query\Builder\MatchQuery">
308-
<arguments>
309-
<argument name="preprocessorContainer" xsi:type="array">
310-
<item name="stopwordsPreprocessor" xsi:type="object">Magento\Elasticsearch\SearchAdapter\Query\Preprocessor\Stopwords</item>
311-
<item name="synonymsPreprocessor" xsi:type="object">Magento\Search\Adapter\Query\Preprocessor\Synonyms</item>
312-
</argument>
313-
</arguments>
314-
</type>
315307
<type name="Magento\Elasticsearch\SearchAdapter\Query\Preprocessor\Stopwords">
316308
<arguments>
317309
<argument name="stopwordsModule" xsi:type="string">Magento_Elasticsearch</argument>
@@ -515,7 +507,6 @@
515507
<arguments>
516508
<argument name="preprocessors" xsi:type="array">
517509
<item name="stopwordsPreprocessor" xsi:type="object">Magento\Elasticsearch\SearchAdapter\Query\Preprocessor\Stopwords</item>
518-
<item name="synonymsPreprocessor" xsi:type="object">Magento\Search\Adapter\Query\Preprocessor\Synonyms</item>
519510
</argument>
520511
</arguments>
521512
</type>
@@ -564,6 +555,9 @@
564555
<type name="Magento\Catalog\Model\ResourceModel\Attribute">
565556
<plugin name="updateElasticsearchIndexerMapping" type="Magento\Elasticsearch\Model\Indexer\Fulltext\Plugin\Category\Product\Attribute"/>
566557
</type>
558+
<type name="Magento\Search\Model\ResourceModel\SynonymGroup">
559+
<plugin name="synonymReaderPlugin" type="Magento\Elasticsearch\Model\Indexer\Fulltext\Plugin\Search\Model\SynonymReaderPlugin"/>
560+
</type>
567561
<type name="Magento\Elasticsearch\Model\Indexer\IndexerHandler">
568562
<arguments>
569563
<argument name="cacheContext" xsi:type="object">Magento\Framework\Indexer\CacheContext\Proxy</argument>

0 commit comments

Comments
 (0)