Сравнение записей в файле и статистика отчетов - Сценарий 1
Требования следующие:
Факт 1: у нас есть несколько файлов данных, созданных устаревшей системой
Факт 2: у нас есть несколько файлов данных, созданных новой системой, которые в конечном итоге должны заменить устаревшую
Факт 3:
- Оба файла являются текстовыми /ASCII-файлами, причем записи состоят из нескольких строк.
- Каждая строка в записи состоит из имени поля и значения поля.
- Формат, в котором представлены строки, отличается от 1 до 2, но имя поля и значение поля можно извлечь из каждой строки с помощью регулярных выражений
- Имена полей могут меняться от 1 до 2, но у нас есть сопоставление, которое связывает их
- Каждая запись имеет уникальный идентификатор, который помогает нам связать устаревшую запись с новой записью, поскольку порядок записей в выходном файле не обязательно должен быть одинаковым в обеих системах.
- Каждый файл для сравнения занимает минимум 10 МБ, а средний размер - 30–35 МБ.
Факт 4: Как и когда мы выполняем итерацию при создании новой системы, нам нужно сравнить файлы, созданные обеими системами в одинаковых условиях, и согласовать различия.
Факт 5: Это сравнение выполняется вручную с использованием дорогого инструмента визуального сравнения. Чтобы помочь в этом, я написал инструмент, который объединяет два разных имени поля в общее имя, а затем сортирует имена полей в каждой записи, в каждом файле, чтобы они синхронизировались по порядку (новые файлы могут иметь дополнительные поля, которые игнорируются в визуальный дифференциал)
Факт 6: из-за того, что люди производят сравнение вручную и из-за ошибок, допущенных человеком, мы получаем ложные позитивные и отрицательные стороны, которые существенно влияют на наши временные рамки.
Очевидно, вопрос в том, какими должны быть "ALG" и "DS"?
Сценарий, который я должен рассмотреть:
Там, где люди продолжают визуально проверять различия - при этом производительность ожидающего скрипта неутешительна - большая часть обработки заключается в сортировке массива строк в лексикографическом порядке (элемент массива чтения / выборки: Tie::File::FETCH, Tie::File::Cache::lookup и помещаем его в правильное место, чтобы он был отсортирован: Tie::File::Cache::insert, Tie::File::Heap::insert)
use strict;
use warnings;
use Tie::File;
use Data::Dumper;
use Digest::MD5 qw(md5_hex);
# open an existing file in read-only mode
use Fcntl 'O_RDONLY';
die "Usage: $0 <unsorted input filename> <sorted output filename>" if ($#ARGV < 1);
our $recordsWrittenCount = 0;
our $fieldsSorted = 0;
our @array;
tie @array, 'Tie::File', $ARGV[0], memory => 50_000_000, mode => O_RDONLY or die "Cannot open $ARGV[0]: $!";
open(OUTFILE, ">" . $ARGV[1]) or die "Cannot open $ARGV[1]: $!";
our @tempRecordStorage = ();
our $dx = 0;
# Now read in the EL6 file
our $numberOfLines = @array; # accessing @array in a loop might be expensive as it is tied??
for($dx = 0; $dx < $numberOfLines; ++$dx)
{
if($array[$dx] eq 'RECORD')
{
++$recordsWrittenCount;
my $endOfRecord = $dx;
until($array[++$endOfRecord] eq '.')
{
push @tempRecordStorage, $array[$endOfRecord];
++$fieldsSorted;
}
print OUTFILE "RECORD\n";
local $, = "\n";
print OUTFILE sort @tempRecordStorage;
@tempRecordStorage = ();
print OUTFILE "\n.\n"; # PERL does not postfix trailing separator after the last array element, so we need to do this ourselves)
$dx = $endOfRecord;
}
}
close(OUTFILE);
# Display results to user
print "\n[*] Done: " . $fieldsSorted . " fields sorted from " . $recordsWrittenCount . " records written.\n";
Так что я подумал об этом, и я думаю, что-то вроде trie, может быть, trie/PATRICIA trie с суффиксом, так что при самой вставке поля в каждой записи сортируются. Следовательно, мне не пришлось бы сортировать окончательный массив всего за один раз, и стоимость была бы амортизирована (спекуляция с моей стороны)
В этом случае возникает другая проблема - Tie::File использует массив для абстрагирования строк в файле - чтение строк в дерево и последующая их сериализация обратно в массив потребует дополнительной памяти И обработки /
Вопрос в том, будет ли это стоить больше, чем текущая стоимость сортировки связанного массива?
1 ответ
Tie::File очень медленный Для этого есть две причины: во-первых, связанные переменные значительно медленнее, чем стандартные переменные. Другая причина в том, что в случае Tie::File данные в вашем массиве находятся на диске, а не в памяти. Это сильно замедляет доступ. Кеш Tie::File может помочь производительности в некоторых случаях, но не тогда, когда вы просто зацикливаете массив по одному элементу за раз, как здесь. (Кэш помогает только при повторном посещении того же индекса.) Время использования Tie::File - это когда у вас есть алгоритм, который требует наличия всех данных в памяти одновременно, но у вас недостаточно памяти для этого. Поскольку вы обрабатываете файл по одной строке за раз, используя Tie::File, это не только бессмысленно, но и вредно.
Я не думаю, что три это правильный выбор здесь. Я бы использовал простой HoH (хэш хэшей) вместо этого. Ваши файлы достаточно малы, чтобы вы могли получить все в памяти сразу. Я рекомендую разбирать каждый файл и создавать хэш, который выглядит следующим образом:
%data = (
id1 => {
field1 => value1,
field2 => value2,
},
id2 => {
field1 => value1,
field2 => value2,
},
);
Если вы используете свои сопоставления для нормализации имен полей при построении структуры данных, это упростит сравнение.
Чтобы сравнить данные, сделайте это:
- Выполните сравнение набора ключей двух хешей. Это должно создать три списка: идентификаторы, присутствующие только в устаревших данных, идентификаторы, присутствующие только в новых данных, и идентификаторы, присутствующие в обоих.
- Сообщите списки идентификаторов, которые появляются только в одном наборе данных. Это записи, которые не имеют соответствующей записи в другом наборе данных.
- Для идентификаторов в обоих наборах данных сравните данные для каждого поля идентификатора по полю и сообщите о любых различиях.