更快地查找受时间限制的重复项

Posted

技术标签:

【中文标题】更快地查找受时间限制的重复项【英文标题】:Faster way to find duplicates conditioned by time 【发布时间】:2010-09-05 14:37:10 【问题描述】:

在没有PERL 的AIX 机器中,如果它们具有相同的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); '

【问题讨论】:

【参考方案1】:

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

【讨论】:

【参考方案2】:

@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 输出按摩到单个正则表达式中以提供给 grep,但只有当 OP 发布包含可疑重复键的行与文件中总行的预期比率时,才能知道好处。

【讨论】:

【参考方案3】:

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

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

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

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

【讨论】:

【参考方案4】:

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

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

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

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

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

【讨论】:

【参考方案5】:

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

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

【讨论】:

【参考方案6】:

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

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

【讨论】:

以上是关于更快地查找受时间限制的重复项的主要内容,如果未能解决你的问题,请参考以下文章

将不受信任的java代码限制为单个线程[重复]

MySQL 限制的 SQL Server 等效项 [重复]

如何优化限制查询以便从庞大的表中更快地访问数据?

按组限制而不省略重复项?

更好/更快地循环遍历集合或列表?

在 db4o 中创建对象时限制子重复项