Модераторы: korob2001, ginnie

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> нужна помощь 
:(
    Опции темы
DooZ
Дата 14.4.2008, 22:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



задача следующая:

есть файл со словами (очень большой, например 500 мегабайт, или 10.000.000 слов, как пример)
мама смотрит в окно
моя книга очень интересная
книга и авто не совместимы

все слова в столбик

есть второй файл, со словами по которым делать выборку, пример:
авто
окно
книга

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

Код

foreach my $request (keys %request)
{
if ($keyword =~ /(?:^|\s+)$request(?:\s+|$)/i)
{
open(F, ">>$request");
print F "$keyword\n";
close(F);
}


как видите, в первом файле могут быть строки вроде:
книга и авто не совместимы

в свою очередь во втором файле мы видим что нам нужны все строки где есть слово: "авто" и "книга"
т.е. мы должды записать строку: "книга и авто не совместимы" в файл: "авто"
И (!)
эту же строку записать в файл: "книга"

т.е. вариант с объединением всех запросов для нахождения в один регекс не катит т.к. будет найдено только одно совпадение

посоветовали сделать сначала выборку путем комманды: "cat $file|grep -P '(?:^|\s+)(?:окно|авто|книга)(?:\s+|$)' >tmp/complete"
и потом уже разбирать файл complete построчно
НО очень долго получается разбирать его

т.е. cat + grep работает очень быстро
а вот выборка по нужным запросом долго (файл в миллион строк, разбирается около часа)

т.е. получается в данном случае нам надо три запроса:
окно
книга
авто
т.е. если cat + grep насобирал миллион записей, то при выборке будет обработано 3.000.000 записей

у меня этих запросов сотни, соответсвенно кол-во выборок увеличивается не по детски =)

как быть? кто что подскажет?

можно в аську: 9603308 (можно за денежку, если действительно быстро будет работать, о цене договоримся)

заранее благодарю
PM MAIL   Вверх
arto
Дата 14.4.2008, 23:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



grep "\\b$word\\b" ?
+ распарралелить по возможности
PM MAIL ICQ   Вверх
DooZ
Дата 14.4.2008, 23:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



поточнее можно?
мне надо каждую найденую строку У КАЖДОГО запроса записать в свой файл
т.е.
если в файле номер 1 есть строка:
ааа ббб ввв ггг ддд

а в файле 2 в котором нужные мне запросы есть два запроса:
ббб
ддд

надо записать в два файла эту строку
в файл: ббб
и в файл: ддд
PM MAIL   Вверх
arto
Дата 14.4.2008, 23:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



1. поделить второй список по 20 слов, например.
2. запускать по 20 процессов grep с выводом в нужный файл
3. удалить пустые файлы.
4. простой греп быстрее, чем perl regexp
PM MAIL ICQ   Вверх
DooZ
Дата 14.4.2008, 23:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



разделение на процессы не дает скорости, процессор один и толку делить нет, проверено

Добавлено через 2 минуты и 30 секунд
проблемма не у grep, а в том что много запросов нужных мне, и приходится перебирать массив (хеш) и работать с каждым запросом на каждой строке

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

Добавлено через 11 минут и 12 секунд
вот код тот что щас работает:

Код

#!/usr/bin/perl -w

use strict;

my %request;
my $request = "";

open(F, "request");

    while (my $request=<F>)
    {
    chomp($request);
    next if (!$request || $request eq "");
    $request{$request}++;
    }

close(F);

    foreach my $r (keys %request)
    {
    $request .= "$r|";
    }

$request =~ s/\|$//;
####################
my $grep = '(?:^|\s+)(?:'.$request.')(?:\s+|$)';
system("cat $file|grep -P '$grep' >complete");

open(F, "complete");

    while (my $keyword=<F>)
    {
    chomp($keyword);
    next if (!$keyword || $keyword eq "");

#вот место то что тормозит
#оно и понятно, запросов порядка 100 штук, соответственно на каждую строку 100 проверок, как быть???
#а смысл проверок в том что бы взять строку, для каждого нужного мне запроса, а не одну на первый попавшийся

        foreach my $request (keys %request)
        {
            if ($keyword =~ /(?:^|\s+)$request(?:\s+|$)/i)
            {
            open(WRITE, ">>out/$request");
            print WRITE "$keyword\n";
            close(WRITE);
            }
        }
    }

close(F);

PM MAIL   Вверх
arto
Дата 14.4.2008, 23:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



тогда вам надо подготовить списки под задачу заранее.
PM MAIL ICQ   Вверх
DooZ
Дата 14.4.2008, 23:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



т.е. подготовить?

они и так подготовлены
в файле1, список строк на проверку
в файле2, список слов которые мне нужно выдирать из файла1, что тут не подготовлено?

или я чего-то не понимаю, или Вы меня smile
PM MAIL   Вверх
arto
Дата 15.4.2008, 00:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



не понимаете, да.

например -- адреса всех слов в первом файле, с длиной.
тогда сможете сократить перебор по длине.
еще можете проиндексировать по первой букве.

делать это надо не сейчас, а когда собирается первый файл.
PM MAIL ICQ   Вверх
sir_nuf_nuf
Дата 15.4.2008, 00:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 920
Регистрация: 6.1.2008

Репутация: 14
Всего: 31



так...если хотим простое решение, то на мой взгляд их 2
в обоих случаях - 2 цикла , один в другом.

в первом проходим по всем строкам,  для каждой строки ищем ключи:

Код

open STRS, "<first" or die "no first";
open KEYS, "<second" or die "no second";
my @keys = <KEYS>;
chomp @keys;
my %handles = map {open my $fh, ">$_"; $_ => $fh } @keys;
my %regex = map {$_ => qr/$_/} @keys;
foreach my $str (<STRS>) {
    foreach my $key (keys %regex) {
        if ($str =~ $regex{$key}) {
            my $fh = $handles{$key};
            print $fh $str;
        }
    }
}

close STRS;
close KEYS;



или второй вариант - для каждого ключа полностью просматриваем файл с данными
Код

open STRS, "<first" or die "no first";
open KEYS, "<second" or die "no second";
my @keys = <KEYS>;
chomp @keys;
my %handles = map {open my $fh, ">$_"; $_ => $fh } @keys;
my %regex = map {$_ => qr/$_/} @keys;
foreach my $key (keys %regex) {
    seek(STRS, 0,0);
    foreach my $str (<STRS>) {
        if ($str =~ $regex{$key}) {
            my $fh = $handles{$key};
            print $fh $str;
        }
    }
}

close STRS;
close KEYS;


какой из них быстрее зависит от соотношений количества ключей и длинны файла с данными. 
подозреваю, что в большинстве случаев быстрее первый.

есть еще вариант - засунуть перебор шаблонов в регулярку:
Код

open STRS, "<first" or die "no first";
open KEYS, "<second" or die "no second";

my @keys = <KEYS>;
chomp @keys;
my %handles = map {open my $fh, ">$_"; $_ => $fh } @keys;
my $regex = "(" . join("|", @keys) . ")";
my $compiled = qr/$regex/;
foreach my $str (<STRS>) {
    if (my @matches = $str =~ /$compiled/g ) {
        foreach my $file (@matches) {
            my $h = $handles{$file};
            print $h $str;
        }
    }
}

close STRS;
close KEYS;

здесь перебор ключей осуществляется движком regex. Не думаю, что он делает оптимизацию для поиска 
по нескольким ключам, скорее всего просматривает строку на наличие каждго ключа последовательно.


Если вам нужен _быстрый_ поиск по нескольким ключам - заведите новый топик и изучите алгоритмы =)


