2014-09-11 2 views
-1

두 개의 커다란 .csv 파일을 가지고 있는데 하나는 약 8GB이고 다른 하나는 3.4GB의 파일 크기입니다. 그 .csv 파일 안의 각 줄에서 몇 가지 값만 원한다. 데이터를 수정하고 새 파일에 복사하는 데 많은 시간이 걸립니다.큰 파일을 perl 스크립트를 사용하여 한 줄씩 수정

누구든지 코드 수정에 도움을 줄 수 있습니까? 수정은 적절한 시간 내에 완료됩니다.

#!/usr/bin/perl 
use strict; 
use warnings; 

use Text::CSV; 

require "$ENV{'SAI_HOME'}/bin/utils/Logging.pl"; 
require "$ENV{'SAI_HOME'}/bin/utils/Utilities.pl"; 

my $date1 = `date '+%d-%m-%Y_%H-%M-%Ss'`; 
chomp($date1); 
our $LOGPATH = "$ENV{'SAI_HOME'}/logs/SP6migrationcsv_$date1.log"; 
my $status = 0; 
log_info("Refer $LOGPATH log file for more information"); 
my $csv = Text::CSV->new({ binary => 1, eol => $/, sep_char => ',' }); 
my $file1 = $ARGV[0] or die "Please provide Subscriber and Subscription CSV files on the command line\n"; 
my $file2 = $ARGV[1] or die "Please provide Subscriber and Subscription CSV files on the command line\n"; 
my $subscriberFile = ""; 
my $subscriptionFile = ""; 

if ((grep /SUBSCRIBER/i, $file1) && (grep /SUBSCRIPTION/i, $file2)) { 
    $subscriberFile = $file1; 
    $subscriptionFile = $file2; 
} elsif ((grep /SUBSCRIBER/i, $file2) && (grep /SUBSCRIPTION/i, $file1)) { 
    $subscriptionFile = $file1; 
    $subscriberFile = $file2; 
} else { 
    log_error("Invalid CSV files input"); 
    exit -1; 
} 
my $SP6DIR = `dirname $0`; 
chomp $SP6DIR; 
$SP6DIR = "${SP6DIR}/SP6"; 
`mkdir -p $SP6DIR` or checkExit($?, "Unable to carete $SP6DIR directory"); 
my $newSubscriberFile = "Subscriber.csv"; 
my $newSubscriptionFile = "Subscription.csv"; 
my $subscriptionimsifile = "$SP6DIR/.IMSI_$newSubscriptionFile"; 
my $subscriberimsifile = "$SP6DIR/.IMSI_$newSubscriberFile"; 
$newSubscriberFile = "${SP6DIR}/$newSubscriberFile"; 
$newSubscriptionFile = "${SP6DIR}/$newSubscriptionFile"; 
`dos2unix $subscriptionFile $subscriberFile 2>/dev/null` 
    or checkExit($?, "Unable to perform dos2unix on input files"); 
`cut -d "," -f3 $subscriptionFile > $subscriptionimsifile` 
    or checkExit($?, "Failed to get IMSI details from $subscriptionFile"); 
`cut -d "," -f1 $subscriberFile > $subscriberimsifile` 
    or checkExit($?, "Failed to get IMSI details from $subscriberFile"); 
my $isSubscriptionHeaderPresesnt = "false"; 
my $isSubscriberHeaderPresesnt = "false"; 
$status = system("head -1 $subscriptionimsifile | grep 'IMSI' >>/dev/null"); 

if ($status == 0) { 
    $isSubscriptionHeaderPresesnt = "true"; 
} 
$status = system("head -1 $subscriberimsifile | grep 'IMSI' >>/dev/null"); 
if ($status == 0) { 
    $isSubscriberHeaderPresesnt = "true"; 
} 
open(my $subscriptionData, '<:encoding(utf8)', $subscriptionFile) 
    or die "Could not open '$subscriptionFile' $!\n"; 
