Текстовый файл с IP -> Разделение на хиты и уники

nick4

Guest
Текстовый файл с IP -> Разделение на хиты и уники

Возникла проблема с обработкой базы данных = разделение на хиты и уники:

Есть текстовый файл с IP адресами (собираются за текущий день) раз в пол часа собираем информацию о уникальных и не уникальных посетителях. Для этого написал простенькую функцию:

PHP:
function ip2uniq($file) {
 $f=file($file);$i=0;$h=0;
 $u=array();
 foreach($f as $r) {
  $r=rtrim($r);
  if (empty($r)) continue;
  if (!isset($u[$r])){$h++;$u[$r]=0;}
  $i++;
 }
 return array('uniq' => $u, 'hits' => $i);
}
все конечно-же работает, проверил на файле со 100.000 ip - запрос примерно 7-10 секунд. однако эта-же функция на базе из 1 млн IP просто вешает проц, причем, что интересно - функция set_time_limit игнорируется. И виснет она не при переборе IP-шников, а еще только при чтение файла функцией file.

Вот думаю - что делать? в связи с чем file виснет?
Как можно оптимизировать работу скрипта?
Может стоит использовать для испорта MySQL? - но что-то мне не очень хочется.. и будет-ли быстрее?

И попутно вопросы:
1. Стоит-ли использовать заместо разделителя строк "\n" например ":" и затем разбивать строку не функцией file, а explode + file_get_contents?
2. Будет лучше, если я сделаю базу не из IP, а из ip2long?
 

SelenIT

IT-лунатик :)
1. Вроде бы по теме - коммент к [m]file[/m] от justin at visunet dot ie (20-Mar-2003 12:36).
 

nick4

Guest
Автор оригинала: Фанат
читай файл частями.
Попробовал сделать так, разбор 1 млн строк занимает ~40-55 sec.

PHP:
# $file = Файл;
# $d = Разделитель IP-адресов;
function ip2uniq($file, $d) {
 $i=0;$h=0;   # Хиты / Уники
 $u=array();  # Массив ключей (IP-адресов);
 $j='';
 
 $f = fopen($file,'r');
 while (!feof($f)) {
  $o = $j.fgets($f,100000); # $j-обрезанная строка + чтение текущего блока
  $a = strrchr($o,$d);      # Последнее вхождение разделителя "$d" (оставш. обрезанная строка отправляется в след. цикл)
  $s = strlen($a);          # Длина обрезанной строки
  $j = substr($a,1,$s);     # Обрезанная строка, которую прибавляем в начале след. цикла
  $o = substr($o,0,-$s);    # Полная строка, целых IP, разделенных "$d"

   foreach(explode($d,$o) as $r) {
    if(!isset($u[$r])){$h++;$u[$r]='';}
    $i++;
   }
 }
 fclose($f);
 return array('uniq' => $h, 'hits' => $i);
}

print_r(ip2uniq('ips.txt',':'));
До этого еще не использовал fgets, может можно сделать рациональнее чем прибавлять остаток строки предыдущего цикла? или как-нибудь оптимальнее этот код сделать?
 

Фанат

oncle terrible
Команда форума
переводи айпишник в int, int - в binary вид, и записывай в бинарный файл :)
таким образом ты получишь во-первых, фиксированный размер записи, а во-вторых, в 4 раза меньший объем - 4 байта.
 

nick4

Guest
не могу поверить своим глазам :)
спасибо большое.
 

nick4

Guest
нет, к сожалению не стало.
меня удивило то, что IP можно к 4м байтам привести.
вообщем базу маленькую он читает, но уже на 0.5 млн загинается сверять бинарные ключи массива :) Я сомневаюсь, что распаковывая их или приводя к bin2hex это даст большую производительность. Вернее даже не сомневаюсь - точно не даст. Насколько я понял реализовывается это так?

PHP:
function ip2uniq($file) {
 $i=0;$h=0;$u=array();
 $f=fopen($file,'rb');
 while($o=fread($f,4)){if(!$u[$o]){$h++;$u[$o]='';}$i++;}fclose($f);
 return array('uniq' => $h, 'hits' => $i);
}
 

SiMM

Новичок
> Я сомневаюсь
А ты не сомневайся. Если хорошенько продумать алгоритмы и структуру данных, должно быть вполне шустро.
 

Фанат

oncle terrible
Команда форума
Я одного не пойму - откуда у него берется миллион уников?
 

nick4

Guest
а по сколько надо читать? :)

Если хорошенько продумать алгоритмы и структуру данных, должно быть вполне шустро.
а какая структура данных? ну все IP 4 байта пишутся в один файл, тут разве можно струтуру организовать? или имеется ввиду сортировка?
 

Фанат

oncle terrible
Команда форума
более крупными кусками.
ты лучше скажи - откуда такую цифру высосал - миллион уников за полчаса?
 

nick4

Guest
Насколько я понял идею:

1. Приводим IP к INT с помощью функции ip2long
2. Полученное число пакуем функцией pack('L');
3. Добавляем к остальным записям в файл.

скрипт который будет подсчитывать уники
1. Проходится по бинарному списку IP каждые 4 символа
2. Проверяем есть ли такой ключ в массиве
3. Добавляем новый ключ, если такой не найден

как можно читать не по 4 символа?
ведь упаковывается каждый IP отдельно?

-~{}~ 27.02.05 23:56:

да не важно откуда цифра. я поставил себе задачу найти оптимальный вариант для любой цифры :)
 

Фанат

oncle terrible
Команда форума
мне не нравится, что ты желаешь ответов на свои вопросы, и кладёшь болт с прибором на те, которые задают тебе

-~{}~ 27.02.05 23:58:

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

поставил? решай. сам.
 

nick4

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

то что вы специально провоцируйте авторов топиков на конфликты - для меня не секрет, и поэтому я со всей серьезностью подхожу к написанию вопросов и решаю их сам (с помощью ваших "подсказок") по возможности. Разве не в этом заключается главная идея форума phpclub'a?

Год назад я бы назвал всех тут моральными уродами, которые сливают свою злость на новичках - однако сейчас мое мнение поменялось с точностью до наоборот. Я полностью поддерживаю ваши принципы.

откуда такую цифру высосал - миллион уников за полчаса?
Все просто: 10 тысяч обрабатываются в секунду, 1 млн - это ресурсоемкая операция, и она дает большее представление об оптимальности чем первая. я не говорю что у меня 1 млн уников за пол часа, я ищу реальное решения на 200-300 тысяч.
 

Фанат

oncle terrible
Команда форума
все равно непонятно.
у тебя статистика сливается за полчаса.
после неё должна остаться общая цифра и файл обнулиться.
откуда за полчаса наберется 300 тыс?
1 млн - это ресурсоемкая операция, и она дает большее представление
это НЕВЕРНЫЙ вывод.
с чего ты взял, что загрузка возрастает линейно?
 

nick4

Guest
нет, она не обнуляется раз в пол часа, обнуляется она только за сутки и сводная информация кладется уже на постоянное хранение в БД, иначе как я могу считать суточных уникальных и не уникальных IP?

с чего ты взял, что загрузка возрастает линейно?
я не имел ввиду что нагрузка возрастает линейно,
просто на 100k униках я не почувствую разницы времени выполнения скрипта. Например второй мой вариант выполняется 40-50 секунд, если я напишу такой что-бы выполнялся 30-40 секунд - я сразу замечу разницу.
 
Сверху