优化重复检测

时间:2012-10-23 01:37:36

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

背景

这是一个优化问题。 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的机器 - 欢迎使用其他语言的算法或解决方案。

谢谢!

3 个答案:

答案 0 :(得分: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

使用上面的代码只会报告精确的逐字节重复项。如果您想要将两个不相同的文件视为此比较的等效文件(例如,如果您不关心案例),请首先创建每个文件的规范化副本(例如,通过将每个字符转换为小写字母{ {1}})。

答案 1 :(得分:0)

执行此操作的最佳方法是散列每个文件,如SHA-1,然后使用集合。我不确定bash可以做到这一点,但python可以。虽然如果你想要最佳性能,C ++就是你的选择。

答案 2 :(得分:-1)

优化文件比较:

#!/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

<强> USAGE

./script /dir/*