查找按时间限制的重复项的更快方法
在装有AIX且没有" PERL"的机器上,我需要过滤记录,如果它们具有相同的ID,并且在四个小时内被注册,那么这些记录将被视为重复记录。
我使用AWK
实现了此过滤器,并且运行良好,但是我需要更快的解决方案:
# Generar lista de Duplicados awk 'BEGIN { FS="," } /OK/ { old[] = f[]; f[] = mktime(, , , , , ); x[]++; } /OK/ && x[]>1 && f[]-old[] Any suggestions? Are there ways to improve the environment (preloading the file or someting like that)? The input file is already sorted. With the corrections suggested by jj33 I made a new version with better treatment of dates, still maintaining a low profile for incorporating more operations: awk 'BEGIN { FS=","; SECSPERMINUTE=60; SECSPERHOUR=3600; SECSPERDAY=86400; split("0 31 59 90 120 151 181 212 243 273 304 334", DAYSTOMONTH, " "); split("0 366 731 1096 1461 1827 2192 2557 2922 3288 3653 4018 4383 4749 5114 5479 5844 6210 6575 6940 7305", DAYSTOYEAR, " "); } /OK/ { old[] = f[]; f[] = mktime(, , , , , ); x[]++; } /OK/ && x[]>1 && f[]-old[] 2 ) && ( ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0) ) ) { d2m = d2m + 1; } d2y = DAYSTOYEAR[ y - 1999 ]; return ss + (mm*SECSPERMINUTE) + (hh*SECSPEROUR) + (d*SECSPERDAY) + (d2m*SECSPERDAY) + (d2y*SECSPERDAY); } '
解决方案
回答
如果数据文件包含所有记录(即,其中包含文件中没有重复ID的记录),则可以对其进行预处理,并生成仅包含重复(ID)记录的文件。
如果是这种情况,则会减小文件的大小,我们需要使用AWK程序进行处理。
回答
输入文件如何排序?就像cat文件|通过单个特定字段或者多个字段排序?如果有多个字段,什么字段和什么顺序?看来小时字段是24小时制,而不是12小时,对吗?所有日期/时间字段是否都补零(上午9点是" 9"还是" 09"?)
如果不考虑性能,则代码似乎存在月份边界问题,因为它假设所有月份都为30天。拿两个日期2008-05-31 / 12:00:00和2008-06-01:12:00:00。这些时间间隔为24小时,但代码会为两个代码产生相同的时间代码(63339969600)
回答
我认为我们需要考虑leap年。我没有进行数学运算,但是我认为在a年期间,如果将2月29日的中午和3/1的中午进行比较,那么2月的硬编码为28天,则时间戳将与之前相同。尽管看起来我们并没有那样实现。他们以哪种方式实现了它,我认为我们仍然有问题,但是它介于$ leapyear的12/31和$ leapyear + 1的1/1之间。
我认为,如果代码必须处理处理它们的时区,那么在时间更改期间我们可能还会遇到一些冲突。
该文件似乎并没有以任何有用的方式进行排序。我猜$ 1字段是某种状态(我们要检查的"确定")。因此,它是按记录状态排序的,然后是DAY,然后是MONTH,YEAR,HOURS,MINUTES,SECONDS。如果是年,月,日,我认为那里可能会有一些优化。可能仍然是,但是我的大脑现在正朝着不同的方向前进。
如果与行总数成比例的重复键数量很少,我认为最好的选择是将awk脚本可工作的文件减少为重复键(如David所说)。我们还可以对文件进行预处理,因此仅存在的行是/ OK /行。我想我会用一个管道来做到这一点,其中第一个awk脚本仅打印具有重复ID的行,第二个awk脚本基本上是上面的行,但是经过优化以不查找/ OK /并且知道存在的任何键都是重复键。
如果我们提前知道所有或者大多数行都将具有重复的键,那么可能就不值得一试。我会硬着头皮用C编写它。编写更多的代码行,比awk脚本快得多。
回答
在许多unixen上,我们可以按特定的列或者字段进行排序。因此,通过按ID对文件进行排序,然后按日期对文件进行排序,我们将不再需要保留上次看到每个ID时的关联数组。所有上下文均按文件顺序存在。
在我的Mac(具有GNU排序)上,它是:
sort -k 8 < input.txt > output.txt
在ID字段上排序。我们也可以在第二个字段中排序,例如改为说8,3,但只能说2个字段。因此,unix风格的time_t时间戳在文件中易于排序很容易,它可以节省所有这些日期计算。另外,(至少在GNU awk中)还有一个mktime函数,该函数通过组件为我们提供time_t。
回答
@AnotherHowie,我认为整个预处理过程可以通过sort和uniq完成。问题在于OP的数据似乎是用逗号分隔的,并且(Solaris 8的)uniq不允许我们指定记录分隔符的任何方式,因此,没有一种使用标准的unix工具进行预处理的超级干净的方法。我认为速度不会更快,因此我不会查找确切的选项,但是我们可以执行以下操作:
cut -d, -f8 <infile.txt | sort | uniq -d | xargs -i grep {} infile.txt >outfile.txt
这不是很好,因为它会对包含重复键的每一行执行grep。我们可能可以将uniq输出按摩到单个regexp中以馈送给grep,但是只有在OP发布文件中包含可疑重复键的行与总行数的预期比率时,才能知道好处。
回答
这听起来像是实际数据库的工作。甚至像SQLite之类的东西也可能在这里对我们有所帮助。我看到的最大问题是我们对" 4小时内"的定义。这是一个滑动窗口问题,这意味着我们不能简单地将所有数据量化为4小时片段...我们必须为其他每个元素分别计算所有"附近"元素。啊。