open(NEWSUBSCRIBERDATA, "> $newSubscriberFile") or die "Could not open '$newSubscriberFile' $!\n"; 
open(NEWSUBSCRIPTIONDATA, "> $newSubscriptionFile") or die "Could not open '$newSubscriptionFile' $!\n"; 
if ("$isSubscriptionHeaderPresesnt" eq "true") { 
    my $subscriptionHeader = <$subscriptionData>; 
    if ($csv->parse($subscriptionHeader)) { 
     my @subscriptionHeaderFields = $csv->fields(); 
     print NEWSUBSCRIPTIONDATA "\"$subscriptionHeaderFields[0]\",\"$subscriptionHeaderFields[2]\",\"$subscriptionHeaderFields[4]\",\"$subscriptionHeaderFields[5]\",\"$subscriptionHeaderFields[6]\",\"$subscriptionHeaderFields[8]\",\"$subscriptionHeaderFields[13]\",\"$subscriptionHeaderFields[14]\",\"$subscriptionHeaderFields[15]\",\"$subscriptionHeaderFields[16]\",\"$subscriptionHeaderFields[17]\",\"$subscriptionHeaderFields[18]\",\"$subscriptionHeaderFields[25]\",\"$subscriptionHeaderFields[26]\",\"$subscriptionHeaderFields[27]\"\n"; 
     print NEWSUBSCRIBERDATA "\"IMSI\",\"IMEI\",\"MSISDN\",\"$subscriptionHeaderFields[21]\",\"$subscriptionHeaderFields[22]\",\"$subscriptionHeaderFields[12]\",\"$subscriptionHeaderFields[9]\",\"$subscriptionHeaderFields[1]\",\"$subscriptionHeaderFields[0]\"\n"; 
    } else { 
     log_error("Line could not be parsed: $subscriptionHeader\n"); 
     exit 1; 
    } 
} else { 
    log_only("No header info in subscription file"); 
} 

if ("$isSubscriptionHeaderPresesnt" eq "false" && "$isSubscriberHeaderPresesnt" eq "true") { 
    print NEWSUBSCRIBERDATA "\"IMSI\",\"IMEI\",\"MSISDN\",\"CUSTOMER_SEGMENTATION\",\"CUST_SUBCATEGORY\",\"SUBS_TYPE\",\"SUBSCRIPTION_PLAN\",\"CONTRACT_IDREF\",\"SUBSCRIPTION_IDREF\"\n"; 
} else { 
    log_only("No header info in subscriber file"); 
} 
my $subscriberHeader = ""; 
my @subscriptionFields = {}; 
my @subscriberFields = {}; 

while (my $eachSubscriptionLine = <$subscriptionData>) { 
    chomp $eachSubscriptionLine; 
    if ($csv->parse($eachSubscriptionLine)) { 
     @subscriptionFields = $csv->fields(); 
     $status = system("grep \"^[\\\"]*${subscriptionFields[2]}[\\\"]*\\\$\" $subscriberimsifile >> /dev/null"); 
     if ($status == 0) { 
      my $lastMatchedSubscriberdata = `grep "^[\\\"]*${subscriptionFields[2]}[\\\"]*," $subscriberFile | tail -1`; 
      chomp $lastMatchedSubscriberdata; 
      if ($csv->parse($lastMatchedSubscriberdata)) { 
       @subscriberFields = $csv->fields(); 
       if ("${subscriberFields[0]}" eq "${subscriptionFields[2]}") { 
        #log_only("Updating \"@subscriberFields\" subscriber details from subscription data"); 
        print NEWSUBSCRIBERDATA "\"$subscriberFields[0]\",\"$subscriberFields[1]\",\"$subscriptionFields[2]\",\"$subscriptionFields[21]\",\"$subscriptionFields[22]\",\"$subscriptionFields[12]\",\"$subscriptionFields[9]\",\"$subscriptionFields[1]\",\"$subscriptionFields[0]\"\n"; 
       } else { 
        log_error("Unable to process @subscriberFields record"); 
        exit -1; 
       } 
      } else { 
       log_error("Line could not be parsed: $lastMatchedSubscriberdata\n"); 
       exit 1; 
      } 
     } else { 
      log_only("Adding new subscriber details from subscription : \"@subscriptionFields\""); 
      print NEWSUBSCRIBERDATA "\"$subscriptionFields[2]\",,\"$subscriptionFields[3]\",\"$subscriptionFields[21]\",\"$subscriptionFields[22]\",\"$subscriptionFields[12]\",\"$subscriptionFields[9]\",\"$subscriptionFields[1]\",\"$subscriptionFields[0]\"\n"; 
     } 
     print NEWSUBSCRIPTIONDATA "\"$subscriptionFields[0]\",\"$subscriptionFields[2]\",\"$subscriptionFields[4]\",\"$subscriptionFields[5]\",\"$subscriptionFields[6]\",\"$subscriptionFields[8]\",\"$subscriptionFields[13]\",\"$subscriptionFields[14]\",\"$subscriptionFields[15]\",\"$subscriptionFields[16]\",\"$subscriptionFields[17]\",\"$subscriptionFields[18]\",\"$subscriptionFields[25]\",\"$subscriptionFields[26]\",\"$subscriptionFields[27]\"\n"; 
    } else { 
     log_error("Line could not be parsed: $eachSubscriptionLine\n"); 
     exit 1; 
    } 
} 
close(NEWSUBSCRIPTIONDATA); 
open(my $subscriberData, '<:encoding(utf8)', $subscriberFile) || die "Could not open '$subscriberFile' $!\n"; 
if ("$isSubscriberHeaderPresesnt" eq "true") { 
    $subscriberHeader = <$subscriberData>; 
} 
while (my $eachSubscriberLine = <$subscriberData>) { 
    chomp $eachSubscriberLine; 
    if ($csv->parse($eachSubscriberLine)) { 
     @subscriberFields = $csv->fields(); 
     $status = system("grep \"^[\\\"]*${subscriberFields[0]}[\\\"]*\\\$\" $subscriptionimsifile >>/dev/null"); 
     if ($status != 0) { 
      log_only(
       "Adding back subscriber details, because unable to get IMSI details from subscription file : \"@subscriberFields\"" 
      ); 
      print NEWSUBSCRIBERDATA "\"$subscriberFields[0]\",\"$subscriberFields[1]\",\"$subscriberFields[2]\",\"$subscriberFields[6]\",,\"$subscriberFields[7]\",,,\n"; 
     } 
    } else { 
     log_error("Line could not be parsed: $eachSubscriberLine\n"); 
     exit 1; 
    } 
} 
close(NEWSUBSCRIBERDATA); 
`sed -i -e '1 s|SUBSCRIPTION_ID|SUBSCRIPTION_IDREF|g' -e '1 s|SUBS_CATEGORY|SUBSCRIPTION_PLAN|g' -e '1 s|SUBS_STATE|SUBS_TYPE|g' -e '1 s|CUST_CATEGORY|CUSTOMER_SEGMENTATION|g' $newSubscriberFile` 
    or checkExit($?, "Unable to update header info in subscriber fi le"); 
