🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

PowerShell

Windows PowerShellはコマンドラインインターフェースであり、システム管理を含むWindowsタスク自動化のためのスクリプト言語です。

Q&A

1回答

12359閲覧

powershell - 複数の大容量csvを処理したい

puroto

総合スコア0

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

PowerShell

Windows PowerShellはコマンドラインインターフェースであり、システム管理を含むWindowsタスク自動化のためのスクリプト言語です。

0グッド

1クリップ

投稿2021/02/19 13:47

編集2021/02/19 13:50

powershell初心者です。

前提・実現したいこと

1GBのcsvファイル(大体1000万行)*10ファイルほど処理したい。
情報が足りない、書いていることがおかしい等ありましたらご教授いただけると嬉しいです。

  • 処理の内容

  • 入力csvの内容

1000万行(1).csv IP,fagafaga,検索文字列 "11.111.11.111","fugafuga","PPPP" "22.222.22.222","hogehoge","OOOO" . . . 1000万行(2).csv IP,fagafaga,検索文字列 "11.111.11.111","fugafuga","OOOO" "33.333.33.333","hogehoge","AAAA" . . .
  • 出力csvの内容
IP,重複した数,検索文字列が一致した数 "11.111.11.111","2","2" "22.222.22.222","1","1" "33.333.33.333","1","0"

解決したいこと

処理速度が遅い。
出力結果は意図したものが出力できてますが
環境のせいもあるかもしれませんが、1万行を処理するのに2分ほどかかっています。
1000万行のファイルを処理するには厳しい状態です。

該当のソースコード

フォルダ構成
・検索.ps1
・処理対象データ(フォルダ)
ー1000万行(1).csv
ー1000万行(2).csv
ー1000万行(3).csv

ー1000万行(10).csv

powershell

1$sPath = Split-Path -Parent $MyInvocation.MyCommand.Path; 2$outPath = $sPath+'\整形結果.csv'; 3$pkHash = @{}; 4 5get-childItem $sPath"\処理対象データ\" | ForEach-Object { 6 # write-host "ファイル読み込み" 7 8 Get-Content -ReadCount 1 $sPath"\処理対象データ\"$_ -Encoding UTF8| ForEach-Object { 9 10 $LostSeg = 0; 11 $OutofOrder = 0; 12 13 $lineAry = $_ -split '","'; 14 $iP = $lineAry[0]; 15 $s = $lineAry[2]; 16 17 #文字列の検索1 18 if($s.Contains("PPPP")){ 19 $LostSeg = 1; 20 }; 21 #文字列の検索2 22 if($s.Contains("OOOO")){ 23 $OutofOrder = 1; 24 }; 25 26 #IPが既にハッシュテーブルに存在するか確認、存在=すでに存在しているvalueに加算、存在しない=キーの追加 27 $Sequence = $LostSeg + $OutofOrder; 28 if($pkHash.ContainsKey($iP)){ 29 $pkHash.$iP.Count_Out_of_Sequence += $Sequence 30 $pkHash.$iP.Count_Out_of_Packet += 1;#重複IPのカウント 31 }else { 32 $pkHash.Add($iP,@{ 33 Count_Out_of_Sequence = $Sequence 34 Count_Out_of_Packet = 1 35 }; 36 } 37}; 38#csv出力 39$pkHash.GetEnumerator() | 40Select-Object @{N="IP"; E={$_.Key}}, @{N="重複した数"; E={$_.Value.Count_Out_of_Packet}} ,@{N="検索文字列が一致した数"; E={$_.Value.Count_Out_of_Sequence}}| 41Sort-Object Count_Out_of_Sequence -Descending | 42Export-Csv $outPath -Encoding Default -NoTypeInformation 43

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gentaro

2021/02/19 15:29

まずどの箇所がボトルネックなのか調査したら? ファイルI/Oに時間がかかってるとかならSSD使うだけで解決するかもしれんし。
meg_

2021/02/20 00:33

メモリは十分にありますか?メモリがあれば並列で処理するのはどうでしょうか?
puroto

2021/02/21 01:42

返答遅くなり、申し訳ないです。 ご協力本当にありがとうございます。 >gentaroさん Get-DateをファイルI/Oの間に差し込んで1万行のcsvで確認したところ inは値をメモリに渡さず1行ずつパイプでForeach-Objectに渡しているからか、一瞬で outは5秒ほどでした。 なので、ループの中身が遅くなる原因かと思いましたが、、どの部分かいまいちわかっていないのでもう少しコード削りながら調べてみることにいたします。 >meg_さん 並列処理というものをできるということを知りませんでした! メモリは8GBですが、物は試しで調べて書いてみたいと思います。
guest

回答1

0

ForEach-Objectは劇遅なので大容量データ相手では使うべきではないとする報告がありました。

Powershell 各ループの速度比較 - Qiita

質問の趣旨から外れていることは承知で言えば、こういう課題にはperlの方が適しています。ちょっと気になってwindows10上に1000万行のcsvファイルを10個作り、perlで集計してみたところ、10分かからず終了しました。Pentium Goldという安い低性能なCPUを搭載したPCで、cygwinという低速な環境の下での話です。

投稿2021/02/20 14:19

KojiDoi

総合スコア13692

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

puroto

2021/02/21 02:16

回答ありがとうございます! foreachを下記の通り試したところ ImportCSVでファイルを読み込むのが7分 ループの処理が1万行につき1分30秒~、という結果になりました。 まだ足りませんが、気持ち早くなったかもしれません。 ``` $Lists = Import-Csv $sPath"\処理対象データ\"$_ -Encoding Default foreach ($item in $Lists) { ``` やはり、ループ内でハッシュテーブルをごちゃごちゃいじっているから問題なのかなと 個人的には思っております。 >perl 1000万行*10が10分ですか!! 今まで触れたことはありませんが、perlってすごいんですね、、 職場がかなりレガシーなところなので、環境が用意できるかはまだわかりませんが 調べながら試してみたいと思います!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問