I am trying to make use of search synonyms. I have created a synonym group, and added synonyms comma separated, and afterwards ran full re index.
Now I am testing this out with the following API call
http://website/rest/V1/products?searchCriteria[filter_groups][0][filters][0][field]=name&searchCriteria[filter_groups][0][filters][0][value]=%25cucumber%25&searchCriteria[filter_groups][0][filters][0][condition_type]=like&searchCriteria[pageSize]=5&searchCriteria[currentPage]=1
This is returning data. But if I replace 'cucumber' with the synonyms , if returns no results.
I am using open search as my search engine, and I found this block of code in vendor/magento/module-open-search/etc/search_engine.xml
<engines xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Search/etc/search_engine.xsd">
<engine name="opensearch">
<feature name="synonyms" support="true" />
</engine>
</engines>
I am not sure if I am missing anything or doing it wrong.
As I couldn't find any article online which tells me why search criteria api doesn't work with synonyms, did my workaround. Sharing if this helps anyone in future. Created my custom search api.
/**
* Check if query string has synonyms set
*
* @param string $queryString
* @return array|bool
*/
private function checkForSynonyms($queryString,$processResponse = false)
{
$analyzedData = $synonyms = [];
/**
* @var \Magento\Search\Api\SynonymAnalyzerInterface
*/
$analyzedData = $this->synonymAnalyzerInterface->getSynonymsForPhrase($queryString);
foreach($analyzedData as $synm):
if(count($synm) > 1):
$synonyms = $synm;
endif;
endforeach;
return $processResponse ? $this->processSynonymResponse($queryString,$synonyms) : $synonyms ?? false;
}
/**
* Prepare synonyms for api call
*
* @param string $queryString
* @param array $synonyms
* @return array|bool
*/
private function processSynonymResponse($queryString,$synonyms = [])
{
$querySynm = null;
$searchStrings = [];
if($synonyms):
foreach($synonyms as $synonym) {
if(str_contains($queryString, $synonym))
$querySynm = $synonym;
}
foreach($synonyms as $synm) {
if($querySynm && $synm != $querySynm) {
$searchStrings[] = str_replace($querySynm, $synm, $queryString);
}
}
array_push($searchStrings, $queryString);
return $searchStrings;
endif;
return false;
}
Called the above function in search api, and added the synonyms as OR conditions
$synonym = $this->checkForSynonyms(strtolower($queryString),true);
if($synonym):
foreach($synonym as $synmQuery):
$filters[] = $this->filterBuilder->setField('name')
->setValue('%'.$synmQuery.'%')
->setConditionType('like')->create();
endforeach;
foreach($filters as $filter) {
$this->filterGroupBuilder->addFilter($filter);
}
$filterGrpBuilder = $this->filterGroupBuilder->create();
$this->searchCriteriaBuilder->setFilterGroups([$filterGrpBuilder]);
else:
$this->searchCriteriaBuilder->addFilter('name', '%'.$queryString.'%', 'like');
endif;
I have not tested this on different scenarios, but this works for my case.