Powershell针对大分隔文件的聚合操作进行性能调整



我有一个有350列的分隔文件。分隔符为34(Field separator)。我必须提取一个特定的列值,并找出文件中该列的每个不同值的计数。如果distinct值的计数大于或等于2,我需要将其输出到一个文件中。源文件为1GB。我写了以下命令。它非常慢。

Get-Content E:Testtest.txt | Foreach {($_ -split '34')[117]} | Group-Object -Property { $_ } | %{ if($_.Count -ge 2) { Select-Object -InputObject $_ -Property Name,Count} } | Export-csv -Path "E:Testtest2.csv" -NoTypeInformation

请帮忙!

我建议使用switch语句快速处理输入文件(按照PowerShell标准(:

# Get an array of all the column values of interest.
$allColValues = switch -File E:Testtest.txt {
default {  # each input line
# For better performance with *literal* separators, 
# use the .Split() *method*.
# Generally, however, use of the *regex*-based -split *operator* is preferable.
$_.Split([char] 0x1c)[117] # hex 0x1c is octal 034
}
}
# Group the column values, and only output those that occur at least 
# twice.
$allColValues | Group-Object -NoElement | Where-Object Count -ge 2 |
Select-Object Name, Count | Export-Csv E:Testtest2.csv -NoTypeInformation

向Mathias R.Jessen致敬,他建议使用-NoElement开关,该开关仅通过维护抽象组信息来简化Group-Object调用;也就是说,只有分组标准(如.Name中所反映的,而不包括组成组的各个对象(如在.Group中通常所反映的(通过输出对象返回


至于您尝试了什么

  • Get-Content在管道中具有逐行流传输,速度通常(逐对象传递会引入开销(,而且特别是都是如此,因为Get-Content用ETS(扩展类型系统(元数据装饰它输出的每一行。

    • GitHub第7537期建议添加一种选择退出这种装饰的方式
    • -Raw开关将整个文件读取为单个多行字符串,这会以内存消耗和潜在的额外行拆分工作为代价,速度会快得多
  • -Property { $_ }传递给Group-Object是不必要的-只需省略它。如果没有-Property参数,输入对象将被分组为作为一个整体

  • 链接Where-ObjectSelect-Object——而不是在ForEach-Object调用中通过if语句与多个Select-Object调用相结合进行过滤——不仅在概念上更清晰,而且性能更好。


最新更新