dimarina.ru

html, css и javascript1   Разное1   Рецепты программирования на PHP или практические советы по программированию7   Управление проектом1  

 

Рецепты программирования на PHP или практические советы по программированию → Обрабатываем фразу для поиска или "примитивный поиск для сайта"

В форму поиска пользователь часто вводит фразу, со знаками препинания, какими-либо символами, а плохой пользователь - с тегами.

Чтобы сформировать более точный запрос требуется разбить вводимую фразу на отдельные слова, а лишние символы убрать.

Для этого я использую несколько функций, приведенных ниже.

1 //разбиваем строку на слова и формируем чистый выходной массив для поиска    
2 //в качестве аргументов передаем строку поиска, минимальное кол-во букв в слове (min) и максимальное (max)
3 function clearWords($str,$min=2,$max=100) {
4     $out = array(); $out1 = array(); 
5     $str normalize($str);
6     $words preg_split('/([^A-zА-я]+)/',$str,-1,PREG_SPLIT_NO_EMPTY);
7         foreach($words as $word)          
8          if (strpos($word,"_")===false && strlen($word)<=self::MAX_WORD_LENGTH && strlen($word)>self::MIN_WORD_LENGTH
9              $out[] = $word;
10     //убираем одинаковые слова
11      array_unique($out);     
12      //переводим все слова в верхний регистр    
13      foreach ($out as $k=>$v$out1[]=rstrtoupper($v);     
14      return $out1;        
15 }
16
17 //дополнительные функции 
18 //эта функция убирает знаки препинания в строке
19 function normalize($str) {         
20     $str preg_replace('/[.;,-:!?\[\]@\(\)]/',' ',$str); //убиваем знаки препинания
21     //пропускаем только символы русского и латинского алфавита, все остальное заменяем на _
22     $str preg_replace('/[^\x7F-\xFFA-z0-9 -]/','_',$str); 
23     return $str;
24 }     
25 //эта функция корректно переводит русские слова в нижний регистр
26 //строки в верхний и нижний регистр (корректно обрабатывает cp1251)
27 function rstrtoupper($str) {    
28     return strtr($str
29         "abcdefghijklmnopqrstuvwxyz".
30         "\xE0\xE1\xE2\xE3\xE4\xE5".
31         "\xb8\xe6\xe7\xe8\xe9\xea".
32         "\xeb\xeC\xeD\xeE\xeF\xf0".
33         "\xf1\xf2\xf3\xf4\xf5\xf6".
34         "\xf7\xf8\xf9\xfA\xfB\xfC".
35         "\xfD\xfE\xfF",
36         "ABCDEFGHIJKLMNOPQRSTUVWXYZ".
37         "\xC0\xC1\xC2\xC3\xC4\xC5".
38         "\xA8\xC6\xC7\xC8\xC9\xCA".
39         "\xCB\xCC\xCD\xCE\xCF\xD0".
40         "\xD1\xD2\xD3\xD4\xD5\xD6".
41         "\xD7\xD8\xD9\xDA\xDB\xDC".
42         "\xDD\xDE\xDF");
43 }

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

Эта функция работает на 10000 циклов 0.1сек (предыдущий код работает за 0.04 сек.)

1 function rstrtoupper($str) {    
2     return strtr(strtoupper($str), '[абвгдеёжзиклмнопрстуфхцчшщьъэюя]''[АБВГДЕЁЖЗИКЛМНОПРСТУФХЦШЩЬЪЭЮЯ]');    
3 }

Теперь осталось считать запрос из формы поиска и состряпать запрос к базе данных

1 //считываем строку, введенную в поисковой форме
2 $search = isset($_REQUEST["search"]) && trim($_REQUEST["search"]) ? trim($_REQUEST["search"]) : FALSE;
3 if($search) {
4     //получаем массов чистых слов
5     $words clearWords($search);
6     //добавляем ограничители для формирования условия WHERE к каждому слову
7     foreach($words as $k=>&$v$v="'".$v."%'";
8     //формируем условие WHERE
9     $where implode(" OR header like ".clearWords($search);
10     //отрезаем первое " OR" из условия
11     $where preg_replace("/^\sOR/","",$where);
12     //формируем окончательный запрос к БД    
13     $query "SELECT * FROM table WHERE ".$where;
14 }

В результате выполнения этого запроса мы получим массив всех строк таблицы table, у которых заголовок хоть одним словом похож на запрос посетителя.

Например, если пользователь ввел в форму поиска словосочетание "Ищу большой дом на Канарах", то запрос будет вида:

1 SELECT FROM table WHERE header like 'ИЩУ%' OR header like 'БОЛЬШОЙ%' OR header like 'ДОМ%' OR header like 'КАНАРАХ%'

В реальной жизни "хороший" поиск устроен немного по другому. Если вкратце, то все материалы сайта проиндексированы заранее и каждое слово в базовой словоформе "уложено" в отдельную индексную табличку, в которой указан идентификатор статьи (товара, новости и т.п.) сайта, идентификатор базовой словоформы, смещение слова относительно начала статьи и еще несколько параметров.

Все словоформы, которые встречаются на сайте, также уложены в отдельную табличку - словарик сайта. Эта таблица содержит все слова, которые встречаются на сайте.

Далее, очищенные слова, которые ввел пользователь, приводятся к основным словоформам, для каждого слова ищется его идентификатор с словарике сайта и по идентификаторам ищутся связи в таблице индексов.

В этом случае поиск уже можно сделать релевантным и с учетом морфологии русского языка.

Также, в результатах поиска не сложно выделить слова, которые задал пользователь.

"Хороший" поиск с учетом морфологии я реализовал в нескольких своих проектах. Например, на сайтах: log-in.ru и sbtrader.ru.

Это отдельная и довольно сложная тема, которую постараюсь написать в следующих материалах.

Комментарии:

14.07.2015 → Karan написал:
Canillg all cars, calling all cars, we're ready to make a deal. http://bxrjxevzvtf.com [url=http://mfujgl.com]mfujgl[/url] [link=http://plaqwpt.com]plaqwpt[/link]

12.07.2015 → Silvanosantos написал:
A really good answer, full of <a href="http://wncdvoprun.com">raiilnaotty!</a>

08.07.2015 → Candid написал:
Dag nabbit good stuff you <a href="http://tylffspvm.com">whreppisnappers!</a>

07.07.2015 → Jonas написал:
That's a clever answer to a tricky qutieson

19.10.2012 → nvdgfhoue написал:
j3K4cx , [url=http://oxfvrrthanlt.com/]oxfvrrthanlt[/url], [link=http://dksryudbnzgc.com/]dksryudbnzgc[/link], http://gvvolrhsbprc.com/

16.10.2012 → dogqucwgxns написал:
oTxHP5 <a href="http://nopoqejgdvux.com/">nopoqejgdvux</a>

15.10.2012 → rzgyhsbbswq написал:
BxgGBl , [url=http://ilbokmsrnnrc.com/]ilbokmsrnnrc[/url], [link=http://jbosttgafuue.com/]jbosttgafuue[/link], http://vdnwhsstppio.com/

14.10.2012 → ympexjnlbex написал:
3IUEfA <a href="http://jdeucdbvsnzp.com/">jdeucdbvsnzp</a>

14.10.2012 → Alejandro написал:
There is a critical shortage of infromaitve articles like this.

Написать комментарий





Включите отображение картинок в браузере
Число на картинке: