首页 > 解决方案 > 针对大分隔文件的聚合操作的 Powershell 性能调整

问题描述

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

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

请帮忙!

标签: powershellfiledelimitedgroup-object

解决方案


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

# Get an array of all the column values of interest.
$allColValues = switch -File E:\Test\test.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:\Test\test2.csv -NoTypeInformation

Mathias R. Jessen 致敬,感谢他提出了转换的建议,该转换通过仅维护抽象组信息-NoElement来简化呼叫;也就是说,只有分组标准(反映在 中,而不是组成组的各个对象(通常反映在 中)通过输出对象返回。Group-Object.Name.Group


至于你尝试了什么:

  • Get-Content流水线中的逐行流式传输速度很通常是(逐个对象传递引入开销),特别是因为Get-Content使用 ETS(扩展类型系统)元数据装饰它输出的每一行。

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

  • 链接Where-Object和- 而不是通过与多个调用组合的调用中的语句进行Select-Object过滤- 不仅在概念上更清晰,而且性能更好。ifForEach-Object Select-Object



推荐阅读