3

在一台装有 AIX 的机器上,PERL如果它们具有相同的 id 并且如果它们在四个小时内注册,则我需要过滤将被视为重复的记录。

我使用这个过滤器实现了这个过滤器AWK并且工作得很好,但我需要一个更快的解决方案:

# Generar lista de Duplicados
awk'开始{
FS=","
}
/好的/ {
    老[$8] = f[$8];
    f[$8] = mktime($4, $3, $2, $5, $6, $7);
    x[$8]++;
}
/OK/ && x[$8]>1 && f[$8]-old[$8]

有什么建议么?有没有办法改善环境(预加载文件或类似的东西)?

输入文件已经排序。

通过jj33建议的更正,我制作了一个新版本,对日期进行了更好的处理,但仍然保持低调以合并更多操作:

awk'开始{ FS=","; 秒每分钟=60; 秒=3600; SECSPERDAY=86400; 拆分(“0 31 59 90 120 151 181 212 243 273 304 334”,DAYSTOMONTH,“”); 拆分(“0 366 731 1096 1461 1827 2192 2557 2922 3288 3653 4018 4383 4749 5114 5479 5844 6210 6575 6940 7305”,DAYSTOYEAR,“”); } /好的/ { 老[$8] = f[$8]; f[$8] = mktime($4, $3, $2, $5, $6, $7); x[$8]++; } /OK/ && x[$8]>1 && f[$8]-old[$8] 2 ) && ( ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 = = 0) ) ) { d2m = d2m + 1; } d2y = DAYSTOYEAR[ y - 1999 ]; 返回 ss + (mm*SECSPERMINUTE) + (hh*SECSPEROUR) + (d*SECSPERDAY) + (d2m*SECSPERDAY) + (d2y*SECSPERDAY); } '
4

6 回答 6

3

这听起来像是一个实际数据库的工作。甚至像 SQLite 这样的东西也可能在这里为您提供相当好的帮助。我看到的最大问题是您对“4 小时内”的定义。这是一个滑动窗口问题,这意味着您不能简单地将所有数据量化为 4 小时段……您必须分别计算每个其他元素的所有“附近”元素。啊。

于 2008-10-05T06:29:33.500 回答
1

如果您的数据文件包含您的所有记录(即它包括文件中没有重复 ID 的记录),您可以对其进行预处理并生成一个仅包含具有重复 ID 的记录的文件。

如果这种情况会减少您需要使用 AWK 程序处理的文件大小。

于 2008-08-09T15:25:29.980 回答
1

输入文件是如何排序的?比如,cat 文件|排序,还是通过单个特定字段或多个字段排序?如果有多个字段,哪些字段和顺序是什么?似乎小时字段是 24 小时制,而不是 12,对吧?所有日期/时间字段是否都用零填充(上午 9 点是“9”还是“09”?)

在不考虑性能的情况下,您的代码似乎存在月份边界问题,因为它假设所有月份都是 30 天。取两个日期 2008-05-31/12:00:00 和 2008-06-01:12:00:00。这些时间相隔 24 小时,但您的代码为两者生成相同的时间代码 (63339969600)

于 2008-08-09T18:41:47.977 回答
1

我认为您需要考虑闰年。我没有做数学计算,但我认为在闰年,2 月的硬代码为 28 天,比较 2 月 29 日中午和 3 月 1 日中午会导致与以前相同的重复时间戳. 虽然看起来你没有像那样实现它。他们以你实现它的方式,我认为你仍然有问题,但它介于 $leapyear 的 12/31 和 $leapyear+1 的 1/1 之间。

我认为如果您的代码必须处理处理它们的时区,那么在时间更改期间您可能还会遇到一些冲突。

该文件似乎并没有以任何有用的方式进行排序。我猜该字段 $1 是某种状态(您正在检查的“OK”)。所以它是按记录状态排序的,然后是天,然后是月、年、小时、分钟、秒。如果是年、月、日,我认为那里可能会有一些优化。仍然可能是,但我的大脑现在正朝着不同的方向发展。

如果与总行数成比例的重复键数量很少,我认为最好的办法是减少 awk 脚本工作的文件,只使用重复键(正如大卫所说)。您还可以对文件进行预处理,以便唯一存在的行是 /OK/ 行。我想我会使用管道来执行此操作,其中第一个 awk 脚本仅打印具有重复 ID 的行,而第二个 awk 脚本基本上是上面的那个,但经过优化以不查找 /OK/ 并且知道存在的任何键都是重复键。

如果您提前知道所有或大多数行都会有重复的键,那么可能不值得搞砸。我会硬着头皮用 C 语言编写它。代码行数更多,比 awk 脚本快得多。

于 2008-08-10T03:12:10.240 回答
1

在许多 unixen 上,您可以通过特定的列或字段进行排序。因此,通过按 ID 排序文件,然后按日期排序,您不再需要保留上次看到每个 ID 时间的关联数组。所有上下文都按文件的顺序排列。

在我的具有 GNU 排序的 Mac 上,它是:

sort -k 8 < input.txt > output.txt

对 ID 字段进行排序。您也可以通过说(例如)8,3 来对第二个字段进行排序,但只有 2 个字段。因此,unix 风格的 time_t 时间戳在文件中可能不是一个坏主意 - 它很容易排序,并为您节省所有这些日期计算。此外,(再次至少在 GNU awk 中),有一个mktime 函数可以从组件中为您生成 time_t。

于 2008-08-10T14:51:02.187 回答
1

@AnotherHowie, I thought the whole preprocessing could be done with sort and uniq. The problem is that the OP's data seems to be comma delimited and (Solaris 8's) uniq doesn't allow you any way specify the record separator, so there wasn't a super clean way to do the preprocessing using standard unix tools. I don't think it would be any faster so I'm not going to look up the exact options, but you could do something like:

cut -d, -f8 <infile.txt | sort | uniq -d | xargs -i grep {} infile.txt >outfile.txt

That's not very good because it executes grep for every line containing a duplicate key. You could probably massage the uniq output into a single regexp to feed to grep, but the benefit would only be known if the OP posts expected ratio of lines containing suspected duplicate keys to total lines in the file.

于 2008-08-11T13:07:51.987 回答