- Подробности
-
Категория: PHP. Базы данных
Собираем поисковый механизм на PHP/MySQL
Итак, у вас полностью динамический сайт, на котором находится большое количество различных данных (любого вида — форумы, статьи и т.п.). Преимущественно большие данные хранятся в 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