【问题标题】:Optimize Duplicate Detection优化重复检测
【发布时间】:2012-10-23 01:37:35
【问题描述】:

背景

这是一个优化问题。 Oracle Forms XML 文件具有以下元素:

<Trigger TriggerName="name" TriggerText="SELECT * FROM DUAL" ... />

TriggerText 是任意 SQL 代码。每个 SQL 语句都被提取到唯一命名的文件中,例如:

sql/module=DIAL_ACCESS+trigger=KEY-LISTVAL+filename=d_access.fmb.sql     
sql/module=REP_PAT_SEEN+trigger=KEY-LISTVAL+filename=rep_pat_seen.fmb.sql 

我编写了一个脚本来使用蛮力方法生成一个完全重复的列表。

问题

有 37,497 个文件可供相互比较;将一个文件与所有其他文件进行比较需要 8 分钟。从逻辑上讲,如果A = BA = C,则无需检查B = C。那么问题来了:如何消除冗余比较?

脚本将在大约 208 天内完成。

脚本源代码

对比脚本如下:

#!/bin/bash

echo Loading directory ...

for i in $(find sql/ -type f -name \*.sql); do
        echo Comparing $i ...

        for j in $(find sql/ -type f -name \*.sql); do
                if [ "$i" = "$j" ]; then
                        continue;
                fi

                # Case insensitive compare, ignore spaces
                diff -IEbwBaq $i $j > /dev/null

                # 0 = no difference (i.e., duplicate code)
                if [ $? = 0 ]; then
                        echo $i :: $j >> clones.txt
                fi
        done
done

问题

您将如何优化脚本以便检查克隆代码的速度提高几个数量级?

想法 #1

将匹配的文件删除到另一个目录,这样就不需要检查两次了。

系统约束

使用带有 SSD 的四核 CPU;尽可能避免使用云服务。该系统是一台安装了 Cygwin 的基于 Windows 的机器——欢迎使用其他语言的算法或解决方案。

谢谢!

【问题讨论】:

  • 两个初始问题:1)“重复”文件中的数据是否总是按相同的顺序排列,或者行是否可以乱序?我假设是前者,因为您使用的是diff; 2)要被视为重复,我们可以假设它必须区分大小写吗?我假设不敏感,因为您专门将diff 与不区分大小写的比较一起使用 - 但如果区分大小写,则存在更好的方法。
  • 1) 文件应按相同顺序返回;这可以使用排序命令或find 的参数强制执行。 2)大小写需要不敏感匹配;只有空格和空行不同的文件必须被视为重复代码。
  • 如果你想要性能,bash 脚本不是一个好主意。
  • Bash 不是问题,Dani(虽然我同意基于 C 的解决方案会执行得更快,但即使比较所有 37,000 个文件只需要 30 秒 [而不是 8 分钟],那也是还有 12 天)。算法是O(n^2) 任何语言。

标签: perl bash optimization big-o code-duplication


【解决方案1】:

您的解决方案和 sputnick 的解决方案都需要 O(n^2) 时间。这可以通过对文件进行排序并使用列表合并在 O(nlog n) 时间内完成。它可以通过比较文件的 MD5(或任何其他加密强的哈希函数)而不是文件本身来进一步加快速度。

假设您在sql 目录中:

md5sum * | sort > ../md5sums
perl -lane 'print if $F[0] eq $lastMd5; $last = $_; $lastMd5 = $F[0]' < ../md5sums

使用上面的代码将只报告精确的逐字节重复。如果您想考虑两个不相同的文件在此比较中是等效的(例如,如果您不关心大小写),请首先创建每个文件的规范化副本(例如,通过使用 @ 将每个字符转换为小写987654323@)。

【讨论】:

  • 必须忽略大小写和空格。关于哈希的好主意;我也在考虑简单地将匹配的文件移动到另一个目录。
  • 空格可以用tr -d ' \r\n\t'删除。
  • 谢谢!我用tr -s 挤压它。
【解决方案2】:

最好的方法是对每个文件进行哈希处理,比如 SHA-1,然后使用一个集合。我不确定 bash 可以做到这一点,但 python 可以。虽然如果你想要最好的性能 C++ 是要走的路。

【讨论】:

    【解决方案3】:

    优化文件比较:

    #!/bin/bash
    
    for i; do
        for j; do
            [[ "$i" != "$j" ]] &&
                if diff -IEbwBaq "$i" "$j" > /dev/null; then
                    echo "$i & $j are the same"
                else
                    echo "$i & $j are different"
                fi
        done
    done
    

    用法

    ./script /dir/*
    

    【讨论】:

    • cmp 不提供不区分大小写或忽略空格的比较。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-26
    • 2013-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-29
    相关资源
    最近更新 更多