Прочитайте большой CSV в PowerShell, проанализируйте несколько столбцов и найдите уникальные значения, сохраните результаты на основе самого старого значения в столбце. - PullRequest
0 голосов
/ 02 июня 2019

У меня большой 10-миллионный файл строк (в настоящее время CSV).Мне нужно прочитать файл и удалить дубликаты элементов на основе нескольких столбцов.

Пример строки данных будет выглядеть примерно так:

Имя_компьютера, IP-адрес, MacAddress, CurrentDate, FirstSeenDate

Я бы хотел проверить MacAddress и ComputerName на наличие дубликатов, и, если обнаружен дубликат, сохраните уникальную запись с самой старой FirstSeenDate.

Я прочитал CSV в переменную с помощью import-csv, а затем обработалпеременная с использованием объекта сортировки ... и т. д., но это ужасно медленно.

$data | Group-Object -Property ComputerName,MaAddress | ForEach-Object{$_.Group | Sort-Object -Property FirstSeenDate | Select-Object -First 1}

Я думаю, я мог бы использовать stream.reader и построчно читать CSV, создавая уникальный массив, основанный на массиве, содержащем логику.

Мысли?

Ответы [ 2 ]

0 голосов
/ 02 июня 2019

Я бы, вероятно, использовал Python, если бы производительность была главной проблемой.Или LogParser.

Однако, если бы мне пришлось использовать PowerShell, я, вероятно, попробовал бы что-то вроде этого:

$CultureInfo = [CultureInfo]::InvariantCulture
$DateFormat = 'M/d/yyyy' # Use whatever date format is appropriate

# We need to convert the strings that represent dates. You can skip the ParseExact() calls if the dates are already in a string sortable format (e.g., yyyy-MM-dd).
$Data = Import-Csv $InputFile | Select-Object -Property ComputerName, IPAddress, MacAddress, @{n = 'CurrentDate'; e = {[DateTime]::ParseExact($_.CurrentDate, $DateFormat, $CultureInfo)}}, @{n = 'FirstSeenDate'; e = {[DateTime]::ParseExact($_.FirstSeenDate, $DateFormat, $CultureInfo)}}

$Results = @{}
foreach ($Record in $Data) {
    $Key = $Record.ComputerName + ';' + $Record.MacAddress
    if (!$Results.ContainsKey($Key)) {
        $Results[$Key] = $Record
    }
    elseif ($Record.FirstSeenDate -lt $Results[$Key].FirstSeenDate) {
        $Results[$Key] = $Record
    }
}

$Results.Values | Sort-Object -Property ComputerName, MacAddress | Export-Csv $OutputFile -NoTypeInformation

Это может быть гораздо быстрее, потому что Group-Object часто является узким местом дажехотя он довольно мощный.

Если вы действительно хотите попробовать использовать потоковое считывающее устройство, попробуйте использовать класс Microsoft.VisualBasic.FileIO.TextFieldParser , который является частью .Net Framework.несмотря на это немного вводящее в заблуждение название.Вы можете получить к нему доступ, набрав Add-Type -AssemblyName Microsoft.VisualBasic.

0 голосов
/ 02 июня 2019

Вы можете выполнить импорт в базу данных (например, SQLite пример ) а затем запрос:

SELECT 
  MIN(FirstSeenDate) AS FirstSeenDate, 
  ComputerName, 
  IPAddress, 
  MacAddress
FROM importedData
GROUP BY ComputerName, IPAddress, MacAddress
...