PrestaShop a un bel outil de recherche, mais parfois il ne répond pas à tous vos besoins. De plus, il n’est pas vraiment rapide et sur les grandes boutiques, la recherche et l’indexation peuvent être très lentes.
Si vous voulez quelque chose de mieux, vous pouvez utiliser un excellent remplacement – Sphinx.
De Wikipedia :
Sphinx est un moteur de recherche en texte intégral (Fulltext) open source/logiciel libre conçu pour fournir des fonctionnalités de recherche en texte intégral aux applications clientes.
Site web de Sphinx – http://sphinxsearch.com/
Installation de Sphinx
J’ai utilisé Debian 8.1. Dans d’autres distributions Linux (et en particulier sous Windows), l’installation peut différer légèrement.
Si Sphinx est disponible dans les dépôts, installez-le simplement :
1 2 3 | su apt-get update apt-get install sphinxsearch |
Si Sphinx n’est pas disponible dans les dépôts, vous pouvez télécharger un programme d’installation depuis le site officiel et installer les dépendances :
1 2 3 | apt-get install mysql-client unixodbc libpq5 wget http://sphinxsearch.com/files/sphinxsearch_2.2.9-release-1~wheezy_i386.deb dpkg -i sphinxsearch_2.2.9-release-1~wheezy_i386.deb |
Vous devez remplacer le nom et l’URL du programme d’installation par les versions actuelles pertinentes. Elles sont toutes disponibles sur le site officiel.
Configuration de Sphinx
Ouvrez la configuration de Sphinx et modifiez-la :
1 | nano /etc/sphinxsearch/sphinx.conf |
Vous devez modifier le bloc par défaut existant « source src1 » (ou ajouter un nouveau bloc). Le résultat devrait ressembler à ceci :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | source PrestaSite { type = mysql sql_host = localhost # PrestaShop database username sql_user = DBUSER # PrestaShop database password sql_pass = DBPASSWORD # PrestaShop database name sql_db = DBNAME sql_port = 3306 # optional, default is 3306 sql_query_pre = SET NAMES utf8 # MySQL query with list of fields for indexation sql_query = SELECT id_product, name, description, description_short FROM ps_product_lang } |
Tout d’abord, vous pouvez voir les paramètres de connexion à la base de données (n’oubliez pas de les modifier en conséquence). Le paramètre sql_query contient une requête avec les champs à indexer.
Ce sont tous les paramètres de ma configuration. Fondamentalement, le fichier de configuration est bien documenté et toutes les options y sont décrites, vous pouvez donc facilement personnaliser votre configuration.
Ensuite, dans le bloc « index definition », vous devez configurer l’index :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | index PrestaSite { # data source for indexation source = PrestaSite # location for index data path = /var/lib/sphinxsearch/data/prestasite # morphology preprocessors morphology = stem_en # minimal word length for indexation min_word_len = 1 } |
Ensuite, vous pouvez voir les blocs « indexer settings » et « searchd settings ». Habituellement, ils sont corrects, vous pouvez simplement les ignorer.
Nous avons donc configuré la source de données (source PrestaSite) et l’index (index PrestaSite).
Indexation
Lancez l’indexeur pour indexer votre base de données :
1 | indexer --all |
Lancement de Sphinx
N’oubliez pas de démarrer/redémarrer searchd :
1 | searchd |
Et d’ajouter l’indexeur à la crontab :
1 | 15 * * * * root indexer --all |
L’indexation sera lancée toutes les heures.
Configuration de PrestaShop
Ci-dessous, vous pouvez voir le code pour PrestaShop 1.6. Pour les autres versions de PrestaShop, cela peut différer légèrement.
Créez (ou modifiez) la surcharge de la classe Search :
/override/classes/Search.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | <?php class Search extends SearchCore { public static function find($id_lang, $expr, $page_number = 1, $page_size = 1, $order_by = 'position', $order_way = 'desc', $ajax = false, $use_cookie = true, Context $context = null) { if (!$context) { $context = Context::getContext(); } $db = Db::getInstance(_PS_USE_SQL_SLAVE_); // TODO : smart page management if ($page_number < 1) $page_number = 1; if ($page_size < 1) $page_size = 1; if (!Validate::isOrderBy($order_by) || !Validate::isOrderWay($order_way)) return false; if (!Validate::isOrderBy($order_by) || !Validate::isOrderWay($order_way)) { return false; } $start = ($page_number - 1) * $page_size; // Sphinx search, get ids of found products $sphinx_results = self::getSphinxResults($expr, $start, $page_size); $result = null; $total = 0; // get products by id if something found if (is_array($sphinx_results) AND sizeof($sphinx_results) AND isset($sphinx_results['total']) AND $sphinx_results['total'] > 0) { $sql = 'SELECT p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity, pl.`description_short`, pl.`available_now`, pl.`available_later`, pl.`link_rewrite`, pl.`name`, MAX(image_shop.`id_image`) id_image, il.`legend`, m.`name` manufacturer_name, MAX(product_attribute_shop.`id_product_attribute`) id_product_attribute, DATEDIFF( p.`date_add`, DATE_SUB( NOW(), INTERVAL '.(Validate::isUnsignedInt(Configuration::get('PS_NB_DAYS_NEW_PRODUCT')) ? Configuration::get('PS_NB_DAYS_NEW_PRODUCT') : 20).' DAY ) ) > 0 new FROM '._DB_PREFIX_.'product p '.Shop::addSqlAssociation('product', 'p').' INNER JOIN `'._DB_PREFIX_.'product_lang` pl ON ( p.`id_product` = pl.`id_product` AND pl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('pl').' ) LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON (p.`id_product` = pa.`id_product`) '.Shop::addSqlAssociation('product_attribute', 'pa', false, 'product_attribute_shop.`default_on` = 1').' '.Product::sqlStock('p', 'product_attribute_shop', false, $context->shop).' LEFT JOIN `'._DB_PREFIX_.'manufacturer` m ON m.`id_manufacturer` = p.`id_manufacturer` LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_product` = p.`id_product`)'. Shop::addSqlAssociation('image', 'i', false, 'image_shop.cover=1').' LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON (i.`id_image` = il.`id_image` AND il.`id_lang` = '.(int)$id_lang.') WHERE p.`id_product` IN('.implode(',', $sphinx_results['results']).') GROUP BY product_shop.id_product'; $result = $db->executeS($sql); // results count $total = $sphinx_results['total']; } if (!$result) { $result_properties = array(); } else { $result_properties = Product::getProductsProperties((int)$id_lang, $result); } return array('total' => $total, 'result' => $result_properties); } protected static function getSphinxResults($search_query, $page_number, $page_size) { $results = array(); $total = 0; if(!$search_query) return null; // connect to Sphinx database $link = mysqli_connect('127.0.0.1', '', '', '', '9306'); if($link) { $query = 'SELECT * FROM `PrestaSite` WHERE MATCH(''.pSQL($search_query).'') limit '.(int)$page_number.', '.(int)$page_size.';'; if ($result = $link->query($query)) { while($query_results = $result->fetch_array()) { $results = array_merge($results, $query_results); } /* clear result */ $result->close(); } // get count of results $query_total = 'SELECT count(*) FROM `PrestaSite` WHERE MATCH(''.pSQL($search_query).'');'; if ($result = $link->query($query_total)) { $total = (int)$result->fetch_array()[0]; if($total > 1000) $total = 1000; } mysqli_close($link); } return array('results' => $results, 'total' => $total); } } |
Fondamentalement, le code est assez simple. Nous surchargeons la fonction « find », dans laquelle nous remplaçons la recherche de PrestaShop par la recherche Sphinx. Sphinx renvoie les ID des produits et, en utilisant ces ID, nous interrogeons les données des produits. La deuxième fonction (getSphinxResults) effectue directement la recherche.
À la fin, vous devez vider le cache et supprimer le cache de classe (/cache/class_index.php). Tout est terminé !
