我经常需要在一个目录中搜索服务器日志文件,该目录可能包含 50 个或更多文件,每个文件超过 200 MB。我在 Powershell 中编写了一个函数来执行此搜索。它查找并提取给定查询参数的所有值。它适用于单个大文件或小文件集合,但在上述情况下完全咬合,即大文件目录。
该函数接受一个参数,该参数由要搜索的查询参数组成。
在伪代码中:
Take parameter (e.g. someParam or someParam=([^& ]+))
Create a regex (if one is not supplied)
Collect a directory list of *.log, pipe to Select-String
For each pipeline object, add the matchers to a hash as keys
Increment a match counter
Call GC
At the end of the pipelining:
if (hash has keys)
enumerate the hash keys,
sort and append to string array
set-content the string array to a file
print summary to console
exit
else
print summary to console
exit
这是文件处理的精简版本。
$wtmatches = @{};
gci -Filter *.log | Select-String -Pattern $searcher |
%{ $wtmatches[$_.Matches[0].Groups[1].Value]++; $items++; [GC]::Collect(); }
我只是使用一个旧的 perl 技巧,通过将找到的项目设为哈希的键来对它们进行重复数据删除。也许,这是一个错误,但处理的典型输出最多约为 30,000 个项目。更常见的是,找到的项目在数千个范围内。从我所见,散列中的键数不会影响处理时间,而是文件的大小和数量会破坏它。我最近绝望地投入了GC,它确实有一些积极的影响,但它是微不足道的。
问题在于,对于大型文件的大量集合,处理过程会在大约 60 秒内将 RAM 池吸干。有趣的是,它实际上并没有使用很多 CPU,但是有很多易失性存储正在进行。一旦 RAM 使用率上升 90% 以上,我就可以打卡出去看电视了。完成处理以生成具有 15,000 或 20,000 个唯一值的文件可能需要数小时。
我想要提高效率的建议和/或建议,即使这意味着使用不同的范例来完成处理。我带着我所知道的去了。我几乎每天都使用这个工具。
哦,我致力于使用 Powershell。;-) 这个函数是我为我的工作编写的完整模块的一部分,因此,Python、perl 或其他有用语言的建议在这种情况下没有用。
谢谢。
mp
更新:使用 latkin 的ProcessFile
函数,我使用以下包装器进行测试。他的功能比我原来的要快几个数量级。
function Find-WtQuery {
<#
.Synopsis
Takes a parameter with a capture regex and a wildcard for files list.
.Description
This function is intended to be used on large collections of large files that have
the potential to take an unacceptably long time to process using other methods. It
requires that a regex capture group be passed in as the value to search for.
.Parameter Target
The parameter with capture group to find, e.g. WT.z_custom=([^ &]+).
.Parameter Files
The file wildcard to search, e.g. '*.log'
.Outputs
An object with an array of unique values and a count of total matched lines.
#>
param(
[Parameter(Mandatory = $true)] [string] $target,
[Parameter(Mandatory = $false)] [string] $files
)
begin{
$stime = Get-Date
}
process{
$results = gci -Filter $files | ProcessFile -Pattern $target -Group 1;
}
end{
$etime = Get-Date;
$ptime = $etime - $stime;
Write-Host ("Processing time for {0} files was {1}:{2}:{3}." -f (gci
-Filter $files).Count, $ptime.Hours,$ptime.Minutes,$ptime.Seconds);
return $results;
}
}
输出:
clients:\test\logs\global
{powem} [4] --> Find-WtQuery -target "WT.ets=([^ &]+)" -files "*.log"
Processing time for 53 files was 0:1:35.
感谢大家的评论和帮助。