Как ускорить синонимайзер?

12
DG
На сайте с 07.01.2007
Offline
53
1074

Добрый вечер. Я пишу синонимайзер, все вроде бы хорошо, но одно "но": он работает слишком долго. У меня есть база из 18 тысяч слов (плюс синонимы к ним). Я разбиваю всю базу в массивы (один для слова-оригинала, другой для синонимов под тем же номером ячейки). Ну, грубо говоря:

$i = 100;

$words[$i] - слово с ID 100

$syn[$i] - синонимы для слова с ID 100

Почему массив? Потому, что он (теоретически) должен работать наиболее быстро. Но при этом обработка вида ($word - слово, для которого мы ищем синоним):

for ($i = 0; $i < count ($words); $i++){

if ($words[$i] == $word) { /* какие-то действия */ break;}

}

происходит крайне долго. Где-то секунд 40 на одно слово.

Я пробовал загонять синонимы в базу (вдруг MySQL как-то круто оптимизирует запросы), скорость примерно та же (нет выигрыша в 500%, в общем).

Можно ли как-нибудь ускорить поиск по массиву, если только не сменить язык (на C++ например)?

P.S. Пока писал пришла в голову идея, как обычно. Загонять все в массив вида $words['слово-оригинал'] = 'синонимы для этого слова';. Но мне почему-то кажется, что этот способ не ускорит обработку, потому, что таким образом мы просто возложим поиск на интерпретатор, а по длительности он будет таким же.

Хотелось бы выслушать идеи. Спасибо.

Синонимайзер будет публичный и бесплатный, если кого-то интересует.

мой блог - заработок в сети (http://izombie.ru)
wdsg
На сайте с 09.02.2009
Offline
31
#1

Если не сложно, приведите пример структуры таблицы и запроса выборки синонимов, использовавшийся в варианте с БД. Для полноты представления, так сказать.

Проектирование и разработка сложных IT-систем. Вожусь с проблемными задачами.
dkameleon
На сайте с 09.12.2005
Offline
386
#2
DimoninG:

Можно ли как-нибудь ускорить поиск по массиву, если только не сменить язык (на C++ например)?

хотя бы для начала освойте ассоциативные массивы и всю их мощь:

$syn[$words[$i]]

function GetSyn($word) {

return $syn[$word];

}

а то по списку из 18к слов вы до усрачки будете гонять :)

Дизайн интерьера (http://balabukha.com/)
DG
На сайте с 07.01.2007
Offline
53
#3
wdsg:
Если не сложно, приведите пример структуры таблицы и запроса выборки синонимов, использовавшийся в варианте с БД. Для полноты представления, так сказать.

Очень банальное:

word varchar(255) primary key, syn varchar(255)

запрос вроде:

select syn from table where word=''; // точное совпадение

Может быть я сделал что-то не так.

dkameleon
На сайте с 09.12.2005
Offline
386
#4
DimoninG:
Может быть я сделал что-то не так.

здесь всё выглядит правильно.

почему у вас выигрыша нет - загадка.

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

wdsg
На сайте с 09.02.2009
Offline
31
#5

Таблица MEMORY была? Попробуйте, по рекомендации уважаемого dkameleon использовать таки индексы в массиве синонимов. Быстродействие непременно возрастёт. Другое дело, что загоняя в оперативку сервера по полной копии словаря синонимов на запрос, Вы рискуете упереться в память. Особенно если проект вдруг станет популярным.

DG
На сайте с 07.01.2007
Offline
53
#6
dkameleon:
хотя бы для начала освойте ассоциативные массивы и всю их мощь:
$syn[$words[$i]]

function GetSyn($word) {
return $syn[$word];
}

а то по списку из 18к слов вы до усрачки будете гонять :)

Я вот написал соображения по этому поводу :) Ведь ассоциативных массивах на более низких уровнях (на С++ хотя бы, именно на нем написан интерпретатор ПХП), насколько я знаю, не существует ;) Так что это замаскированный вариант первого. Хотя C++ работает все равно быстрее, но ощутимой выгоды врят ли получится.

