Utilizzare la ricerca Sphinx in PrestaShop

PrestaShop ha un ottimo strumento di ricerca, ma a volte non soddisfa tutte le tue esigenze. Inoltre non è molto veloce e nei grandi negozi la ricerca e l’indicizzazione potrebbero essere molto lente.

Se desideri qualcosa di meglio, puoi utilizzare un’ottima alternativa – Sphinx.


Da Wikipedia:

Sphinx è un motore di ricerca Fulltext open source/software libero progettato per fornire funzionalità di ricerca full-text alle applicazioni client.

Sito web di Sphinx – http://sphinxsearch.com/

Installazione di Sphinx

Ho usato Debian 8.1. In altre distribuzioni Linux (e in particolar modo in Windows) l’installazione potrebbe differire leggermente.
Se Sphinx è disponibile nei repository, installalo semplicemente:

1
2
3
su
apt-get update
apt-get install sphinxsearch

Se Sphinx non è disponibile nei repository, puoi scaricare un programma di installazione dal sito ufficiale e installare le dipendenze:

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

Devi sostituire il nome e l’url del programma di installazione con le versioni correnti rilevanti. Sono tutte disponibili sul sito ufficiale.

Configurazione di Sphinx

Apri la configurazione di Sphinx e modificala:

1
nano /etc/sphinxsearch/sphinx.conf

Devi modificare il blocco predefinito esistente “source src1” (o aggiungere un nuovo blocco). Il risultato dovrebbe apparire così:

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
}

Per prima cosa puoi vedere le impostazioni per connettersi al database (non dimenticare di modificarle con quelle pertinenti). Il parametro sql_query contiene una query con i campi per l’indicizzazione.

Queste sono tutte le impostazioni dalla mia configurazione. Fondamentalmente, il file di configurazione è ben documentato e tutte le opzioni sono descritte lì, in modo da poter personalizzare facilmente la tua configurazione.

Successivamente, nel blocco “index definition” devi configurare l’indice:

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
}

Successivamente puoi vedere i blocchi “indexer settings” e “searchd settings”. Di solito vanno bene, puoi semplicemente saltarli.

Quindi, abbiamo configurato l’origine dati (source PrestaSite) e l’indice (index PrestaSite).

Indicizzazione

Avvia indexer per indicizzare il tuo database:

1
indexer --all

Avvio di Sphinx

Non dimenticare di avviare/riavviare searchd:

1
searchd

E aggiungi indexer a crontab:

1
15 * * * * root indexer --all

L’indicizzazione verrà avviata ogni ora.

Configurazione di PrestaShop

Di seguito puoi vedere il codice per PrestaShop 1.6. Per le altre versioni di PrestaShop potrebbe differire leggermente.

Crea (o modifica) l’override della 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);
    }
}

Sostanzialmente, il codice è piuttosto semplice. Sovrascriviamo la funzione “find”, nella quale sostituiamo la ricerca di PrestaShop con la ricerca Sphinx. Sphinx restituisce gli id dei prodotti e utilizzando tali id eseguiamo la query dei dati dei prodotti. La seconda funzione (getSphinxResults) esegue direttamente la ricerca.

Alla fine, devi svuotare la cache e rimuovere la cache delle classi (/cache/class_index.php). Tutto fatto!

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *