Magento 2.4.6 Opensearch Search synonyms

155 views Asked by At

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.

enter image description here

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.

1

There are 1 answers

0
Aniruddha Ray On

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.