Позже попробую. Спасибо за подсказку.

DimoninG добавил 03.09.2009 в 02:35

wdsg:
Таблица MEMORY была? Попробуйте, по рекомендации уважаемого dkameleon использовать таки индексы в массиве синонимов. Быстродействие непременно возрастёт. Другое дело, что загоняя в оперативку сервера по полной копии словаря синонимов на запрос, Вы рискуете упереться в память. Особенно если проект вдруг станет популярным.

Нет, не была. Попробую, спасибо.

wdsg
На сайте с 09.02.2009
Offline
31
#7
DimoninG:
Но мне почему-то кажется, что этот способ не ускорит обработку, потому, что таким образом мы просто возложим поиск на интерпретатор, а по длительности он будет таким же.

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


// Готовим тестовый массив. Пусть в нём будет 100000 элементов.
$Arr = array();
for ($i = 0; $i < 100000; $i++) {
$Arr[] = 'value'.$i;
}

// Будем искать в массиве значение $Word
$Word = 'value99999';

// Ваш вариант поиска.
$Start1 = microtime(true);
for ($i = 0; $i < count($Arr); $i++) {
if ($Arr[$i] == $Word) {
echo $i;
break;
}
}
$Time1 = microtime(true) - $Start1;

// А теперь попросим сделать тоже самое встроенную функцию. Как Вы выразились, "просто возложим поиск на интерпретатор"
$Start2 = microtime(true);
$Keys = array_keys($Arr, $Word);
print_r($Keys);
$Time2 = microtime(true) - $Start2;

echo 'Вариант 1: '.$Time1.' Вариант 2:'.$Time2;

У меня первый вариант занимает ~0.04 c., а второй ~0.008 c. Полагаю, это стимулирует к определённым выводам.

P.S. Кстати, чем ближе к началу массива искомое значение, тем менее заметна разница во времени выполнения.

SJ
На сайте с 16.03.2008
Offline
78
#8
wdsg:
Давайте выполним небольшой тест, ведь лучше один раз получить практическое подтверждение, чем месяцами спорить о эффективности того или иного метода.

// Готовим тестовый массив. Пусть в нём будет 100000 элементов.
$Arr = array();
for ($i = 0; $i < 100000; $i++) {
$Arr[] = 'value'.$i;
}

// Будем искать в массиве значение $Word
$Word = 'value99999';

// Ваш вариант поиска.
$Start1 = microtime(true);
for ($i = 0; $i < count($Arr); $i++) {
if ($Arr[$i] == $Word) {
echo $i;
break;
}
}
$Time1 = microtime(true) - $Start1;

// А теперь попросим сделать тоже самое встроенную функцию. Как Вы выразились, "просто возложим поиск на интерпретатор"
$Start2 = microtime(true);
$Keys = array_keys($Arr, $Word);
print_r($Keys);
$Time2 = microtime(true) - $Start2;

echo 'Вариант 1: '.$Time1.' Вариант 2:'.$Time2;

У меня первый вариант занимает ~0.04 c., а второй ~0.008 c. Полагаю, это стимулирует к определённым выводам.

Угу. Особенно если время, затраченное на второй вариант считать без print_r ;)

Насчет SQL - юзать стоит. Особенно если сделать индекс.

Любимый хостинг (http://beget.ru?id=2902) How can we grow old when the soundtrack of our lives is rock-n-roll?
kuzjma
На сайте с 07.12.2008
Offline
24
#9

По моему ассоциативный массив лучший выход, но еще как вариант, можно посмотреть в сторону SQLite, у него выборка данных быстрее.

Серверный скрипт проверки показателей (/ru/forum/451837)
DG
На сайте с 07.01.2007
Offline
53
#10
wdsg:
Давайте выполним небольшой тест, ведь лучше один раз получить практическое подтверждение, чем месяцами спорить о эффективности того или иного метода.

Большое спасибо! Сделали домашнюю работу за меня :)

P. S. Ради теории. Все-таки, я считаю, оно работает быстрее именно потому, что поиск возложен теперь на C++ (интерпретатор), а не на PHP.

12

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий