Example #1
0
    public static function indexation($full = false, $id_product = false)
    {
        $db = Db::getInstance();
        if ($id_product) {
            $full = false;
        }
        if ($full) {
            $db->execute('TRUNCATE ' . _DB_PREFIX_ . 'search_index');
            $db->execute('TRUNCATE ' . _DB_PREFIX_ . 'search_word');
            ObjectModel::updateMultishopTable('Product', array('indexed' => 0));
        } else {
            // Do it even if you already know the product id in order to be sure that it exists and it needs to be indexed
            $products = $db->executeS('
				SELECT p.id_product
				FROM ' . _DB_PREFIX_ . 'product p
				' . Shop::addSqlAssociation('product', 'p') . '
				WHERE product_shop.visibility IN ("both", "search")
				AND ' . ($id_product ? 'p.id_product = ' . (int) $id_product : 'product_shop.indexed = 0'));
            $ids = array();
            if ($products) {
                foreach ($products as $product) {
                    $ids[] = (int) $product['id_product'];
                }
            }
            if (count($ids)) {
                $db->execute('DELETE FROM ' . _DB_PREFIX_ . 'search_index WHERE id_product IN (' . implode(',', $ids) . ')');
                ObjectModel::updateMultishopTable('Product', array('indexed' => 0), 'a.id_product IN (' . implode(',', $ids) . ')');
            }
        }
        // Every fields are weighted according to the configuration in the backend
        $weight_array = array('pname' => Configuration::get('PS_SEARCH_WEIGHT_PNAME'), 'reference' => Configuration::get('PS_SEARCH_WEIGHT_REF'), 'ean13' => Configuration::get('PS_SEARCH_WEIGHT_REF'), 'upc' => Configuration::get('PS_SEARCH_WEIGHT_REF'), 'description_short' => Configuration::get('PS_SEARCH_WEIGHT_SHORTDESC'), 'description' => Configuration::get('PS_SEARCH_WEIGHT_DESC'), 'cname' => Configuration::get('PS_SEARCH_WEIGHT_CNAME'), 'mname' => Configuration::get('PS_SEARCH_WEIGHT_MNAME'), 'tags' => Configuration::get('PS_SEARCH_WEIGHT_TAG'), 'attributes' => Configuration::get('PS_SEARCH_WEIGHT_ATTRIBUTE'), 'features' => Configuration::get('PS_SEARCH_WEIGHT_FEATURE'));
        // Those are kind of global variables required to save the processed data in the database every X occurrences, in order to avoid overloading MySQL
        $count_words = 0;
        $query_array3 = array();
        // Every indexed words are cached into a PHP array
        $word_ids = $db->executeS('
			SELECT id_word, word, id_lang, id_shop
			FROM ' . _DB_PREFIX_ . 'search_word', false);
        $word_ids_by_word = array();
        while ($word_id = $db->nextRow($word_ids)) {
            if (!isset($word_ids_by_word[$word_id['id_shop']][$word_id['id_lang']])) {
                $word_ids_by_word[$word_id['id_shop']][$word_id['id_lang']] = array();
            }
            $word_ids_by_word[$word_id['id_shop']][$word_id['id_lang']]['_' . $word_id['word']] = (int) $word_id['id_word'];
        }
        // Retrieve the number of languages
        $total_languages = count(Language::getLanguages(false));
        // Products are processed 50 by 50 in order to avoid overloading MySQL
        while (($products = Search::getProductsToIndex($total_languages, $id_product, 50)) && count($products) > 0) {
            $products_array = array();
            // Now each non-indexed product is processed one by one, langage by langage
            foreach ($products as $product) {
                $product['tags'] = Search::getTags($db, (int) $product['id_product'], (int) $product['id_lang']);
                $product['attributes'] = Search::getAttributes($db, (int) $product['id_product'], (int) $product['id_lang']);
                $product['features'] = Search::getFeatures($db, (int) $product['id_product'], (int) $product['id_lang']);
                // Data must be cleaned of html, bad characters, spaces and anything, then if the resulting words are long enough, they're added to the array
                $product_array = array();
                foreach ($product as $key => $value) {
                    if (strncmp($key, 'id_', 3) && isset($weight_array[$key])) {
                        $words = explode(' ', Search::sanitize($value, (int) $product['id_lang'], true, $product['iso_code']));
                        foreach ($words as $word) {
                            if (!empty($word)) {
                                $word = Tools::substr($word, 0, PS_SEARCH_MAX_WORD_LENGTH);
                                // Remove accents
                                $word = Tools::replaceAccentedChars($word);
                                if (!isset($product_array[$word])) {
                                    $product_array[$word] = 0;
                                }
                                $product_array[$word] += $weight_array[$key];
                            }
                        }
                    }
                }
                // If we find words that need to be indexed, they're added to the word table in the database
                if (count($product_array)) {
                    $query_array = $query_array2 = array();
                    foreach ($product_array as $word => $weight) {
                        if ($weight && !isset($word_ids_by_word['_' . $word])) {
                            $query_array[$word] = '(' . (int) $product['id_lang'] . ', ' . (int) $product['id_shop'] . ', \'' . pSQL($word) . '\')';
                            $query_array2[] = '\'' . pSQL($word) . '\'';
                            $word_ids_by_word[$product['id_shop']][$product['id_lang']]['_' . $word] = 0;
                        }
                    }
                    if ($query_array2) {
                        $existing_words = $db->executeS('
						SELECT DISTINCT word FROM ' . _DB_PREFIX_ . 'search_word
							WHERE word IN (' . implode(',', $query_array2) . ')
						AND id_lang = ' . (int) $product['id_lang'] . '
						AND id_shop = ' . (int) $product['id_shop']);
                        foreach ($existing_words as $data) {
                            unset($query_array[Tools::replaceAccentedChars($data['word'])]);
                        }
                    }
                    if (count($query_array)) {
                        // The words are inserted...
                        $db->execute('
						INSERT IGNORE INTO ' . _DB_PREFIX_ . 'search_word (id_lang, id_shop, word)
						VALUES ' . implode(',', $query_array));
                    }
                    if (count($query_array2)) {
                        // ...then their IDs are retrieved and added to the cache
                        $added_words = $db->executeS('
						SELECT sw.id_word, sw.word
						FROM ' . _DB_PREFIX_ . 'search_word sw
						WHERE sw.word IN (' . implode(',', $query_array2) . ')
						AND sw.id_lang = ' . (int) $product['id_lang'] . '
						AND sw.id_shop = ' . (int) $product['id_shop'] . '
						LIMIT ' . count($query_array2));
                        // replace accents from the retrieved words so that words without accents or with differents accents can still be linked
                        foreach ($added_words as $word_id) {
                            $word_ids_by_word[$product['id_shop']][$product['id_lang']]['_' . Tools::replaceAccentedChars($word_id['word'])] = (int) $word_id['id_word'];
                        }
                    }
                }
                foreach ($product_array as $word => $weight) {
                    if (!$weight) {
                        continue;
                    }
                    if (!isset($word_ids_by_word[$product['id_shop']][$product['id_lang']]['_' . $word])) {
                        continue;
                    }
                    if (!$word_ids_by_word[$product['id_shop']][$product['id_lang']]['_' . $word]) {
                        continue;
                    }
                    $query_array3[] = '(' . (int) $product['id_product'] . ',' . (int) $word_ids_by_word[$product['id_shop']][$product['id_lang']]['_' . $word] . ',' . (int) $weight . ')';
                    // Force save every 200 words in order to avoid overloading MySQL
                    if (++$count_words % 200 == 0) {
                        Search::saveIndex($query_array3);
                    }
                }
                if (!in_array($product['id_product'], $products_array)) {
                    $products_array[] = (int) $product['id_product'];
                }
            }
            Search::setProductsAsIndexed($products_array);
            // One last save is done at the end in order to save what's left
            Search::saveIndex($query_array3);
        }
        return true;
    }
Example #2
0
    public static function indexation($full = false, $id_product = false)
    {
        $db = Db::getInstance();
        if ($id_product) {
            $full = false;
        }
        if ($full && Context::getContext()->shop->getContext() == Shop::CONTEXT_SHOP) {
            $db->execute('DELETE si, sw FROM `' . _DB_PREFIX_ . 'search_index` si
				INNER JOIN `' . _DB_PREFIX_ . 'product` p ON (p.id_product = si.id_product)
				' . Shop::addSqlAssociation('product', 'p') . '
				INNER JOIN `' . _DB_PREFIX_ . 'search_word` sw ON (sw.id_word = si.id_word AND product_shop.id_shop = sw.id_shop)
				WHERE product_shop.`visibility` IN ("both", "search")
				AND product_shop.`active` = 1');
            $db->execute('UPDATE `' . _DB_PREFIX_ . 'product` p
				' . Shop::addSqlAssociation('product', 'p') . '
				SET p.`indexed` = 0, product_shop.`indexed` = 0
				WHERE product_shop.`visibility` IN ("both", "search")
				AND product_shop.`active` = 1
				');
        } elseif ($full) {
            $db->execute('TRUNCATE ' . _DB_PREFIX_ . 'search_index');
            $db->execute('TRUNCATE ' . _DB_PREFIX_ . 'search_word');
            ObjectModel::updateMultishopTable('Product', array('indexed' => 0));
        } else {
            $db->execute('DELETE si FROM `' . _DB_PREFIX_ . 'search_index` si
				INNER JOIN `' . _DB_PREFIX_ . 'product` p ON (p.id_product = si.id_product)
				' . Shop::addSqlAssociation('product', 'p') . '
				WHERE product_shop.`visibility` IN ("both", "search")
				AND product_shop.`active` = 1
				AND ' . ($id_product ? 'p.`id_product` = ' . (int) $id_product : 'product_shop.`indexed` = 0'));
            $db->execute('UPDATE `' . _DB_PREFIX_ . 'product` p
				' . Shop::addSqlAssociation('product', 'p') . '
				SET p.`indexed` = 0, product_shop.`indexed` = 0
				WHERE product_shop.`visibility` IN ("both", "search")
				AND product_shop.`active` = 1
				AND ' . ($id_product ? 'p.`id_product` = ' . (int) $id_product : 'product_shop.`indexed` = 0'));
        }
        // Every fields are weighted according to the configuration in the backend
        $weight_array = array('pname' => Configuration::get('PS_SEARCH_WEIGHT_PNAME'), 'reference' => Configuration::get('PS_SEARCH_WEIGHT_REF'), 'pa_reference' => Configuration::get('PS_SEARCH_WEIGHT_REF'), 'supplier_reference' => Configuration::get('PS_SEARCH_WEIGHT_REF'), 'pa_supplier_reference' => Configuration::get('PS_SEARCH_WEIGHT_REF'), 'ean13' => Configuration::get('PS_SEARCH_WEIGHT_REF'), 'pa_ean13' => Configuration::get('PS_SEARCH_WEIGHT_REF'), 'upc' => Configuration::get('PS_SEARCH_WEIGHT_REF'), 'pa_upc' => Configuration::get('PS_SEARCH_WEIGHT_REF'), 'description_short' => Configuration::get('PS_SEARCH_WEIGHT_SHORTDESC'), 'description' => Configuration::get('PS_SEARCH_WEIGHT_DESC'), 'cname' => Configuration::get('PS_SEARCH_WEIGHT_CNAME'), 'mname' => Configuration::get('PS_SEARCH_WEIGHT_MNAME'), 'tags' => Configuration::get('PS_SEARCH_WEIGHT_TAG'), 'attributes' => Configuration::get('PS_SEARCH_WEIGHT_ATTRIBUTE'), 'features' => Configuration::get('PS_SEARCH_WEIGHT_FEATURE'));
        // Those are kind of global variables required to save the processed data in the database every X occurrences, in order to avoid overloading MySQL
        $count_words = 0;
        $query_array3 = array();
        // Retrieve the number of languages
        $total_languages = count(Language::getIDs(false));
        $sql_attribute = Search::getSQLProductAttributeFields($weight_array);
        // Products are processed 50 by 50 in order to avoid overloading MySQL
        while (($products = Search::getProductsToIndex($total_languages, $id_product, 50, $weight_array)) && count($products) > 0) {
            $products_array = array();
            // Now each non-indexed product is processed one by one, langage by langage
            foreach ($products as $product) {
                if ((int) $weight_array['tags']) {
                    $product['tags'] = Search::getTags($db, (int) $product['id_product'], (int) $product['id_lang']);
                }
                if ((int) $weight_array['attributes']) {
                    $product['attributes'] = Search::getAttributes($db, (int) $product['id_product'], (int) $product['id_lang']);
                }
                if ((int) $weight_array['features']) {
                    $product['features'] = Search::getFeatures($db, (int) $product['id_product'], (int) $product['id_lang']);
                }
                if ($sql_attribute) {
                    $attribute_fields = Search::getAttributesFields($db, (int) $product['id_product'], $sql_attribute);
                    if ($attribute_fields) {
                        $product['attributes_fields'] = $attribute_fields;
                    }
                }
                // Data must be cleaned of html, bad characters, spaces and anything, then if the resulting words are long enough, they're added to the array
                $product_array = array();
                foreach ($product as $key => $value) {
                    if ($key == 'attributes_fields') {
                        foreach ($value as $pa_array) {
                            foreach ($pa_array as $pa_key => $pa_value) {
                                Search::fillProductArray($product_array, $weight_array, $pa_key, $pa_value, $product['id_lang'], $product['iso_code']);
                            }
                        }
                    } else {
                        Search::fillProductArray($product_array, $weight_array, $key, $value, $product['id_lang'], $product['iso_code']);
                    }
                }
                // If we find words that need to be indexed, they're added to the word table in the database
                if (is_array($product_array) && !empty($product_array)) {
                    $query_array = $query_array2 = array();
                    foreach ($product_array as $word => $weight) {
                        if ($weight) {
                            $query_array[$word] = '(' . (int) $product['id_lang'] . ', ' . (int) $product['id_shop'] . ', \'' . pSQL($word) . '\')';
                            $query_array2[] = '\'' . pSQL($word) . '\'';
                        }
                    }
                    if (is_array($query_array) && !empty($query_array)) {
                        // The words are inserted...
                        $db->execute('
						INSERT IGNORE INTO ' . _DB_PREFIX_ . 'search_word (id_lang, id_shop, word)
						VALUES ' . implode(',', $query_array), false);
                    }
                    $word_ids_by_word = array();
                    if (is_array($query_array2) && !empty($query_array2)) {
                        // ...then their IDs are retrieved
                        $added_words = $db->executeS('
						SELECT sw.id_word, sw.word
						FROM ' . _DB_PREFIX_ . 'search_word sw
						WHERE sw.word IN (' . implode(',', $query_array2) . ')
						AND sw.id_lang = ' . (int) $product['id_lang'] . '
						AND sw.id_shop = ' . (int) $product['id_shop'], true, false);
                        foreach ($added_words as $word_id) {
                            $word_ids_by_word['_' . $word_id['word']] = (int) $word_id['id_word'];
                        }
                    }
                }
                foreach ($product_array as $word => $weight) {
                    if (!$weight) {
                        continue;
                    }
                    if (!isset($word_ids_by_word['_' . $word])) {
                        continue;
                    }
                    $id_word = $word_ids_by_word['_' . $word];
                    if (!$id_word) {
                        continue;
                    }
                    $query_array3[] = '(' . (int) $product['id_product'] . ',' . (int) $id_word . ',' . (int) $weight . ')';
                    // Force save every 200 words in order to avoid overloading MySQL
                    if (++$count_words % 200 == 0) {
                        Search::saveIndex($query_array3);
                    }
                }
                $products_array[] = (int) $product['id_product'];
            }
            $products_array = array_unique($products_array);
            Search::setProductsAsIndexed($products_array);
            // One last save is done at the end in order to save what's left
            Search::saveIndex($query_array3);
        }
        return true;
    }
Example #3
0
    public static function indexation($full = false)
    {
        $db = Db::getInstance();
        $dropIndex = false;
        if ($full) {
            $db->Execute('TRUNCATE ' . _DB_PREFIX_ . 'search_index');
            $db->Execute('TRUNCATE ' . _DB_PREFIX_ . 'search_word');
            $db->Execute('UPDATE ' . _DB_PREFIX_ . 'product SET indexed = 0');
            $dropIndex = true;
        } else {
            $products = $db->ExecuteS('SELECT id_product FROM ' . _DB_PREFIX_ . 'product WHERE indexed = 0');
            $ids = array();
            if ($products) {
                foreach ($products as $product) {
                    $ids[] = (int) $product['id_product'];
                }
            }
            if (sizeof($ids)) {
                //$db->Execute('DELETE FROM '._DB_PREFIX_.'search_index WHERE id_product IN ('.implode(',', $ids).')');
                //reindex the products in solr index
                SolrSearch::updateProducts($ids);
                $products = $db->ExecuteS('UPDATE ' . _DB_PREFIX_ . 'product set indexed = 1 WHERE indexed = 0');
            }
            if (count($ids)) {
                Db::getInstance()->Execute('UPDATE ' . _DB_PREFIX_ . 'product SET indexed = 1 WHERE id_product IN (' . implode(',', $ids) . ') LIMIT ' . (int) count($ids));
            }
            if (count($products) > 2000) {
                $dropIndex = true;
            }
        }
        //do not do anything to the db index
        return;
        if ($dropIndex) {
            $dropIndex = false;
            $result = $db->ExecuteS('SHOW INDEX FROM `' . _DB_PREFIX_ . 'search_index`');
            foreach ($result as $row) {
                if (strtolower($row['Key_name']) == 'primary') {
                    $dropIndex = true;
                }
            }
            if ($dropIndex) {
                $db->Execute('ALTER TABLE ' . _DB_PREFIX_ . 'search_index DROP PRIMARY KEY');
            }
            $dropIndex = true;
        }
        // Every fields are weighted according to the configuration in the backend
        $weightArray = array('pname' => Configuration::get('PS_SEARCH_WEIGHT_PNAME'), 'reference' => Configuration::get('PS_SEARCH_WEIGHT_REF'), 'ean13' => Configuration::get('PS_SEARCH_WEIGHT_REF'), 'upc' => Configuration::get('PS_SEARCH_WEIGHT_REF'), 'description_short' => Configuration::get('PS_SEARCH_WEIGHT_SHORTDESC'), 'description' => Configuration::get('PS_SEARCH_WEIGHT_DESC'), 'cname' => Configuration::get('PS_SEARCH_WEIGHT_CNAME'), 'mname' => Configuration::get('PS_SEARCH_WEIGHT_MNAME'), 'tags' => Configuration::get('PS_SEARCH_WEIGHT_TAG'), 'attributes' => Configuration::get('PS_SEARCH_WEIGHT_ATTRIBUTE'), 'features' => Configuration::get('PS_SEARCH_WEIGHT_FEATURE'));
        // All the product not yet indexed are retrieved
        $products = $db->ExecuteS('
		SELECT p.id_product, pl.id_lang, pl.name pname, p.reference, p.ean13, p.upc, pl.description_short, pl.description, cl.name cname, m.name mname
		FROM ' . _DB_PREFIX_ . 'product p
		LEFT JOIN ' . _DB_PREFIX_ . 'product_lang pl ON p.id_product = pl.id_product
		LEFT JOIN ' . _DB_PREFIX_ . 'category_lang cl ON (cl.id_category = p.id_category_default AND pl.id_lang = cl.id_lang)
		LEFT JOIN ' . _DB_PREFIX_ . 'manufacturer m ON m.id_manufacturer = p.id_manufacturer
		WHERE p.indexed = 0', false);
        // Those are kind of global variables required to save the processed data in the database every X occurences, in order to avoid overloading MySQL
        $countWords = 0;
        $countProducts = 0;
        $queryArray3 = array();
        $productsArray = array();
        // Every indexed words are cached into a PHP array
        $wordIdsByWord = array();
        $wordIds = Db::getInstance()->ExecuteS('
		SELECT sw.id_word, sw.word, id_lang
		FROM ' . _DB_PREFIX_ . 'search_word sw', false);
        $wordIdsByWord = array();
        while ($wordId = $db->nextRow($wordIds)) {
            if (!isset($wordIdsByWord[$wordId['id_lang']])) {
                $wordIdsByWord[$wordId['id_lang']] = array();
            }
            $wordIdsByWord[$wordId['id_lang']]['_' . $wordId['word']] = (int) $wordId['id_word'];
        }
        // Now each non-indexed product is processed one by one, langage by langage
        while ($product = $db->nextRow($products)) {
            $product['tags'] = Search::getTags($db, (int) $product['id_product'], (int) $product['id_lang']);
            $product['attributes'] = Search::getAttributes($db, (int) $product['id_product'], (int) $product['id_lang']);
            $product['features'] = Search::getFeatures($db, (int) $product['id_product'], (int) $product['id_lang']);
            // Data must be cleaned of html, bad characters, spaces and anything, then if the resulting words are long enough, they're added to the array
            $pArray = array();
            foreach ($product as $key => $value) {
                if (strncmp($key, 'id_', 3)) {
                    $words = explode(' ', Search::sanitize($value, (int) $product['id_lang'], true));
                    foreach ($words as $word) {
                        if (!empty($word)) {
                            $word = Tools::substr($word, 0, PS_SEARCH_MAX_WORD_LENGTH);
                            if (!isset($pArray[$word])) {
                                $pArray[$word] = 0;
                            }
                            $pArray[$word] += $weightArray[$key];
                        }
                    }
                }
            }
            // If we find words that need to be indexed, they're added to the word table in the database
            if (sizeof($pArray)) {
                $list = '';
                foreach ($pArray as $word => $weight) {
                    $list .= '\'' . $word . '\',';
                }
                $list = rtrim($list, ',');
                $queryArray = array();
                $queryArray2 = array();
                foreach ($pArray as $word => $weight) {
                    if ($weight and !isset($wordIdsByWord['_' . $word])) {
                        $queryArray[] = '(' . (int) $product['id_lang'] . ',\'' . pSQL($word) . '\')';
                        $queryArray2[] = '\'' . pSQL($word) . '\'';
                        $wordIdsByWord[$product['id_lang']]['_' . $word] = 0;
                    }
                }
                if (count($queryArray)) {
                    // The words are inserted...
                    $db->Execute('
					INSERT IGNORE INTO ' . _DB_PREFIX_ . 'search_word (id_lang, word)
					VALUES ' . implode(',', $queryArray));
                    // ...then their IDs are retrieved and added to the cache
                    $addedWords = $db->ExecuteS('
					SELECT sw.id_word, sw.word
					FROM ' . _DB_PREFIX_ . 'search_word sw
					WHERE sw.word IN (' . implode(',', $queryArray2) . ')
					AND sw.id_lang = ' . (int) $product['id_lang'] . '
					LIMIT ' . count($queryArray2));
                    foreach ($addedWords as $wordId) {
                        $wordIdsByWord[$product['id_lang']]['_' . $wordId['word']] = (int) $wordId['id_word'];
                    }
                }
            }
            foreach ($pArray as $word => $weight) {
                if (!$weight) {
                    continue;
                }
                if (!isset($wordIdsByWord[$product['id_lang']]['_' . $word])) {
                    continue;
                }
                if (!$wordIdsByWord[$product['id_lang']]['_' . $word]) {
                    continue;
                }
                $queryArray3[] = '(' . (int) $product['id_product'] . ',' . (int) $wordIdsByWord[$product['id_lang']]['_' . $word] . ',' . (int) $weight . ')';
                // Force save every 200 words in order to avoid overloading MySQL
                if (++$countWords % 200 == 0) {
                    Search::saveIndex($queryArray3);
                }
            }
            if (!in_array($product['id_product'], $productsArray)) {
                $productsArray[] = (int) $product['id_product'];
            }
            // Force save every 50 products in order to avoid overloading MySQL
            if (++$countProducts % 50 == 0) {
                Search::setProductsAsIndexed($productsArray);
            }
        }
        // One last save is done at the end in order to save what's left
        Search::saveIndex($queryArray3);
        Search::setProductsAsIndexed($productsArray);
        // If it has been deleted, the index is created again once the indexation is done
        if (!$dropIndex) {
            $dropIndex = true;
            $result = $db->ExecuteS('SHOW INDEX FROM `' . _DB_PREFIX_ . 'search_index`');
            foreach ($result as $row) {
                if (strtolower($row['Key_name']) == 'primary') {
                    $dropIndex = false;
                }
            }
        }
        if ($dropIndex) {
            $db->Execute('ALTER TABLE `' . _DB_PREFIX_ . 'search_index` ADD PRIMARY KEY (`id_word`, `id_product`)');
        }
        Configuration::updateValue('PS_NEED_REBUILD_INDEX', 0);
        return true;
    }
Example #4
0
    public static function indexation($full = false)
    {
        $db = Db::getInstance();
        if ($full) {
            $db->Execute('TRUNCATE ' . _DB_PREFIX_ . 'search_index');
            $db->Execute('TRUNCATE ' . _DB_PREFIX_ . 'search_word');
            $db->Execute('UPDATE ' . _DB_PREFIX_ . 'product SET indexed = 0');
        } else {
            $products = $db->ExecuteS('SELECT id_product FROM ' . _DB_PREFIX_ . 'product WHERE indexed = 0');
            $ids = array();
            if ($products) {
                foreach ($products as $product) {
                    $ids[] = (int) $product['id_product'];
                }
            }
            if (sizeof($ids)) {
                $db->Execute('DELETE FROM ' . _DB_PREFIX_ . 'search_index WHERE id_product IN (' . implode(',', $ids) . ')');
            }
        }
        $weightArray = array('pname' => Configuration::get('PS_SEARCH_WEIGHT_PNAME'), 'reference' => Configuration::get('PS_SEARCH_WEIGHT_REF'), 'ean13' => Configuration::get('PS_SEARCH_WEIGHT_REF'), 'upc' => Configuration::get('PS_SEARCH_WEIGHT_REF'), 'description_short' => Configuration::get('PS_SEARCH_WEIGHT_SHORTDESC'), 'description' => Configuration::get('PS_SEARCH_WEIGHT_DESC'), 'cname' => Configuration::get('PS_SEARCH_WEIGHT_CNAME'), 'mname' => Configuration::get('PS_SEARCH_WEIGHT_MNAME'), 'tags' => Configuration::get('PS_SEARCH_WEIGHT_TAG'), 'attributes' => Configuration::get('PS_SEARCH_WEIGHT_ATTRIBUTE'), 'features' => Configuration::get('PS_SEARCH_WEIGHT_FEATURE'));
        $products = $db->ExecuteS('
		SELECT p.id_product, pl.id_lang, pl.name pname, p.reference, p.ean13, p.upc, pl.description_short, pl.description, cl.name cname, m.name mname
		FROM ' . _DB_PREFIX_ . 'product p
		LEFT JOIN ' . _DB_PREFIX_ . 'product_lang pl ON p.id_product = pl.id_product
		LEFT JOIN ' . _DB_PREFIX_ . 'category_lang cl ON (cl.id_category = p.id_category_default AND pl.id_lang = cl.id_lang)
		LEFT JOIN ' . _DB_PREFIX_ . 'manufacturer m ON m.id_manufacturer = p.id_manufacturer
		WHERE p.indexed = 0', false);
        $countWords = 0;
        $countProducts = 0;
        $queryArray = array();
        $queryArray2 = array();
        $productsArray = array();
        while ($product = $db->nextRow($products)) {
            $product['tags'] = Search::getTags($db, (int) $product['id_product'], (int) $product['id_lang']);
            $product['attributes'] = Search::getAttributes($db, (int) $product['id_product'], (int) $product['id_lang']);
            $product['features'] = Search::getFeatures($db, (int) $product['id_product'], (int) $product['id_lang']);
            $pArray = array();
            foreach ($product as $key => $value) {
                if (strncmp($key, 'id_', 3)) {
                    $words = explode(' ', Search::sanitize($value, (int) $product['id_lang'], true));
                    foreach ($words as $word) {
                        if (!empty($word)) {
                            $word = Tools::substr($word, 0, PS_SEARCH_MAX_WORD_LENGTH);
                            if (!isset($pArray[$word])) {
                                $pArray[$word] = $weightArray[$key];
                            } else {
                                $pArray[$word] += $weightArray[$key];
                            }
                        }
                    }
                }
            }
            foreach ($pArray as $word => $weight) {
                if (!$weight) {
                    continue;
                }
                $queryArray[] = '(' . (int) $product['id_lang'] . ',\'' . pSQL($word) . '\')';
                $queryArray2[] = '(' . (int) $product['id_product'] . ',(SELECT id_word FROM ' . _DB_PREFIX_ . 'search_word WHERE word = \'' . pSQL($word) . '\' AND id_lang = ' . (int) $product['id_lang'] . ' LIMIT 1),' . (int) $weight . ')';
                // Force save every 40 words in order to avoid overloading MySQL
                if (++$countWords % 40 == 0) {
                    Search::saveIndex($queryArray, $queryArray2);
                }
            }
            if (!in_array($product['id_product'], $productsArray)) {
                $productsArray[] = (int) $product['id_product'];
            }
            // Force save every 20 products in order to avoid overloading MySQL
            if (++$countProducts % 20 == 0) {
                Search::setProductsAsIndexed($productsArray);
                $productsArray = array();
            }
        }
        // One last save is done at the end in order to save what's left
        Search::saveIndex($queryArray, $queryArray2);
        Search::setProductsAsIndexed($productsArray);
        $db->Execute('DELETE FROM ' . _DB_PREFIX_ . 'search_word WHERE id_word NOT IN (SELECT id_word FROM ' . _DB_PREFIX_ . 'search_index)');
        return true;
    }