+0

@ jm666 그래도 성능에 대해 불평해서는 안됩니다. csv가 의무적 인 경우 가져 오기/내보내기 데이터베이스 형식으로 만 사용할 수 있지만 자주 업데이트하는 데는 사용할 수 없습니다. –

+0

@mpapec thats 's fair :) – jm666

+3

아마도 여러분은 긴 코드를 분석해야 할 것입니다. 여기서 여러분은 여러 번 외부 명령을 호출 할 것입니다. 할 수있는 최선의 방법은 코드 부분에서 가장 많은 시간이 걸리는 부분을 찾아 몇 줄의 코드로 문제를 줄이고 몇 가지 샘플 입력과 원하는 출력 샘플을 제공하는 것입니다. 없이는 더 이상 뭔가를 추천하지 않고, 8GB file_에 3 개의 외부 프로세스를 호출하고 연속적으로 행을 처리합니다 ._ 그리고 그러한 일반적인 일 ... 그리고 [ask]를 읽어주십시오. – jm666

답변

4

일반 정보 :

  • 가 입력을 구문 분석하는 역 따옴표를 사용하지 마십시오

    다음은 코드의 라인입니다. Perl은 while 루프와 split을 사용하여 완벽하게 수행 할 수 있습니다.

  • 철자가 틀린 변수 이름이 당신을 망칠 것입니다. 하지마. isSubscriptionHeaderPresesnt

  • open 호출을 렉시 칼과 함께 사용하는 것이 일반적으로 선호되지만 불일치가 좋지 않습니다.

  • 부울 대신 텍스트 문자열 "false"를 사용하는 것은 끔찍한 행위입니다. 하지 마. 누군가 언젠가 print "true" if "false"에 해당하는 일을 할 것이고 그것은 깨질 것입니다.

  • 스크립트가 수행하는 '비싼'작업은 파일을 읽는 것입니다. 거의 항상 사실입니다. 따라서 syscalls 이외의 항목을 grep 또는 sed으로 지정하면 대상 파일을 완전히 다시 읽어야합니다. subscriptionFilesubscriberFile이 귀하의 거물이라면 여러 번 읽는 것입니다. 전체를 읽는 cut을 실행 중입니다. 모든 것을 읽는 dos2unix. 전체를 읽는 grep. 그리고 나서 당신은 open이고, 모든 것을 읽는 것입니다.

  • 귀하의 마지막 줄은 sed입니다. 출력 파일을 완전히 다시 읽고 행 변환을 적용합니다.

관련 문제