2017-01-26 8 views
1

3つの列しかない15MBのCSVファイルを処理しようとしています。たとえば:再帰的検索に基づいてCSVで新しい列を作成する

StaffNumber,EmailAddress,Manager 
123,[email protected],456. 

私はその後、CSVファイルの各行を検索する職員番号、電子メールアドレスを表示し、管理者のID番号を取得し、そのスタッフの番号と電子メールを表示する、そのために検索する必要がありますのマネージャーIDを使用して同じことを繰り返します。最後に、私はCSVファイルの各行にユーザーのIDと電子メールを持ち、の管理者IDと電子メールを最大でとする必要があります。

私はこれで終わるしようとしている:それは作品の中に別のレンチを投げるよう

123,[email protected],456,[email protected],789,[email protected],098,[email protected] 

一部の行に、電子メールアドレスまたは管理者のID番号が含まれていません。私はこれらのフィールドに単に "空白"または "X"を追加する予定でした。

これまでのところ、この簡単なスクリプトを使用して、一度に1つずつ検索しました。それは動作しますが、それはひどく遅いです。今朝以降、そのファイルから0.31%を得るのに6時間かかりました。うん!

15MB相当のCSVデータ、さまざまなPowerShellバージョン、今週のベストプラクティスなどを処理するにはどうすればいいのかよく分かりませんでしたが、PowerShellは私の通常の言語とはかけ離れています。 PSスキル。私はちょうどアイデアを得るために基本的なテストスクリプトを完成させようとしていた)。

私は現在PowerShell v4を使用しています。以前のバージョンとの互換性の問題があります。合理的な将来のバージョンとの互換性を保つようにしたいと思います。

このファイルを処理する最も速い方法は何ですか? 30万行でわずか15MBで、私はRAMについて心配していません。この検索をより効率的に実行する方法がわかりません。

$FilePath = "C:\Temp\DA-UserList.csv" 
$DAUserlist = Import-CSV $FilePath 

$inputNumber = Read-Host -Prompt "Employee ID Number" 

$DAUser1 = $DAUserlist | Where{$inputNumber -match $_.StaffNumber}| Select -First 1 
ForEach ($item in $DAUser1){ 
    $StaffNumber1 = $($item.StaffNumber) 
    $EmailAddress1 = $($item.EmailAddress) 
    $Manager1 = $($item.Manager) 
    printf $item.StaffNumber 
    printf "," 
    printf $EmailAddress1 
    $DAUser2 = $DAUserlist | Where{$Manager1 -match $_.StaffNumber}| Select -First 1 
    ForEach ($item in $DAUser2){ 
     $StaffNumber2 = $($item.StaffNumber) 
     $EmailAddress2 = $($item.EmailAddress) 
     $Manager2 = $($item.Manager) 
     printf "," 
     printf $StaffNumber2 
     printf "," 
     printf $EmailAddress2 
     $DAUser3 = $DAUserlist | Where{$Manager2 -match $_.StaffNumber}| Select -First 1 
     ForEach ($item in $DAUser3){ 
      $StaffNumber3 = $($item.StaffNumber) 
      $EmailAddress3 = $($item.EmailAddress) 
      $Manager3 = $($item.Manager) 
      printf "," 
      printf $StaffNumber3 
      printf "," 
      printf $EmailAddress3 
      $DAUser4 = $DAUserlist | Where{$Manager3 -match $_.StaffNumber}| Select -First 1 
      ForEach ($item in $DAUser4){ 
       $StaffNumber4 = $($item.StaffNumber) 
       $EmailAddress4 = $($item.EmailAddress) 
       $Manager4 = $($item.Manager) 
       printf "," 
       printf $StaffNumber4 
       printf "," 
       printf $EmailAddress4 
       printf \n 
      } 
     } 
    } 
} 

答えて

1

15MBのファイルでは、ハードコアの最適化は必要ありません(少なくとも私はそうだと思います)。ですから、同じことを何度も何度も繰り返しているので、あなたが探しているのは再帰関数です。

少なくともパフォーマンスのためとして、 .where() methodを使用してみてください、良く見て、理解しやすいだろう
$data = Import-Csv "C:\Temp\DA-UserList.csv" 
$i = 0 

function Get-CsvUser { 
    param(
     [string]$id 
    ) 

    $data.Where({$_.StaffNumber -eq $id}, 'First', 1) 
} 

function Get-CsvNested { 
    param(
     [string]$id 
    ) 

    $user = Get-CsvUser $id 
    Get-CsvUser -id $user.Manager | % { 
     while ($global:i -lt 3) { # using global here to avoid circular execution 
      $global:i++ 

      Write-Output "User: $($user.EmailAddress)" 
      Write-Output "His Manager: $($_.EmailAddress)" 

      "" # to output an empty string 
      Get-CsvNested -id $_.StaffNumber 
     } 
    } 
} 

。それはより速いです。
はまた、あなたがチャンクにCSVを分割し、チャンクを解析するために別のプロセスを作成することができ

上記のコードは、単一のユーザー(と彼のマネージャー)調べるためのもので、([スタート] - ジョブまたはより良いStart-RSJobと思います)あなたが最終的な目標が何であるかは分かりません。なぜなら、あなたはそれをかなりうまく言い表していないからです(私はそれを理解しませんでした)。

私にpingを依頼する必要がある場合は(私のプロフィールを確認してください)、私たちは何か手を差し伸べることができます。

1

$DAUserlist | Where { # ... } | Select -First 1のようなものを実行するたびに、300,000レコードのように線形検索が行われます。あなたはGroup-Object cmdletを使ってこれをスピードアップすることができます...

$DAUserlist = Import-CSV $FilePath 
$DAUsersByStaffNumber = $DAUserlist | Group-Object -Property 'StaffNumber' -AsHashTable 

$DAUsersByStaffNumberユーザーレコードに各スタッフの数をマッピングHashTableインスタンスが含まれています。特定のユーザーを検索するには、その3つの管理者は、次で置き換えることができます...コードを少し単純化し、あなたのルックアップが多く、より効率的になり

$DAUser1 = $DAUsersByStaffNumber[$inputNumber] 
# ... 
$DAUser2 = $DAUsersByStaffNumber[$Manager1] 
# ... 
$DAUser3 = $DAUsersByStaffNumber[$Manager2] 
# ... 
$DAUser4 = $DAUsersByStaffNumber[$Manager3] 

あなたのコード。

また、あなたはスタッフの数でユーザーリストをフィルタリングしているとき-eqオペレータが正確な文字列の一致を探します一方、あなたは、正規表現をサポートし-match演算子を使用しているされていることを認識するために何か他のもの(大文字非感受性)。これが問題になる理由の1つは、正規表現でサポートされている複雑な文字列マッチングを行うつもりがない場合に-matchを使用すると、おそらく目に見えないほどですが、-eqと比較してパフォーマンスが低下する可能性があります。さらに重要なことは、300,000人以上のユーザーがいるため、StaffNumberの値のうちのいくつかは、少なくとも6桁でなければならず、CSVのフォーマットに応じて(StaffNumberは最大桁数にゼロが埋め込まれていますか?間違ったユーザーと一致する可能性があります。たとえば、$inputNumber12345の場合、ユーザ12345に一致するだけでなく、ユーザ112345および123450も一致します。正確なスタッフ番号での検索のみを許可する場合は、上記の-eqまたはHashTableのソリューションに切り替えることができます。

関連する問題