PHP

Релевантный поиск по сайту (Yandex API + PHP +MySql)

Поиск по сайту – необходимый инструмент при создании любого сайта (от визитки до социальной сети). Этому посвящено уже много статей, найти которые не составит для вас труда, но все они рассказывают об очень посредственном поиске. Я хочу рассказать о том как легко и без особых усилий вы можете сделать умный поиск на своем сайте. Под умным поиском я понимаю следующее:

1) проверка правописания в поисковой фразе
2) выделение корней значимых слов (stemming)
3) релевантный поиск по значимым словам

1) Проверку правописания выполним с помощью яндекс сервиса Speller (подробная документация)
Как мы видим в описании api yandex, нам необходимо отправить get запросом текст который нужно проверить в ответ мы получим данные по проверке (в документации все подробно описано поэтому не буду вдаваться в подробности). $str – поисковая фраза которую нужно проверить на правописание. Ответ от сервиса я получаю в формате json, если есть варианты исправления правописания то вывожу их на экран:
$checker=json_decode(file_get_contents("http://speller.yandex.net/services/spellservice.json/checkText?text=".urlencode($str)));
$checked_str=$str;
foreach($checker as $word) {
  $checked_str=str_replace($word->word,$word->s[0],$checked_str);
}
if(mb_strtolower($checked_str,'utf8')!=mb_strtolower($str,'utf8') && !empty($checked_str)) {
  echo "Возможно вы имели ввиду: <a href=\"/search/$checked_str\">$checked_str</a>";
}

2) Выделим корни значимых слов (stemming)
Для этого нам понадобится готовый класс стемминга на php.
$stemming= new Stemming();
$stem_str=$stemming->stem_string($str);

3) Релевантный поиск организуем с помощью mysql и php. Генерируем запрос к базе в котором будем также рассчитывать коеффициент релевантности найденного результата. Коэффициент релевантности для каждой колонки указывается в массиве. Причем полное соответствие поисковому запросу будет иметь больший коэффициент релевантности чем найденное одно или несолько слов из запроса. Для колонки с названием продукта я поставил больший коэффициент чем за колонку с описанием, что тоже вполне логично чтоб поиск по сайту был более адекватным.
$search_req = " AND ( ";
$search_array = explode(" ", $stem_str);
 
$search_str=preg_replace("/[^а-яА-Яa-zA-z0-9\-]/ui","%",$stem_str); //заменяем все знаки кроме цифр и букв на % (любое кол-во любых символов)
 
// массив колонок по которым ищем и их коэффицент релевантности
$search_columns=array(
  'prod.title'=>'20',
  'prod.small_descr'=>'10',
  'prod.articul'=>'15',
  'prod.maker'=>'15',
  'sscat.title'=>'10',
  );
 
$select =", ( 0";
$search_req_arr=array();
 
foreach($search_columns as $col=>$coeff) {
  // полнотекстовый
  $select.= " + IF ($col LIKE '".$search_str."', $coeff*3, 0)";
  $search_req_arr[]= " $col LIKE '%".$search_str."%'";
 
  // для отдельного слова
  $word_coeff=round(($coeff/count($search_array)),2);
 
  foreach($search_array as $word) {
    $select .= "+ IF ($col LIKE '%".$word."%', ".$word_coeff.", 0)";
    $search_req_arr[] = "$col LIKE '%".$word."%'";
  }
}
$select.=") AS `relevant`";
$search_req .=implode(" OR ",$search_req_arr);
$search_req .= ")";
 
$query="SELECT prod.id, prod.title, prod.price, prod.description prod.isnew, prod.ishit, prod.small_descr $select
FROM ss_products prod
WHERE prod.status = '1' $search_req
ORDER BY relevant DESC LIMIT 0, 20";

В итоге получился вот такой запрос в базу данных:
SELECT prod.id, prod.title, prod.price, prod.description prod.isnew, prod.ishit, prod.small_descr ,
( 0 + IF (prod.title LIKE 'насос%вод', 20*3, 0)+ IF (prod.title LIKE '%насос%', 10, 0)+
IF (prod.title LIKE '%вод%', 10, 0) + IF (prod.small_descr LIKE 'насос%вод', 10*3, 0)+
IF (prod.small_descr LIKE '%насос%', 5, 0)+ IF (prod.small_descr LIKE '%вод%', 5, 0) +
IF (prod.articul LIKE 'насос%вод', 15*3, 0)+ IF (prod.articul LIKE '%насос%', 7.5, 0)+
IF (prod.articul LIKE '%вод%', 7.5, 0) + IF (prod.maker LIKE 'насос%вод', 15*3, 0)+
IF (prod.maker LIKE '%насос%', 7.5, 0)+ IF (prod.maker LIKE '%вод%', 7.5, 0)) AS `relevant`
FROM ss_products prod
WHERE prod.status = '1' AND (
prod.title LIKE '%насос%вод%' OR prod.title LIKE '%насос%' OR prod.title LIKE '%вод%' OR
prod.small_descr LIKE '%насос%вод%' OR prod.small_descr LIKE '%насос%' OR prod.small_descr LIKE '%вод%'
OR prod.articul LIKE '%насос%вод%' OR prod.articul LIKE '%насос%' OR prod.articul LIKE '%вод%'
OR prod.maker LIKE '%насос%вод%' OR prod.maker LIKE '%насос%' OR prod.maker LIKE '%вод%'
)
ORDER BY relevant DESC LIMIT 0, 20

Не бойтесь не смотря на много IF, запрос отрабатывает очень быстро и хорошо справляется с задачей организации релевантного поиска на сайте.

В моем случае в поисковом запросе я набрал фразу нососы для воды, специально сделав ошибку в одном слове. После прохождения через yandex speller скрипт мне предложил правильный вариант насосы для воды. Затем поисковая фраза прошла через stemming и на выходе отдала вразу насос вод. По этой фразе мы и выполняем релевантный поиск по сайту. В моем случае с увернностью можно сказать что в результате найдено то что искал пользователь, когда коэффициет релевантности больше 70.
Надеюсь теперь больше сайтов будут иметь адекватный красивый поиск.
Добавлено: 13 Сентября 2013 12:47:23 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...