У цій статті ми розберемо дієвий спосіб вирішення цієї проблеми.
У цій статті ми розберемо ефективний спосіб вирішення цієї проблеми.
Суть
У момент індексації елемента додаватимемо до таблиці b_search_content_stem наші частини слів. Тобто в нашому випадку для товару з артикулом «Р6543» ми додамо «6543» у пошуковий індекс. Запити «654» та «65» також віддаватимуть товар з артикулом «Р6543».
Оброблювачі - наше все
Як завжди, вирішувати ми будемо обробниками. Оффтоп: іноді бачу проекти взагалі без файлів init.php та своїх кастомних модулів. Як вам вдається без цього сайти збирати?
Будемо слухати 3 події: BeforeIndex, OnBeforeIndexUpdate та OnAfterIndexAdd.
- BeforeIndex — викликається перед індексацією елемента методом CSearch::Index()
- OnBeforeIndexUpdate — викликається перед оновленням пошукового індексу
- OnAfterIndexAdd — викликається після додавання нових даних до пошукового індексу.
На подію BeforeIndex ми перевіримо, що до індексу летить потрібний нам запис і збережемо у статичну змінну дані, які нам знадобляться у наступних подіях. Інакше їх там не дістати
На події OnBeforeIndexUpdate та OnAfterIndexAdd запишемо до таблиці b_search_content_stem те, що нам потрібно. API для цього немає, тому будемо писати чисті SQL-запити. Перевіряв на MySQL з InnoDB таблицею. На решті не факт, що коректно працюватиме
Код оброблювача
Зберігаємо код у файлі /local/php_interface/classes/handlers/search/stemming.php
В якості класу $allowedIblockId необхідно вказати ID інфоблоків, для яких потрібен функціонал.
<!?php namespace Olegpro\Classes\Handlers\Search; use Bitrix\Main\Loader; use Bitrix\Main\Application; use Bitrix\Main\DB\SqlQueryException;
class Stemming { /** * @var array */ protected static $allowedIblockId = array( 1 ); /** * @var */ private static $element; /** * @param array $arFields * @return mixed */ public static function beforeIndex($arFields) { static $allowedIblockId = null; if ($allowedIblockId === null) { $allowedIblockId = array_flip(self::$allowedIblockId); } if ( $arFields['MODULE_ID'] == 'iblock' && isset($allowedIblockId[$arFields['PARAM2']]) && strlen($arFields['ITEM_ID']) > 0 && substr($arFields['ITEM_ID'], 0, 1) != 'S' && Loader::includeModule('iblock') ) { if ($obElement = \CIBlockElement::GetList( array(), array('ID' => $arFields['ITEM_ID']), false, false, array() )->GetNextElement() ) { $element = $obElement->GetFields(); $element['PROPERTIES'] = $obElement->GetProperties(); self::$element = $element; } } return $arFields; } /** * Events: OnBeforeIndexUpdate and OnAfterIndexAdd * @param $indexId * @param $arFields */ public static function beforeIndexUpdate($indexId, $arFields) { if ( isset(self::$element) && is_array(self::$element) && isset(self::$element['PROPERTIES']['ARTICLE']) && strlen(trim(self::$element['PROPERTIES']['ARTICLE']['VALUE'])) && preg_match('~^.*?([0-9.,]+).*?$~', trim(self::$element['PROPERTIES']['ARTICLE']['VALUE']), $m) ) { $word = ToUpper($m[1]); $stemId = \CSearch::RegisterStem($word); if ($stemId > 0) { $connection = Application::getConnection(); $sqlHelper = $connection->getSqlHelper(); try { $thereIs = $connection->queryScalar( sprintf( "SELECT 1 FROM b_search_content_stem WHERE SEARCH_CONTENT_ID = '%s' AND STEM = '%s'", $sqlHelper->forSql($indexId), \CSearch::RegisterStem($word) ) ); if ($thereIs === null) { $connection->query(sprintf( "INSERT IGNORE INTO `b_search_content_stem` (`SEARCH_CONTENT_ID`, `LANGUAGE_ID`, `STEM`, `TF`, `PS`) VALUES ('%s', '%s', '%s', '%s', '%s')", $sqlHelper->forSql($indexId), 'ru', \CSearch::RegisterStem($word), number_format(0.2, 4, ".", ""), number_format(1, 4, ".", "") )); } } catch (SqlQueryException $e) { AddMessage2Log(sprintf("\\%s:\n%s", __METHOD__, $e->getMessage())); } } } self::$element = null; } }
Реєструємо оброблювачі та додаємо клас в автозавантаження
Добавити у /local/php_interface/init.php
<!?php \Bitrix\Main\EventManager::getInstance()->addEventHandler('search', 'BeforeIndex', array('\Olegpro\Classes\Handlers\Search\Stemming', 'beforeIndex') ); \Bitrix\Main\EventManager::getInstance()->addEventHandler('search', 'OnBeforeIndexUpdate', array('\Olegpro\Classes\Handlers\Search\Stemming', 'beforeIndexUpdate') ); \Bitrix\Main\EventManager::getInstance()->addEventHandler('search', 'OnAfterIndexAdd', array('\Olegpro\Classes\Handlers\Search\Stemming', 'beforeIndexUpdate') ); \Bitrix\Main\Loader::registerAutoLoadClasses(null, array( '\Olegpro\Classes\Handlers\Search\Stemming' => '/local/php_interface/classes/handlers/search/stemming.php', ));
На цьому все. Залишилося тільки запустити повну переіндексацію і тепер можна не витрачати життя на вписування у пошук артикулів повністю.
Автор статті: Максименко Олег
Статтю взято з джерела ссылка
