Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Собираем поисковый механизм на 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 

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 

Комментарии

1.
2.8K
13 марта 2004 года
Arsench
27 / / 13.03.2004
Мне нравитсяМне не нравится
2 января 2008, 06:00:34
Warning: mysql_num_rows(): supplied argument is not a valid MySQL result resource in /home/europeh/public_html/ind.php on line 8



poluchayu ety oshibky kto ne byd mojet pamoch?

i esho
$query = "SELECT blob,identifier FROM sr";

blob i identifier eto imena ili tipi tablic

spasibo
2.
27K
20 марта 2007 года
Бостон
0 / / 20.03.2007
+1 / -0
Мне нравитсяМне не нравится
20 марта 2007, 00:52:34
Есть еще неплохой вариант:
Допустим, пользователь ищет слово "картошка", но набирает "кортошка".
Делаем простую замену, после чего получаем строку такого вида:
к(о|а)рт(о|а)шк(о|а)
SELECT text WHERE text REGEXP 'к(о|а)рт(о|а)шк(о|а)'
Это, конечно, не даст результат при слофоформах, но ошибки точно будет проглатывать
3.
Аноним
Мне нравитсяМне не нравится
25 мая 2006, 12:23:36
Поиск идет просто с учетом точного совмпадения с запросом. Но лди запросы состаляют нечеткие: телевизор LG с плоским экраном..... Если в описании есть ТОЧНАЯ ФОРМА слов, то поиск принесет резултат. Но если в описании встречаются слова:
"телевизионный","плоский","экран", то поиск не выдаст это опиание, хотя речьидет иманно об этом. То есть необходимо добавить еще сначала преобработку поискового запроса на выявление различных офрм написания слов. И уже искать по этим формам. СЛожнее? Зато гораздо эффективнее и полнее получается поиск. А сложнее не на много.
На счетконструкции like "%query%".... Тут будет использоваться полный просмотр ВСЕХ записей, тое сть индекс в этом случае ни к чему. А если записей десятки тысяч, их общий объем ОЧЕНЬ большой, да и запросов поступает много (популярный сайт), то такая конструкция - просто загрузит сервер ОЧЕНЬ сильно. Так что как не курти,, а использовать лучше точные сравнениея, либо такого: like "query%". И естественно сделать индексным полем. Но и в этом случае необходимо разбить все данные из болб-поля в varchar (char), пословно. То есть одно слово - одна запись. Деламем индекс и изем с использование м индекса. РАзмер будет несколько больше у этой таблицы, но зато скорость!!! и еще иного нюансов...
4.
Аноним
Мне нравитсяМне не нравится
12 сентября 2005, 13:02:25
а ещё моно попробовать так:

Код:
WHERE MATCH ($table_serch) AGAINST ('+$text_serch' IN BOOLEAN MODE)
5.
Аноним
Мне нравитсяМне не нравится
2 июня 2005, 18:12:11
Ух! Крепко! Но я делаю
Код:
mysql_query ("SELECT `text` WHERE (`text` LIKE '%text%')");
6.
Аноним
+1 / -0
Мне нравитсяМне не нравится
25 апреля 2005, 16:37:31
Мдеее, тормозить наверно будет - мама не горюй. Думаю есть альтернативные пути.
7.
Аноним
Мне нравитсяМне не нравится
23 апреля 2005, 23:45:30
А сам-то код чего не кинули? Пошагово объяснили, а ПОЛНОСТЬЮ кода нет (
8.
Аноним
Мне нравитсяМне не нравится
16 февраля 2005, 23:06:38
FULLTEXT тоже имеет недостаток. Если мы собираемся хранить статьи в HTML-формате то MySQL проиндексирует теги html точно так же как и любые другие слова. При ручном индексировании этот процесс можно контролировать, н-р можно просто вырезать все теги ф-цей strip_tags
9.
Аноним
Мне нравитсяМне не нравится
11 января 2005, 18:23:09
Не думаю. Как минимум потому что в MySql появился FULLTEXT индекс.
10.
Аноним
Мне нравитсяМне не нравится
11 января 2005, 17:45:07
Интересный поисковый механизм... Он и правда эффективный?
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог