| Добрый день.
У меня на сайте есть небольшая текстовая база (~1000 master записей и еще ~600 detail). На сайте есть поиск. Сделан по следующей схеме: сначала ищется в Master записях (ищется в разных полях, в зависимости от того в каком поле найдено Rank умножается на весовой коэффициент) затем ищется в Detail и по MasterID (ссылке на Master запись в Detail) ищутся еще записи, которые добавляются к уже найденному. Потом удаляются дубликаты и сортируется о Rank'у.
Поиск сделан именно так, чтобы если поисковой запрос был найден в названии книги (условно) этот результат был в выдаче выше, чем если в в описании, а если в комментарии - ниже, чем если в описании. Т.е. Релевантность. Также в скрипте производится цитаты, тоже довольно требовательный, надо полагать, процесс.
Теперь о проблеме - стал замечать, что иногда у меня поиск не работает - стал выяснять, говорит не хватает памяти. У хостера установлено ограничение на 10 Mb для PHP. Теперь не знаю что и делать.
Подскажите как такие проблемы вообще решать?
Приведу код (сильно не пинайте пожста):
<?php
....
// Получение
$keys = str_replace(array("'", '"', ';', ','),
array('', '', ' ', ' '),
trim($_GET['q']));
$keys = explode(' ', $keys);
$keys = array_unique($keys);
$key_count = count($keys);
// Считаем длинну слов для поиска
$key_count = count($keys);
for($i=0; $i<$key_count; $i++) {
$nkeys[$i][0] = strlen($keys[$i]);
$nkeys[$i][1] = $keys[$i];
}
// Отсортируем по длинне ключевых слов и выделим пять самых больших слов
rsort($nkeys);
unset($keys);
if($key_count>5) $key_count = 5;
for($i=0; $i<$key_count; $i++) {
$keys[$i] = $nkeys[$i][1];
// Это для вывода
$akeys .= $keys[$i]." ";
$bold_keys[] = "<strong>".$keys[$i]."</strong>";
}
unset($nkeys);
$keys = array_slice($keys, 0, 5);
// Если самое длинное слово короче 4 символов, вернем предупреждение
global $bold_keys;
$akeys = substr($akeys, 0, strlen($akeys)-1);
$max_length = strlen($keys[0]);
if($max_length<=3) {
die("Слишком короткие слова в поисковом запросе, как минимум одно слово должно быть длиннее 3 символов");
}
// У нас будет отдельный поисковой запрос для каждого слова
for($i=0; $i<$key_count; $i++) {
$key = $keys[$i];
$query = "# Поиск в базе с дубликатами
SELECT `Id`, 2 AS `Rank` FROM `books` WHERE `bookName` LIKE \"%$key%\" UNION
SELECT `Id`, 1 AS `Rank` FROM `books` WHERE `bookAuthors` LIKE \"%$key%\" UNION
SELECT `Id`, 0.5 AS `Rank` FROM `books` WHERE `bookYear` LIKE \"%$key%\" UNION
SELECT `Id`, 0.7 AS `Rank` FROM `books` WHERE `bookDescript` LIKE \"%$key%\" UNION
SELECT MIN(`bookId`) AS Id, COUNT(*)/5 AS `Rank` FROM `comments` WHERE `aText` LIKE \"%$key%\" GROUP BY `bookId`, `aText`";
$result = mysql_query($query) or die("Query failed : " . mysql_error());
while($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
$sresult[] = $row;
}
}
if(count($sresult)>0) {
// Теперь нужно пересчитать релевантность: если Id посторяется - сложить Rank и оставить одну запись
$i = 0;
while(isset($sresult[$i])) {
$temp_count = count($sresult); // Потому-что размер массива мужет уменьшиться
for($j=$temp_count-1; $j>$i; $j--) {
if($sresult[$i]['Id']==$sresult[$j]['Id']) {
$sresult[$i]['Rank'] += $sresult[$j]['Rank'];
array_splice($sresult, $j, 1);
}
}
$i++;
}
// Отсортируем по релевантности
function wy_cmp($a, $b) {
if ($a['Rank'] == $b['Rank']) {
return 0;
}
return ($a['Rank'] < $b['Rank']) ? 1 : -1;
}
usort($sresult, "wy_cmp");
$sresult = array_slice($sresult, 0, 20);
// Получение небольшой цитаты с выделенными ключевыми словами
function getQuoting($bookId, $keys) {
global $bold_keys;
// Получим полный текст описания книги из авторов, названия, года, описания и комментариев
$result = mysql_query("SELECT * FROM `books` WHERE `Id`=$bookId");
$result = mysql_fetch_array($result, MYSQL_ASSOC);
$bookDescript = $result['bookDescript'];
$text = $result['bookAuthors'].' / '.$result['bookName'].' / '.$result['bookYear']."\n".$result['bookDescript']."\n";
$result = mysql_query("SELECT * FROM `comments` WHERE `bookId`=$bookId");
while($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
$text .= $row['aText']."\n";
}
// Теперь сделаем цитату: слева и справа от ключевых слов оставим по 20-25 символов
$quote_left = 25; // количество символов слева и справа от ключевых слов
for($i=0; $i<count($keys); $i++) {
$key_pos = strpos(strtolower($text), strtolower($keys[$i]));
// Заполняем массив $anchors - это предполагаемые позиции начала и конца цитаты
if($key_pos !== FALSE) {
if(($key_pos - $quote_left)<0) {
$anchors[] = 0;
} else {
$anchors[] = $key_pos - $quote_left;
}
if(($key_pos + strlen($keys[$i]) + $quote_left)>strlen($text)) {
$anchors[] = strlen($text);
} else {
$anchors[] = $key_pos + strlen($keys[$i]) + $quote_left;
}
}
}
// Если цитаты пересекаются - объеденим их
for($i=1; $i<count($keys); $i=$i+2) {
if((isset($anchors[$i+1])) & ($anchors[$i]-$anchors[$i+1]>=0)) {
array_splice($anchors, $i, 2);
}
}
// Формирование текста цитаты
for($i=0; $i<(count($anchors)-1); $i=$i+2) {
$quote .= '... '.str_replace($keys, $bold_keys, substr($text, $anchors[$i], $anchors[$i+1]-$anchors[$i]))." \n";
}
// Если цитата пустая просто выведем первые 200 символов описания
if(($quote=='... ') | ($quote=='')) {
$quote = substr($bookDescript, 0, 200);
}
return $quote." ...";
}
// Составляем вывод вместе с цитатами
$list_code = '<div class="title">Результаты поиcка по запросу: '."'$akeys'".'</div>'."\n<ol>";
for($j=0; $j<count($sresult); $j++) {
$list_code .= '<li> <a href="'.SITE_WWW.'book.php?id='.$sresult[$j]['Id'].'">'.
getBook($sresult[$j]['Id'], 'bookAuthors').' / '.getBook($sresult[$j]['Id'], 'bookName').' / '.
getBook($sresult[$j]['Id'], 'bookYear').'</a></li>'.
'<div class="search_quote">'.getQuoting($sresult[$j]['Id'], $keys)."</div>\n";
$i++;
}
$list_code .= '</ol>';
}
// К выдаче внутреннего поискового движка добавим не более 10 результатов поиска от Yandex
|
.....
?> | |