--------------------
user posted image
user posted image
PM MAIL Jabber   Вверх
DooZ
Дата 15.4.2008, 01:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



2sir_nuf_nuf
первый вариант теряет всю скорость, если регекс делать таким:
(?:^|\s+)$_(?:\s+|$)
что ознатает что нужный запрос может быть
в начале, после него могут быть пробелы или конец текста
или в конце
или перед и после пробелы и т.д.

а так и надо искать, ибо твой вариант где просто $_ будет искать например:
запрос: машина

-> у меня есть машина (годится)
-> у друга есть машина (годится)
-> естьмашина (не годится, а твой вариант возьмет его!)

есть еще мысли как ускорить?
PM MAIL   Вверх
DooZ
Дата 15.4.2008, 01:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



третий вариант очень быстрый, но в нем минус, если он встречает первое нужное слово в строке, то если даже в этой строке есть второй нужное слово, он его уже не запишет!
PM MAIL   Вверх
DooZ
Дата 15.4.2008, 02:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



вроде заработал третий пример вот так:

    foreach my $str (<STRS>)
    {
        if ($str =~ /$compiled/igs)
        {
            foreach my $file (split(/\s+/, $str))
            {
            next unless (exists $handles{$file});
            my $h = $handles{$file};
            print $h $str;
            }
        }
    }

скорость на 160 запросах, и 100.000 строк файл первый, 1.5 секунды
первый пример справлялся за 60 секунд
PM MAIL   Вверх
sir_nuf_nuf
Дата 15.4.2008, 08:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 920
Регистрация: 6.1.2008

Репутация: 14
Всего: 31



насчет третьего варианта - ты не прав. \
там специально стоит модификатор g и поиск в списковом контексте.
так что третий вариант не будет останавливаться после первого совпадения.

(?:^|\s+)$_(?:\s+|$) -- на счет этого я не подумал.. действительно нужно искать слова целиком

только шаблон этот записывается так:
\b$_\b


--------------------
user posted image
user posted image
PM MAIL Jabber   Вверх
DooZ
Дата 15.4.2008, 11:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



а ты проверь третий пример, без моего добавления. он именно находит первое совпадение и все...
PM MAIL   Вверх
DooZ
Дата 15.4.2008, 11:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 206
Регистрация: 25.11.2005

Репутация: нет
Всего: 1



щас проверил четвертый вариант

Код

open(F, "request");

    foreach my $request (<F>)
    {
    chomp($request);
    next if (!$request || $request eq "");
    open my $fh, ">out/$request";
    $request{$request} = $fh;
    }

close(F);

open STRS, "base" or die "no first";

    foreach my $str (<STRS>)
    {
        foreach my $file (split(/\s+/, $str))
        {
        next unless (exists $request{$file});
        my $h = $request{$file};
        print $h $str;
        }
    }

close STRS;



работает на 100к базе при 158 запросах за 0.6 секунды
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Perl"
korob2001
sharq
  • В этом разделе обсуждаются общие вопросы по языку Perl
  • Если ваш вопрос относится к системному программированию, задавайте его здесь
  • Если ваш вопрос относится к CGI программированию, задавайте его здесь
  • Интерпретатор Perl можно скачать здесь ActiveState, O'REILLY, The source for Perl
  • Справочное руководство "Установка perl-модулей", можно скачать здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, korob2001, sharq.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Perl: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0634 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.