Импорт данных файла журнала в приложение

Мой файл данных: voices.txt состоит из строк, идентичных:

VOTE 1168241980 Campaign:ssss_uk_01B Validity:during 
Choice:Tupele CONN:MIG00VU MSISDN:00088866655598 
GUID:A34-FDS87-FHDHDH-DHDHDHD0 Shortcode:63334

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

Поля:

CONN:MIG00VU MSISDN:00088866655598 
GUID:A34-FDS87-FHDHDH-DHDHDHD0 Shortcode:63334

не используются для этого упражнения.

#!/usr/bin/perl 

use warnings;
use strict;
use Switch;
use DBI();

#
# _voting.pl
#

# Connect to the database.
my $dbh = DBI->connect("DBI:mysql:database=sms_voting;host=localhost",
                    "sisisi", "*********",
                    {'RaiseError' => 1});

my $sth = $dbh->prepare("INSERT INTO voting 
(epoch, validity, choice, campaigns_id, candidates_id ) VALUES (?,?,?,?,?)");

open (LOGFILE, '/var/www/voting/votes.txt') or die("Could not open log file.");

my $errors = 0;
my $campaign_id = 0;
my $candidate_id = 0;

foreach my $line (<LOGFILE>) {  

    my ($vote, $epoch, $campaign, $validity, 
 $choice, $CONN, $MSISDN, $GUID, $Shortcode) = split(' ', $line);

# parse the field:value entries...
$campaign = substr $campaign, 8, 11, '';
$validity = substr $validity, 9, 6, ''; # during
$choice = substr $choice, 7, 10, ''; # Brown

# case statements to define correct foreign keys...
 switch ($campaign) {
        case ("ssss_uk_01B")    { $campaign_id = 1 } 
        case ("ssss_uk_01C")    { $campaign_id = 2 } 
        case ("ssss_uk_01D")    { $campaign_id = 3 } 
        case ("ssss_uk_01E")    { $campaign_id = 4 } 
        case ("ssss_uk_01F")    { $campaign_id = 5 } 
        case ("ssss_uk_01G")    { $campaign_id = 6 } 
}

switch ($choice) {
        case ("Brown")      { $candidate_id = 1 } 
        case ("Cameron")    { $candidate_id = 2 } 
        case ("Balls")      { $candidate_id = 3 } 
        case ("Green")      { $candidate_id = 4 } 
        case ("Boring")     { $candidate_id = 5 } 
        case ("Tupele")     { $candidate_id = 6 } 
}

if ($epoch && $validity && $choice && $campaign_id && $candidate_id ) {

    $sth->execute($epoch, $validity, $choice, $campaign_id, $candidate_id);
    # debug
    print "$epoch $validity $choice \n"; # 1161048980 during Green
    next;
} 

$errors++;
 }

close (LOGFILE);

# debug
print qq(errors=$errors\n);

Для каждого цикла foreach переменные $campaign и $choice обрабатываются операторами switch, чтобы определить номера кандидатов_идентификаторов и кампаний_идентификаторов. Эти внешние ключи будут отображаться в таблицах кандидатов и кампаний соответственно.

см.: http://acookson.org/wp-content/themes/cookie_23112012/img/sms_voting.png для модели базы данных.

i.e.

INSERT INTO voting (epoch, validity, choice, campaigns_id, candidates_id ) 
VALUES (1161048980,'during','Brown', 1, 1),
(1161048980,'during','Tupele', 3, 5), ... etc

Любые нулевые значения, обнаруженные в файле voices.txt, приведут к увеличению переменной $errors.

Сценарий, кажется, успешно проходит через voices.txt, но не может инициализировать: переменные $campaign_id и $candidate_id соответственно. По завершении на терминал выводится error=19; общее количество строк в моем образце данных voices.txt; это означает, что каждая строка в этом файле не может быть вставлена ​​в базу данных.

mysql> select * from voting;
Empty set (0.00 sec)

подтверждает это.

Сценарий не сообщает об ошибках синтаксиса; следовательно, это более низкий уровень. Он отлично работает без переключателя; следовательно, это несколько сузило его. Однако я не вижу проблемы с переключателем, поэтому ищу здесь совета.


person cookie    schedule 01.12.2012    source источник
comment
Насколько я знаю, модуль Switch устарел и заменен функциональностью given/when в perl v5.10.1. См. perldoc perlsyn. Однако я бы порекомендовал вам вместо этого использовать хэш для этого поиска.   -  person TLP    schedule 01.12.2012


Ответы (2)


Не уверен, в чем ваша проблема, но вот несколько указателей на ваш оператор Switch и другой код.

Насколько я знаю, функция/модуль use Switch была заменена в perl v5.10.1 на given/when, и теперь она устарела. Лично я всегда находил эти утверждения немного странными и ненадежными. И ни в коем случае не незаменимым, поскольку perl такой гибкий язык.

В вашем случае я бы порекомендовал вместо этого поиск по хешу:

my %camp = ("ssss_uk_01B" => 1,
            "ssss_uk_01C" => 2,
            ...);
my %cand = ("Brown"       => 1,
            "Cameron"     => 2,
            ...);

$campaign_id  = $camp{$campaign};
$candidate_id = $cand{$choice}

Если вам нужно указать значения по умолчанию, вы можете использовать оператор присваивания defined-or :

$campaign_id //= "default value here";

Ваши substr задания немного неверны. Во-первых, вы используете все четыре аргумента, которые в perldoc описываются так:

substr EXPR,OFFSET,LENGTH,REPLACEMENT

Это означает, что вы заменяете свое совпадение на '' пустую строку. Это влияет на саму переменную и удалит нужные данные, если их оставить отдельно. Длина в вашем случае также не нужна, так как это конец строки, которую вы ищете. Наконец, вас спасает тот факт, что вы используете возвращаемое значение оператора substr.

Наконец, когда я пробую ваши задания, я получаю одноразовую ошибку в вашем первом задании ($campaign). Вывод :ssss_uk_01, а вы ожидаете ssss_uk_01.

Чтобы правильно использовать функцию substr, вы должны использовать:

$campaign = substr $campaign, 9;
$validity = substr $validity, 9;
$choice   = substr $choice, 7;
person TLP    schedule 01.12.2012

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

Я также склонен меньше доверять формату данных в журнале. Использование разделения избавляет от необходимости знать точную длину метки + размер двоеточия. В связи с этим я также предлагаю нормализовать данные, прежде чем использовать их в качестве ключа в хеше поиска. В этом примере я просто сделал все в нижнем регистре.

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

Идиома or+die — отличная практика при работе с файлами. Но это будет более информативно, когда эти штампы появятся, если вы включите $OS_ERROR (a.k.a. $!), даже для печати. Таким образом, вы будете знать разницу между отказом в разрешении, несуществующим или заполненным диском и т. д.

Это предложения, которые говорят о проблемах написания поддерживаемых и устойчивых программ. Но я лично считаю, что эстетика кода также способствует ремонтопригодности. Значимые соглашения об именах и форматирование кода могут иметь большое значение, когда вы откроете эту программу через год или два, чтобы внести улучшения или исправить ошибку. Я предпочитаю создавать код, в котором отсутствует ненужный беспорядок, такой как комментарии, констатирующие очевидное, или использование комментариев для удаления блоков кода.

Продолжайте хорошую работу. Мир нуждается в большей автоматизации программного обеспечения.

#!/usr/bin/perl

use strict;
use warnings;
use DBI;

#
# _voting.pl
#
my $logfile = '/var/www/voting/votes.txt';

my $errors = 0;

my %campaign_id_for = (
    'ssss_uk_01b' => 1,
    'ssss_uk_01c' => 2,
    'ssss_uk_01d' => 3,
    'ssss_uk_01e' => 4,
    'ssss_uk_01f' => 5,
    'ssss_uk_01g' => 6,
);

my %candidate_id_for = (
    'brown'   => 1,
    'cameron' => 2,
    'balls'   => 3,
    'green'   => 4,
    'boring'  => 5,
    'tupele'  => 6,
);

my $dbh = DBI->connect( 
    'DBI:mysql:database=sms_voting;host=localhost',
    'sisisi', 
    '*********', 
    { 'RaiseError' => 1 } 
);

my $sth = $dbh->prepare(q{
    INSERT INTO voting (
        epoch,
        validity,
        choice,
        campaigns_id,
        candidates_id
    ) VALUES (
        ?,
        ?,
        ?,
        ?,
        ?
    )
});

my $fh;

open $fh, '<', $logfile
    or die "open $logfile: $!";

LINE:
for my $line (<$fh>) {

    my ($vote, $epoch,  $campaign, $validity, $choice,
        $CONN, $MSISDN, $GUID,     $Shortcode
    ) = split /\s+/, $line;

    ($campaign) = reverse split /:/, $campaign;
    ($validity) = reverse split /:/, $validity;
    ($choice)   = reverse split /:/, $choice;

    my $campaign_id  = $campaign_id_for{ lc $campaign };
    my $candidate_id = $candidate_id_for{ lc $choice };

    if ( $epoch && $validity && $choice && $campaign_id && $candidate_id ) {

        $sth->execute(
            $epoch,
            $validity,
            $choice,
            $campaign_id,
            $candidate_id
        );

        print "$epoch $validity $choice\n"
            or die "print: $!";

        next LINE;
    }
    else {

        warn "failed to parse: $line\n";
        $errors++;
    }
}

close $fh
    or die "close $logfile: $!";

# debug
print "error count: $errors\n"
    or die "print: $!";
person ddoxey    schedule 01.12.2012
comment
В самом деле, и процитирую: «и кому дана мудрость, тому несомненно дано много добра»; - person cookie; 01.12.2012