Home > Magento > Magento Quick Search Fix

Magento Quick Search Fix

When I upgraded my website from magento 1.4.2.0 to magento 1.5.x the quick search started causing issue, when trying to search for particular SKUs or product names to be matched exactly it would return all the products or unrelated results, after spending hours and beating head against the wall, I found the fix and thought to share that right here.

To start with I had to override the Mage_CatalogSearch_Model_Mysql4_Fulltext::prepareResult() resource model, Magento uses FullText indexing to query the results, there are two advantages of this, one it is faster then traditional LIKE and RegExp and on the other hand it is more comprehensive by using MATCH, AGAINST combined with IN BOOLEAN MODE.

To override the module you would first need to create the module initialization file under app/etc/modules folder in my case the code is.

  <?xml version="1.0"?>
<!--
Document   : Namespace_MyCatalogSearch.xml
Created on : September 5, 2011, 4:57 PM
Author     : aftab
Description:
Initialize Namespace_MyCatalogSearch
-->
<config>
<modules>
<Namespace_MyCatalogSearch>
<active>true</active>
<codePool>local</codePool>
<depends>
<Mage_CatalogSearch />
</depends>
</Namespace_MyCatalogSearch>
</modules>
</config>

Now Create Namespace/MyCatalogSearch folder under app/code/local
and then create config.xml under app/code/local/Namespace/MyCatalogSearch

 <config>
<global>
    <!-- Override Core Model -->
    <models>
        <mycatalogsearch>
            <class>Namespace_MyCatalogSearch_Model</class>
        </mycatalogsearch>
        
        <!-- @override resource models -->
        <catalogsearch_mysql4>
            <rewrite><fulltext>Namespace_MyCatalogSearch_Model_Mysql4_Fulltext</fulltext></rewrite>
        </catalogsearch_mysql4>
    </models>
</global>
</config>

Now finally create the model class Fulltext.php under app/code/local/Namespace/MyCatalogSearch/Model/Mysql4

class Namespace_MyCatalogSearch_Model_Mysql4_Fulltext extends Mage_CatalogSearch_Model_Mysql4_Fulltext
{
    /**
     * Prepare results for query
     *
     * @param Mage_CatalogSearch_Model_Fulltext $object
     * @param string $queryText
     * @param Mage_CatalogSearch_Model_Query $query
     * @return Mage_CatalogSearch_Model_Mysql4_Fulltext
     */
    public function prepareResult($object, $queryText, $query)
    { 
        if (!$query->getIsProcessed()) {
            $searchType = $object->getSearchType($query->getStoreId());

            $stringHelper = Mage::helper('core/string');
            /* @var $stringHelper Mage_Core_Helper_String */

            $bind = array(
                ':query' => "\"$queryText\"" //modified, to escape (+ -) and other operators of IN BOOLEAN MODE for exact match
            );
            $like = array();

            $fulltextCond   = '';
            $likeCond       = '';
            $separateCond   = '';

            if ($searchType == Mage_CatalogSearch_Model_Fulltext::SEARCH_TYPE_LIKE
                || $searchType == Mage_CatalogSearch_Model_Fulltext::SEARCH_TYPE_COMBINE) {
                $words = $stringHelper->splitWords($queryText, true, $query->getMaxQueryWords());
                $likeI = 0;
                foreach ($words as $word) {
                    $like[] = '`s`.`data_index` LIKE :likew' . $likeI;
                    $bind[':likew' . $likeI] = '%' . $word . '%';
                    $likeI ++;
                }
                if ($like) {
                    $likeCond = '(' . join(' OR ', $like) . ')';
                }
            }
            if ($searchType == Mage_CatalogSearch_Model_Fulltext::SEARCH_TYPE_FULLTEXT
                || $searchType == Mage_CatalogSearch_Model_Fulltext::SEARCH_TYPE_COMBINE) {
                $fulltextCond = 'MATCH (`s`.`data_index`) AGAINST (:query IN BOOLEAN MODE)';
            }
            if ($searchType == Mage_CatalogSearch_Model_Fulltext::SEARCH_TYPE_COMBINE && $likeCond) {
                $separateCond = ' OR ';
            }

            $sql = sprintf("INSERT INTO `{$this->getTable('catalogsearch/result')}` "
                . "(SELECT STRAIGHT_JOIN '%d', `s`.`product_id`, MATCH (`s`.`data_index`) "
                . "AGAINST (:query IN BOOLEAN MODE) FROM `{$this->getMainTable()}` AS `s` "
                . "INNER JOIN `{$this->getTable('catalog/product')}` AS `e` "
                . "ON `e`.`entity_id`=`s`.`product_id` WHERE (%s%s%s) AND `s`.`store_id`='%d')"
                . " ON DUPLICATE KEY UPDATE `relevance`=VALUES(`relevance`)",
                $query->getId(),
                $fulltextCond,
                $separateCond,
                $likeCond,
                $query->getStoreId()
            );
            //$db = $this->_getWriteAdapter();
            //$db->getProfiler()->setEnabled(true);
            $this->_getWriteAdapter()->query($sql, $bind);
            //print $db->getProfiler()->getLastQueryProfile()->getQuery();
            //print_r($db->getProfiler()->getLastQueryProfile()->getQueryParams());
            //$db->getProfiler()->setEnabled(false);
            $query->setIsProcessed(1);
        }

        return $this;
    }
}

You would need to delete already existing search term in order to see the results, by logging to admin Catalog/Search Terms

About these ads
Categories: Magento
  1. Asif
    February 23, 2012 at 6:52 am

    Hi, i have magento 1.6.x.x running. Now i want to modify prepareResult() to make it work for EXACT search. For example, my product prices are in product names (product 1 $10, product2 $100). So if i quick search “$10″, the product(product2 $100) also comes in result. How can i modify this such way that only “$10″ products will come?

    • May 11, 2012 at 7:00 am

      Hi Asif, this seems to be a bit old, but any way, you would want to use the LIKE for that, so an thing in in product name which appears after $ sign will be the price. hope this helps

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 264 other followers

%d bloggers like this: