PrestaShop posiada całkiem dobre narzędzie wyszukiwania, ale czasami nie spełnia ono wszystkich Twoich potrzeb. Nie jest też zbyt szybkie, a w dużych sklepach wyszukiwanie i indeksacja mogą być bardzo powolne.
Jeśli potrzebujesz czegoś lepszego, możesz użyć świetnego zamiennika – Sphinx.
Z Wikipedii:
Sphinx to darmowy silnik wyszukiwania pełnotekstowego o otwartym kodzie źródłowym, zaprojektowany w celu zapewnienia funkcjonalności wyszukiwania pełnotekstowego dla aplikacji klienckich.
Strona internetowa Sphinx – http://sphinxsearch.com/
Instalacja Sphinx
Użyłem Debiana 8.1. W innych dystrybucjach Linuksa (a zwłaszcza w Windowsie) instalacja może się nieznacznie różnić.
Jeśli Sphinx jest dostępny w repozytoriach, po prostu go zainstaluj:
1 2 3 | su apt-get update apt-get install sphinxsearch |
Jeśli Sphinx nie jest dostępny w repozytoriach, możesz pobrać instalator z oficjalnej strony i zainstalować zależności:
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 |
Musisz zastąpić nazwę i adres URL instalatora aktualnymi wersjami. Wszystkie są dostępne na oficjalnej stronie internetowej.
Konfiguracja Sphinx
Otwórz konfigurację Sphinx i edytuj ją:
1 | nano /etc/sphinxsearch/sphinx.conf |
Musisz edytować istniejący domyślny blok „source src1” (lub dodać nowy blok). Wynik powinien wyglądać tak:
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 # Nazwa użytkownika bazy danych PrestaShop sql_user = DBUSER # Hasło bazy danych PrestaShop sql_pass = DBPASSWORD # Nazwa bazy danych PrestaShop sql_db = DBNAME sql_port = 3306 # opcjonalnie, domyślnie 3306 sql_query_pre = SET NAMES utf8 # Zapytanie MySQL z listą pól do indeksacji sql_query = SELECT id_product, name, description, description_short FROM ps_product_lang } |
Najpierw widzisz ustawienia połączenia z bazą danych (nie zapomnij zmienić ich na właściwe). Parametr sql_query zawiera zapytanie z polami do indeksacji.
To są wszystkie ustawienia z mojej konfiguracji. Zasadniczo plik konfiguracyjny jest dobrze udokumentowany i wszystkie opcje są w nim opisane, więc możesz łatwo dostosować swoją konfigurację.
Następnie, w bloku „index definition” musisz skonfigurować indeks:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | index PrestaSite { # źródło danych do indeksacji source = PrestaSite # lokalizacja danych indeksu path = /var/lib/sphinxsearch/data/prestasite # preprocesory morfologiczne morphology = stem_en # minimalna długość słowa do indeksacji min_word_len = 1 } |
Następnie widzisz bloki „indexer settings” i „searchd settings”. Zazwyczaj są one w porządku, możesz je po prostu pominąć.
Więc skonfigurowaliśmy źródło danych (source PrestaSite) i indeks (index PrestaSite).
Indeksacja
Uruchom indeksator, aby zaindeksować swoją bazę danych:
1 | indexer --all |
Uruchomienie Sphinx
Nie zapomnij uruchomić/zrestartować searchd:
1 | searchd |
I dodaj indeksator do crontab:
1 | 15 * * * * root indexer --all |
Indeksacja będzie uruchamiana co godzinę.
Konfiguracja PrestaShop
Poniżej znajduje się kod dla PrestaShop 1.6. W innych wersjach PrestaShop może się on nieznacznie różnić.
Utwórz (lub edytuj) nadpisanie klasy 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); } } |
Zasadniczo kod jest dość prosty. Nadpisujemy funkcję „find”, w której zastępujemy wyszukiwanie PrestaShop wyszukiwaniem Sphinx. Sphinx zwraca identyfikatory produktów, a za pomocą tych identyfikatorów pobieramy dane produktów. Druga funkcja (getSphinxResults) bezpośrednio wykonuje wyszukiwanie.
Na koniec musisz wyczyścić pamięć podręczną i usunąć pamięć podręczną klas (/cache/class_index.php). Gotowe!
