Back to Top

How to replace magento2 default search engine

Updated 5 March 2024

Need:

By default, Magento 2 uses MySQL full text for search operations, but is MySQL enough to handle the huge amount of data with complex queries?

The answer is NO.

In the competitive world speed can give you a huge plus over other competitors, and if you have a huge amount of data that needs to be searched in real time MySQL can set you back, but if you have a small amount of data MySQL will do good for you. So let’s see how we can replace MySQL search engine in magento2.

How to do this in Magento 2:

There are several options that you can choose to switch from MySQL search, such as Magento 2 elastic search, solr search, amazon cloud search, etc, but we are talking about replacing an already built sophisticated search engine but the best thing about Magento 2 code structure is it is highly scalable, and build with components that you can easily replace with new technologies.

So let’s see how we can switch from MySQL search engine to any other search engine, suppose we want to replace MySQL search with the elastic search.

Searching for an experienced
Magento 2 Company ?
Find out More

I am assuming that you already know how to build a module in magento 2, so let’s start :

Create di.xml file:

create a di.xml file at the path app/code/CompanyName/ModuleName/etc/di.xml and add this type of configuration:

<type name="Magento\Search\Model\Adminhtml\System\Config\Source\Engine">
    <arguments>
         <argument name="engines" xsi:type="array">
             <item name="elastic" xsi:type="string">Elastic</item>
         </argument>
    </arguments>
</type>

in the above type configuration, you can see I have inserted a string elastic in the engines array of class “Magento\Search\Model\Adminhtml\System\Config\Source\Engine” this class is responsible for rendering search engine options in magento 2  stores > configuration > catalog > storefront > catalog search > search engine :

Search Engine Config

After you have added the entry in di.xml, it will start showing elastic in the search engine select box like this:

search engine option added

By just saving the elastic option here in the config you have managed to change the MySQL search engine, now you need to add your own logic to index data on the elastic server and then search from there.

After saving the elastic option if you will try to load your storefront it will start giving LogicException that there is no such adapter: elastic, you need to add your own adapter class to render data from the elastic server, for that you need to add another type configuration in the same di.xml file:

<type name="Magento\Search\Model\Adminhtml\System\Config\Source\Engine">
        <arguments>
            <argument name="engines" xsi:type="array">
                <item name="elastic" xsi:type="string">Elastic</item>
            </argument>
        </arguments>
    </type>
    <type name="Magento\Search\Model\AdapterFactory">
        <arguments>
            <argument name="adapters" xsi:type="array">
                <item name="elastic" xsi:type="string">YourCompany\ModuleName\Model\SearchAdapter\Adapter</item>
            </argument>
        </arguments>
</type>

So, now you can see I have added another type configuration in the di.xml file this time I have added a class name string with key elastic (the key need to be the same as we have used in the previous type configuration) inside adapters array for class “Magento\Search\Model\AdapterFactory”. Let’s see how Magento adapter class looks like:

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Magento\Framework\Search\Adapter\Mysql;

use Magento\Framework\App\ResourceConnection;
use Magento\Framework\DB\Ddl\Table;
use Magento\Framework\DB\Select;
use Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder as AggregationBuilder;
use Magento\Framework\Search\AdapterInterface;
use Magento\Framework\Search\RequestInterface;

/**
 * MySQL Search Adapter
 *
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class Adapter implements AdapterInterface
{
    /**
     * Mapper instance
     *
     * @var Mapper
     */
    protected $mapper;

    /**
     * Response Factory
     *
     * @var ResponseFactory
     */
    protected $responseFactory;

    /**
     * @var \Magento\Framework\App\ResourceConnection
     */
    private $resource;

    /**
     * @var AggregationBuilder
     */
    private $aggregationBuilder;

    /**
     * @var TemporaryStorageFactory
     */
    private $temporaryStorageFactory;

    /**
     * @param Mapper $mapper
     * @param ResponseFactory $responseFactory
     * @param ResourceConnection $resource
     * @param AggregationBuilder $aggregationBuilder
     * @param TemporaryStorageFactory $temporaryStorageFactory
     */
    public function __construct(
        Mapper $mapper,
        ResponseFactory $responseFactory,
        ResourceConnection $resource,
        AggregationBuilder $aggregationBuilder,
        TemporaryStorageFactory $temporaryStorageFactory
    ) {
        $this->mapper = $mapper;
        $this->responseFactory = $responseFactory;
        $this->resource = $resource;
        $this->aggregationBuilder = $aggregationBuilder;
        $this->temporaryStorageFactory = $temporaryStorageFactory;
    }

    /**
     * {@inheritdoc}
     * @throws \LogicException
     */
    public function query(RequestInterface $request)
    {
        $query = $this->mapper->buildQuery($request);
        $temporaryStorage = $this->temporaryStorageFactory->create();
        $table = $temporaryStorage->storeDocumentsFromSelect($query);

        $documents = $this->getDocuments($table);

        $aggregations = $this->aggregationBuilder->build($request, $table, $documents);
        $response = [
            'documents' => $documents,
            'aggregations' => $aggregations,
        ];
        return $this->responseFactory->create($response);
    }

    /**
     * Executes query and return raw response
     *
     * @param Table $table
     * @return array
     * @throws \Zend_Db_Exception
     */
    private function getDocuments(Table $table)
    {
        $connection = $this->getConnection();
        $select = $connection->select();
        $select->from($table->getName(), ['entity_id', 'score']);
        return $connection->fetchAssoc($select);
    }

    /**
     * @return false|\Magento\Framework\DB\Adapter\AdapterInterface
     */
    private function getConnection()
    {
        return $this->resource->getConnection();
    }
}

Above class is MySQL adapter class, you can see it has implemented “AdapterInterface” interface and implemented “query” function definition from the interface, your class need to do the same thing, and inside query method you can implement your own logic to build the elastic query, aggregations and then fetch data from the elastic server, the same thing with any other search engine, but the query function needs to return the data in a certain format, you need to create that format too after getting the result from the desired search engine(in this case elastic), the format looks like this:

Array
(
    [documents] => Array
        (
            [9] => Array
                (
                    [entity_id] => 9
                    [score] => 46.9016704559326200
                )

            [1] => Array
                (
                    [entity_id] => 1
                    [score] => 0.9771181344985962
                )

        )

    [aggregations] => Array
        (
            [price_bucket] => Array
                (
                    [20_30] => Array
                        (
                            [value] => 20_30
                            [count] => 1
                        )

                    [50_*] => Array
                        (
                            [value] => 50_*
                            [count] => 1
                        )

                )

            [category_bucket] => Array
                (
                    [3] => Array
                        (
                            [value] => 3
                            [count] => 1
                        )

                    [5] => Array
                        (
                            [value] => 5
                            [count] => 1
                        )

                )

        )

)

the above is the result of the query for the text “test” and generated using PHP print_r method, in the above response entity_id is the searched product id and the score is the weight of each result, to set its position in the search results.

So that’s how you can implement another search engine in magento 2, hope this will help you, in case of any doubt please comment below.

Thanks 🙂 .

You may also check our quality Magento 2 Extensions.

. . .

Leave a Comment

Your email address will not be published. Required fields are marked*


Be the first to comment.

Back to Top

Message Sent!

If you have more details or questions, you can reply to the received confirmation email.

Back to Home