【问题标题】:Merging rows in a file | Performance Improvement合并文件中的行 |性能改进
【发布时间】:2013-12-29 20:56:31
【问题描述】:

我有一个文件,我必须根据以下条件合并 2 行:
- 通用 sessionID
- 立即下一个匹配模式(GX 和 QG)

文件1:

session=001,field01,name=GX1_TRANSACTION,field03,field04    
session=001,field91,name=QG    
session=001,field01,name=GX2_TRANSACTION,field03,field04    
session=001,field92,name=QG    

session=004,field01,name=GX1_TRANSACTION,field03,field04    
session=002,field01,name=GX1_TRANSACTION,field03,field04    
session=002,field01,name=GX2_TRANSACTION,field03,field04    
session=002,field92,name=QG    

session=003,field91,name=QG    
session=003,field01,name=GX2_TRANSACTION,field03,field04    
session=003,field92,name=QG    

session=004,field91,name=QG    
session=004,field01,name=GX2_TRANSACTION,field03,field04    
session=004,field92,name=QG    

我创建了一个 awk(我是新手,只从这个门户学习过 awk),它创建了我想要的输出。

输出1

session=001,field01,name=GX1_TRANSACTION,field03,field04,session=001,field91,name=QG
session=001,field01,name=GX2_TRANSACTION,field03,field04,session=001,field92,name=QG
session=002,field01,name=GX1_TRANSACTION,field03,field04,NOMATCH-QG
session=002,field01,name=GX2_TRANSACTION,field03,field04,session=002,field92,name=QG
session=003,field01,name=GX2_TRANSACTION,field03,field04,session=003,field92,name=QG
session=004,field01,name=GX1_TRANSACTION,field03,field04,session=004,field91,name=QG
session=004,field01,name=GX2_TRANSACTION,field03,field04,session=004,field92,name=QG

输出 2:待处理

session=003,field91,name=QG    

Awk:

{
    if($0~/name=GX1_TRANSACTION/ || $0~/GX2_TRANSACTION/) {
        if($1 in ccr)
            print ccr[$1]",NOMATCH-QG";
        ccr[$1]=$0;
    }
    if($0~/name=QG/) {
        if($1 in ccr) {
            print ccr[$1]","$0;
            delete ccr[$1];
        }
        else {
            print $0",NOUSER" >> Pending
        }
    }
}
END {
    for (i in ccr)
        print ccr[i]",NOMATCH-QG"
} 

命令:

awk -F"," -v Pending=t -f a.awk file1    

但问题是我的“file1”真的很大,所以我想提高这个脚本的性能。他们有什么方法可以提高它的性能吗?

【问题讨论】:

  • 我看不到任何明显的改进之处。如果您有gawk 版本4,您可以尝试使用gawk --profile 运行它,并生成带有分析信息的文件awkprof.out。您也可以尝试将程序移植到perl 以查看perl 是否可以提供更快的解决方案..

标签: awk gawk


【解决方案1】:

有一些更改可能会导致速度的小幅提高,如果没有,可能会给您一些关于未来 awk 脚本的想法。

  1. 如果没有必要,不要“手动”测试每一行 - 将 name= 测试提升到主 awk 循环。目前,您的脚本每行最多检查 $0 三次以匹配 name=
  2. 由于您使用, 作为FS,请测试相应的字段($3) 而不是$0。它只会在您的示例数据中保存一些模式匹配的前导字符。

这是重构的a.awk

$3~/name=GX[12]_TRANSACTION/ {
    if($1 in ccr)
        print ccr[$1]",NOMATCH-QG";
    ccr[$1]=$0;
}

$3~/name=QG/ {
    if($1 in ccr) {
        print ccr[$1]","$0;
        delete ccr[$1];
    }
    else {
        print $0",NOUSER"  >> Pending
    }
}

END { for (i in ccr) print ccr[i]",NOMATCH-QG" }

我还将GX 模式匹配压缩为一个正则表达式。我得到与您的示例相同的输出。

【讨论】:

    【解决方案2】:

    在任何程序中,IO(例如print 语句)通常是最实时密集的操作。不过,在 awk 中有一个更慢的操作,那就是字符串连接。因为 awk 不需要您为字符串预先分配内存,所以内存是动态分配的,因此当您增加字符串的长度时,它必须动态重新分配。因此,您可以通过删除字符串连接来加速您的程序,例如对于您正在打印的所有硬编码“,”,而不仅仅是设置/使用 OFS。

    我还没有真正考虑过您的整体方法的逻辑,但您可以尝试其他一些调整:

    BEGIN{ FS=OFS="," }
    
    NF {
        if ($3 ~ /name=GX[12]_TRANSACTION/) {
            if($1 in ccr) {
                print ccr[$1], "NOMATCH-QG"
            }
            ccr[$1]=$0
        }
        else {
            if($1 in ccr) {
                print ccr[$1], $0
                delete ccr[$1]
            }
            else {
                print $0, "NOUSER" >> Pending
            }
        }
    }
    
    END {
        for (i in ccr)
            print ccr[i], "NOMATCH-QG"
    } 
    

    请注意,通过在脚本中设置FS,您不再需要在命令行中使用-F","

    您确定要将打印件上的>> 而非> 设置为“待处理”吗?这两个结构在 awk 中的含义与在 shell 中的含义不同。

    【讨论】:

    • 即使我也喜欢你解释的字符串连接的东西。不知道它对性能有多大帮助,但我肯定会实现它。谢谢:)
    • 是的,我想使用 >> 因为我想追加到文件中
    • 您好 Ed,有趣的是,当我实施您的更改时,处理时间增加了 4 秒(在 290MB 文件上)。我尝试了 3 次。当我恢复更改时,它又减少了 4 秒。因此,您的更改以某种方式增加了时间。
    • >>> 都“附加在文件中”,如果原始文件存在,则先将其删除。我无法想象什么会导致时间增加,您可以尝试逐步实施更改并测试以查看时间更改的位置,如果您关心的话。请注意,结果缓存可能会产生影响,因此请尝试每种解决方案几次,然后平均每个解决方案的时间统计信息。
    猜你喜欢
    • 2019-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-16
    • 1970-01-01
    • 2013-03-23
    • 2012-07-31
    • 2013-03-15
    相关资源
    最近更新 更多