Главная | Учебник | Статьи | FAQ | Книги | Ссылки |
Собираем поисковый механизм на PHP/MySQL
Денис Рощин denis@komkon.org
"Основная проблема ЭВМ -
Вводишь мусор, получаешь мусор"
Дик Фейнман
Итак, у вас полностью динамический сайт, на котором находится большое количество различных данных (любого вида - форумы, статьи и т.п.). Преимущественно большие данные хранятся в BLOBах (чего и вам наверное не удалось избежать), следовательно невозможно сделать ничего полезного, используя стандартный вид запроса LIKE %searchword% так как вывод не будет соответствующим (то есть релевантным).
Должен быть другой путь. И он есть :-).
Шаг один: Редукция "посторонних" слов из blob'а
Первая проблема заключается в том, что данные переполнены посторонними словами (предлогами, междометиями..), такими как "как, где, а, и". Эти слова помогают нам, людям, общаться но не имеют ничего общего с нашей проблемой, когда нужно получить вывод по релевантности.
Ниже, в конце статьи, я приложил мой личный список таких, "посторонних", слов.
Итак, мы сейчас пытаемся сделать - выбрать из данных эти слава, и, - в ново созданной табличке с двумя полями: словом и его указателем (счетчиком). Нам необходимо что-то вроде такого:
+-----+---------------+ | qid | word | +-----+---------------+ | 6 | links | | 5 | Fire | | 5 | topics | | 5 | related | | 5 | Shakespeare | | 4 | people | | 4 | Knowpost | | 3 | cuba | | 3 | cigar | +-----+---------------+
Так, давайте создадим собственно табличку:
CREATE TABLE search_table( word VARCHAR(50), qid INT)
Следующим шагом будет - обработать и переместить данные в нашу таблицу search_table.
<?php $query = "SELECT blob,identifier FROM your_table"; $result = mysql_query($query); $number = mysql_numrows($result); $j = 0; WHILE ($j < $number) { /* Наш "blob" */ $body = mysql_result($result,$j,"blob"); /* Наш "identifier */ $qid = mysql_result($result,$j,"qid"); /* Открыть файл с посторонними словами в массив */ $noise_words = file("noisewords.txt"); $filtered = $body; /* Помещаем пробел перед первым словом */ $filtered = ereg_replace("^"," ",$filtered); /* Теперь мы избавились от ненужных слов и можем поместить то, что осталось - в массив */ /* Пробегаем циклом и удаляем неправильные слова */ for ($i=0; $i < count($noise_words); $i++) { $filterword = trim($noise_words[$i]); $filtered = eregi_replace(" $filterword "," ",$filtered); } $filtered = trim($filtered); $filtered = addslashes($filtered); $querywords = ereg_replace(",","",$filtered); $querywords = ereg_replace(" ",",",$querywords); $querywords = ereg_replace("\?","",$querywords); $querywords = ereg_replace("\(","",$querywords); $querywords = ereg_replace("\)","",$querywords); $querywords = ereg_replace("\.","",$querywords); $querywords = ereg_replace(",","','",$querywords); $querywords = ereg_replace("^","'",$querywords); $querywords = ereg_replace("$","'",$querywords); /* Теперь мы должны иметь что-то типа 'Word1','Word2','Word3' так что теперь мы можем загнать все в массив */ $eachword = explode(",", $querywords); /* наконец-то мы можем пробежаться по массиву и поместить каждое слово в базу данных, вместе со счетчиком */ for ($k=0; $k < count($eachword); $k++) { $inputword = "INSERT INTO search_table VALUES($eachword[$k],$qid)"; mysql_query($inputword); } /* Пробежаться по циклу еще разок с новыми данными */ $j++; } ?>
Этот скрипт обрабатывает ваши старые данные. Необходимо добавить подобную же обработку на добавление данных в вашу базу данных (когда её вводит пользователь, хозяин - или кто угодно) - так, чтобы база обновлялась в процессе.
Шаг два: Поиск в таблице
Теперь мы имеем таблицу с ключевыми словами и счетчиками. Как собрать запрос?
Во-первых, необходимо переформатировать (нет, не жесткий диск) - слова поиска в строку вида 'word1','word2','word3' и записать её в $querywords.
Далее использовать подобный ниже следующему запрос:
SELECT count(search_table.word) as score, search_table.qid,your_table.blob FROM search_table,your_table WHERE your_table.qid = search_table.qid AND search_table.word IN($querywords) GROUP BY search_table.qid ORDER BY score DESC";
Вывод же может быть, например, таким:
<?php $getresults = mysql_query($search); $resultsnumber = mysql_numrows($getresults); IF ($resultsnumber == 0) { PRINT "Ничего не найдено. " ."Попробуйте использовать другие ключевые слова."; } ELSEIF ($resultsnumber > 0) { PRINT "Поиск вернул $resultsnumber результатов<BR>" ."Расположение по релевантности <BR><BR>"; for($count = 0; $count < $resultsnumber; $count++) { $body = mysql_result($getresults,$count,"blob"); $qid = mysql_result($getresults,$count,"qid"); $body2print = substr($body, 0, 100); $cnote = $count+1; PRINT "$cnote. <a href=yourcontent.php3?qid=$qid> " ."<i>$body2print...</i></a><BR>"; } } ?>
Итак, у вас есть механизм поиска по ключевым словам в вашей базе данных по релевантности (актуальности запросу).
Конечно, это не Yandex и не Google :-))).
Но у нас теперь есть небольшой поисковый механизм, который вполне быстро и грамотно работает и вполне подходит обычному пользователю (который не собирается использовать логические элементы и т.п.).
Вот лист моих "посторонних" слов:
noisewords.txt -------------- a about after ago all almost along also am an and answer any anybody anywhere are aren't around as ask at bad be been before being best better between big but by can can't come could couldn't day did didn't do does don't down each either else even ever every everybody everyone far find for found from get go going gone good got had has have haven't having her here hers him his home how href I if in into is isn't it its know large less like little looking look many me more most must my near never new news no none not nothing of off often old on once only or other our ours out over page please question rather recent she should sites small so some something sometime somewhere than true thank that the their theirs them then there these they this those though through thus time times to too under until untrue up upon use users version very via want was way web were what when where which who whom whose why wide will with within without world worse worst would www yes yet you your yours