Memory awk中的关联数组挑战内存限制

Memory awk中的关联数组挑战内存限制,memory,awk,gawk,Memory,Awk,Gawk,这与我最近在中的帖子有关,也与 我在这里的基本问题是简单地从详细的古代档案金融市场数据计算,#交易、#股票、价值、按日期、公司ID、交易所等的每日合计。为此,我学会了在awk中使用关联数组,并且很高兴能够在不到11分钟的时钟时间内处理1.29亿多行。在我喝完咖啡之前 变得更加雄心勃勃,从2个数组下标移动到4个,现在我无法一次处理超过6500行 获取表单的错误消息: K:\User Folders\KRISHNANM\PAPERS\FII\u Transaction\u Data>zcat 原始数

这与我最近在中的帖子有关,也与

我在这里的基本问题是简单地从详细的古代档案金融市场数据计算,#交易、#股票、价值、按日期、公司ID、交易所等的每日合计。为此,我学会了在awk中使用关联数组,并且很高兴能够在不到11分钟的时钟时间内处理1.29亿多行。在我喝完咖啡之前

变得更加雄心勃勃,从2个数组下标移动到4个,现在我无法一次处理超过6500行

获取表单的错误消息:

K:\User Folders\KRISHNANM\PAPERS\FII\u Transaction\u Data>zcat 原始数据\2003\u 1.zip | gawk-f代码\FII\u每日(聚合)\u v2.awk> 输出\2003\u 1.txt&

gawk:CODE\FII\u daily\u aggregates\u v2.awk:33:(文件名=-FNR=49300) 致命:更多\u否des:nextfree:无法分配内存(空间不足)

在一些运行中,机器告诉我它缺少的内存只有52KB。我有我认为的标准配置与Win-7和8MB内存

(培训经济学家,而不是计算机科学家)我意识到,从2个数组到4个数组会使计算机的计算复杂得多,但是有什么方法可以至少稍微改进内存管理呢。我已经试着关闭我正在做的一切。错误总是只与内存有关,而与磁盘空间或其他任何内容无关

样本输入:

49290,C198962542782200306,6/30/2003,433581,F5811773991200306,S5405611832200306,B5086397478200306,NESTLE INDIA LTD.,INE239A01016,6/27/2003,1,E9035083824200306,REG_DL_STLD_02,591.13,5655,3342840.15,REG_DL_INSTR_EQ,REG_DL_DLAY_P,DL_RPT_TYPE_N,DL_AMDMNT_DEL_00
49291,C198962542782200306,6/30/2003,433563,F6292896459200306,S6344227311200306,B6110521493200306,GRASIM INDUSTRIES LTD.,INE047A01013,6/27/2003,1,E9035083824200306,REG_DL_STLD_02,495.33,3700,1832721,REG_DL_INSTR_EQ,REG_DL_DLAY_P,DL_RPT_TYPE_N,DL_AMDMNT_DEL_00
49292,C198962542782200306,6/30/2003,433681,F6513202607200306,S1724027402200306,B6372023178200306,HDFC BANK LTD,INE040A01018,6/26/2003,1,E745964372424200306,REG_DL_STLD_02,242,2600,629200,REG_DL_INSTR_EQ,REG_DL_DLAY_D,DL_RPT_TYPE_N,DL_AMDMNT_DEL_00
49293,C7885768925200306,6/30/2003,48128,F4406661052200306,S7376401565200306,B4576522576200306,Maruti Udyog Limited,INE585B01010,6/28/2003,3,E912851176274200306,REG_DL_STLD_04,125,44600,5575000,REG_DL_INSTR_EQ,REG_DL_DLAY_P,DL_RPT_TYPE_N,DL_AMDMNT_DEL_00
49294,C7885768925200306,6/30/2003,48129,F4500260787200306,S1312094035200306,B4576522576200306,Maruti Udyog Limited,INE585B01010,6/28/2003,4,E912851176274200306,REG_DL_STLD_04,125,445600,55700000,REG_DL_INSTR_EQ,REG_DL_DLAY_P,DL_RPT_TYPE_N,DL_AMDMNT_DEL_00
49295,C7885768925200306,6/30/2003,48130,F6425024637200306,S2872499118200306,B4576522576200306,Maruti Udyog Limited,INE585B01010,6/28/2003,3,E912851176274200306,REG_DL_STLD_04,125,48000,6000000,REG_DL_INSTR_EU,REG_DL_DLAY_P,DL_RPT_TYPE_N,DL_AMDMNT_DEL_00
代码

就是在这种情况下,当输入记录的数量超过6500条时,我最终出现了内存问题。总共有大约700万条记录

对于2阵列下标问题,尽管是在不同的数据集上,在同一台机器上使用相同的GNU-AWK在11分钟的时钟时间内处理了1.29亿多行,请参阅

问:是不是awk在内存管理方面不是很聪明,但是其他一些更现代的工具(比如SQL)可以用同样的内存资源完成这项任务?或者这仅仅是关联数组的一个特征,我发现关联数组很神奇,可以避免数据的多次传递、多次循环和排序过程,但在多达2个数组下标的情况下,关联数组可能工作得很好,然后面临指数级的内存资源消耗

后记:埃德·莫顿在下面的评论中提供的超级详细的、几乎可以证明是傻瓜的教程以及代码使情况发生了巨大的变化,尤其是他的呆滞脚本tst.awk。他教我(a)智能地使用subsp(b)处理不必要的循环,这在这个问题中是至关重要的,这个问题往往有非常稀疏的数组,具有各种AWK构造。与我的旧代码的性能相比(一台机器上最多只能接受6500行输入,而另一台机器甚至无法达到这一水平),Ed Morton的tst.awk的性能可以从下表中看出:

**filename  start      end       min        in ln   out lines
2008_1  12:08:40 AM 12:27:18 AM 0:18        391438  301160
2008_2  12:27:18 AM 12:52:04 AM 0:24        402016  314177
2009_1  12:52:05 AM 1:05:15 AM  0:13        302081  238204
2009_2  1:05:15 AM  1:22:15 AM  0:17        360072  276768
2010_1  "slept"                         507496  397533
2010_2  3:10:26 AM  3:10:50 AM  0:00         76200   58228
2010_3  3:10:50 AM  3:11:18 AM  0:00         80988   61725
2010_4  3:11:18 AM  3:11:47 AM  0:00         86923   65885
2010_5  3:11:47 AM  3:12:15 AM  0:00         80670   63059**

时间是在执行tst.awk之前和之后的行上使用%time%获得的,所有时间都放在一个简单的批处理脚本中,“min”是所用的时钟时间(默认情况下,根据EXCEL的取整),“in-ln”和“out-line”分别是输入行和输出行通过处理我们从2003年1月到2014年1月的全部数据,我们发现理论上的最大输出记录数=#dates*#ISINs*#Exchanges*#FIIs=2992*2955*567*82268,而实际的总输出行数只有5261942条,仅为理论最大值的1.275*10^(-8)——确实非常稀少。我们之前确实猜测到了稀疏性,但是数组可能非常稀疏——这对内存管理非常重要——对于一个真实的数据集,在实际完成之前,我们无法判断。所花费的时间在输入大小上似乎呈指数增长,但在没有实际困难的范围内。非常感谢,Ed.

通常关联数组没有问题。在awk中(除了真实2D数组的gawk),具有4个下标的关联数组与具有2个下标的关联数组是相同的,因为实际上它只有一个下标,即由subsp分隔的每个伪下标的串联

如果您说
我无法一次处理超过6500行。
问题更可能在于您编写代码的方式,而不是任何基本的awk问题,因此如果您需要更多帮助,发布一个包含示例输入和预期输出的小脚本,演示您的问题和尝试的解决方案,看看我们是否有改进其内存使用率的建议

考虑到您发布的脚本,我认为问题在于当您执行以下操作时,结尾部分中的嵌套循环:

for (i=1; i<=maxI; i++) {
    for (j=1; j<=maxJ; j++) {
        if  ( arr[i,j] != 0 ) {
            print arr[i,j]
        }
    }
}
然后循环本身不会在
arr[]
中创建新条目

因此,请更改此块:

if (BNR[date_list[u],isin_list[v],exch_list[w],fii_list[x]] + SNR[date_list[u],isin_list[v],exch_list[w],fii_list[x]] > 0)
{
    BR = BNR[date_list[u],isin_list[v],exch_list[w],fii_list[x]]
    SR = SNR[date_list[u],isin_list[v],exch_list[w],fii_list[x]]
    BS = BSH[date_list[u],isin_list[v],exch_list[w],fii_list[x]]
    BV = BRV[date_list[u],isin_list[v],exch_list[w],fii_list[x]]
    SS = SSH[date_list[u],isin_list[v],exch_list[w],fii_list[x]]
    SV = SRV[date_list[u],isin_list[v],exch_list[w],fii_list[x]]
这可能不必要地将BNR、SNR、BSH、BRV、SSH和SRV中的每一个都变成了巨大但高度稀疏的阵列,如下所示:

idx = date_list[u] SUBSEP isin_list[v] SUBSEP exch_list[w] SUBSEP fii_list[x]
BR = (idx in BNR ? BNR[idx] : 0)
SR = (idx in SNR ? SNR[idx] : 0)
if ( (BR + SR) > 0 )
{
    BS = (idx in BSH ? BSH[idx] : 0)
    BV = (idx in BRV ? BRV[idx] : 0)
    SS = (idx in SSH ? SSH[idx] : 0)
    SV = (idx in SRV ? SRV[idx] : 0)
如果有帮助,请告诉我们。还要检查代码中可能正在执行相同操作的其他位置

当您没有使用2时,4个下标会出现此问题,原因很简单,当您使用2时,循环中有4个嵌套级别,现在创建了更大、更稀疏的数组

最后-您的脚本中有一些奇怪的语法,@MarkSetchell在一条注释中指出了其中一些语法,并且您的脚本没有使用
else
语句,因此测试不可能全部为真的多个条件,并且重复测试同一个条件,因此您的脚本没有达到预期的效率,而且它并不健壮,因为你没有锚定你的REs(例如你测试
/4 | 1[13]/
而不是
/^(4 | 1[13])$/
,因此,例如你的
4
将匹配
14
41
等。而不仅仅是
4
本身),所以将整个脚本更改为:

$ cat tst.awk
BEGIN { FS = "," }
# For each array subscript variable -- DATE ($10), firm_ISIN ($9), EXCHANGE ($12), and FII_ID ($5), after checking for type = EQ, set up counts for each value, and number of unique values.
$17 ~ /_EQ\>/ {
    if (!seenDate[$10]++) date_list[++d] = $10
    if (!seenIsin[$9]++)  isin_list[++i] = $9
    if (!seenExch[$12]++) exch_list[++e] = $12
    if (!seenFii[$5]++)   fii_list[++f]  = $5

    # For cash-in, buy (B), or cash-out, sell (S) count NR = no of records, SH = no of shares, RV = rupee-value.
    idx = $10 SUBSEP $9 SUBSEP $12 SUBSEP $5
    if ( $11 ~ /^([12359]|1[24])$/ ) {
        ++BNR[idx]; BSH[idx] += $15; BRV[idx] += $16
    }
    else if ( $11 ~ /^(4|1[13])$/ ) {
        ++SNR[idx]; SSH[idx] += $15; SRV[idx] += $16
    }
}
END {
    print NR, "records processed."
    print "  "
    printf "%-11s\t%-13s\t%-20s\t%-19s\t%-7s\t%-7s\t%-14s\t%-14s\t%-18s\t%-18s\n",
           "DATE", "ISIN", "EXCH", "FII", "BNR", "SNR", "BSH", "SSH", "BRV", "SRV"
    for (u = 1; u <= d; u++)
    {
        for (v = 1; v <= i; v++)
        {
            for (w = 1; w <= e; w++)
            {
                for (x = 1; x <= f; x++)
                {
                    #check first below for records with zeroes, don't print them
                    idx = date_list[u] SUBSEP isin_list[v] SUBSEP exch_list[w] SUBSEP fii_list[x]
                    BR = (idx in BNR ? BNR[idx] : 0)
                    SR = (idx in SNR ? SNR[idx] : 0)
                    if ( (BR + SR) > 0 )
                    {
                        BS = (idx in BSH ? BSH[idx] : 0)
                        BV = (idx in BRV ? BRV[idx] : 0)
                        SS = (idx in SSH ? SSH[idx] : 0)
                        SV = (idx in SRV ? SRV[idx] : 0)
                        printf "%-11s\t%13s\t%20s\t%19s\t%7d\t%7d\t%14d\t%14d\t%18.2f\t%18.2f\n",
                            date_list[u], isin_list[v], exch_list[w], fii_list[x], BR, SR, BS, SS, BV, SV
                    }
                }
            }
        }
    }
}

您是否也可以添加
FII\u daily\u aggregates\u v2.awk
的代码,以使问题
if (BNR[date_list[u],isin_list[v],exch_list[w],fii_list[x]] + SNR[date_list[u],isin_list[v],exch_list[w],fii_list[x]] > 0)
{
    BR = BNR[date_list[u],isin_list[v],exch_list[w],fii_list[x]]
    SR = SNR[date_list[u],isin_list[v],exch_list[w],fii_list[x]]
    BS = BSH[date_list[u],isin_list[v],exch_list[w],fii_list[x]]
    BV = BRV[date_list[u],isin_list[v],exch_list[w],fii_list[x]]
    SS = SSH[date_list[u],isin_list[v],exch_list[w],fii_list[x]]
    SV = SRV[date_list[u],isin_list[v],exch_list[w],fii_list[x]]
idx = date_list[u] SUBSEP isin_list[v] SUBSEP exch_list[w] SUBSEP fii_list[x]
BR = (idx in BNR ? BNR[idx] : 0)
SR = (idx in SNR ? SNR[idx] : 0)
if ( (BR + SR) > 0 )
{
    BS = (idx in BSH ? BSH[idx] : 0)
    BV = (idx in BRV ? BRV[idx] : 0)
    SS = (idx in SSH ? SSH[idx] : 0)
    SV = (idx in SRV ? SRV[idx] : 0)
$ cat tst.awk
BEGIN { FS = "," }
# For each array subscript variable -- DATE ($10), firm_ISIN ($9), EXCHANGE ($12), and FII_ID ($5), after checking for type = EQ, set up counts for each value, and number of unique values.
$17 ~ /_EQ\>/ {
    if (!seenDate[$10]++) date_list[++d] = $10
    if (!seenIsin[$9]++)  isin_list[++i] = $9
    if (!seenExch[$12]++) exch_list[++e] = $12
    if (!seenFii[$5]++)   fii_list[++f]  = $5

    # For cash-in, buy (B), or cash-out, sell (S) count NR = no of records, SH = no of shares, RV = rupee-value.
    idx = $10 SUBSEP $9 SUBSEP $12 SUBSEP $5
    if ( $11 ~ /^([12359]|1[24])$/ ) {
        ++BNR[idx]; BSH[idx] += $15; BRV[idx] += $16
    }
    else if ( $11 ~ /^(4|1[13])$/ ) {
        ++SNR[idx]; SSH[idx] += $15; SRV[idx] += $16
    }
}
END {
    print NR, "records processed."
    print "  "
    printf "%-11s\t%-13s\t%-20s\t%-19s\t%-7s\t%-7s\t%-14s\t%-14s\t%-18s\t%-18s\n",
           "DATE", "ISIN", "EXCH", "FII", "BNR", "SNR", "BSH", "SSH", "BRV", "SRV"
    for (u = 1; u <= d; u++)
    {
        for (v = 1; v <= i; v++)
        {
            for (w = 1; w <= e; w++)
            {
                for (x = 1; x <= f; x++)
                {
                    #check first below for records with zeroes, don't print them
                    idx = date_list[u] SUBSEP isin_list[v] SUBSEP exch_list[w] SUBSEP fii_list[x]
                    BR = (idx in BNR ? BNR[idx] : 0)
                    SR = (idx in SNR ? SNR[idx] : 0)
                    if ( (BR + SR) > 0 )
                    {
                        BS = (idx in BSH ? BSH[idx] : 0)
                        BV = (idx in BRV ? BRV[idx] : 0)
                        SS = (idx in SSH ? SSH[idx] : 0)
                        SV = (idx in SRV ? SRV[idx] : 0)
                        printf "%-11s\t%13s\t%20s\t%19s\t%7d\t%7d\t%14d\t%14d\t%18.2f\t%18.2f\n",
                            date_list[u], isin_list[v], exch_list[w], fii_list[x], BR, SR, BS, SS, BV, SV
                    }
                }
            }
        }
    }
}
$ cat tst.awk
BEGIN { FS = "," }
# For each array subscript variable -- DATE ($10), firm_ISIN ($9), EXCHANGE ($12), and FII_ID ($5), after checking for type = EQ, set up counts for each value, and number of unique values.
$17 ~ /_EQ\>/ {
    if (!seenDate[$10]++) date_list[++d] = $10
    if (!seenIsin[$9]++)  isin_list[++i] = $9
    if (!seenExch[$12]++) exch_list[++e] = $12
    if (!seenFii[$5]++)   fii_list[++f]  = $5

    # For cash-in, buy (B), or cash-out, sell (S) count NR = no of records, SH = no of shares, RV = rupee-value.
    idx = $10 SUBSEP $9 SUBSEP $12 SUBSEP $5
    if ( $11 ~ /^([12359]|1[24])$/ ) {
        seen[$10,$9]
        seen[$10,$9,$12]
        ++BNR[idx]; BSH[idx] += $15; BRV[idx] += $16
    }
    else if ( $11 ~ /^(4|1[13])$/ ) {
        seen[$10,$9]
        seen[$10,$9,$12]
        ++SNR[idx]; SSH[idx] += $15; SRV[idx] += $16
    }
}
END {
    printf "d = %d\n", d | "cat>&2"
    printf "i = %d\n", i | "cat>&2"
    printf "e = %d\n", e | "cat>&2"
    printf "f = %d\n", f | "cat>&2"

    print NR, "records processed."
    print "  "
    printf "%-11s\t%-13s\t%-20s\t%-19s\t%-7s\t%-7s\t%-14s\t%-14s\t%-18s\t%-18s\n",
           "DATE", "ISIN", "EXCH", "FII", "BNR", "SNR", "BSH", "SSH", "BRV", "SRV"
    for (u = 1; u <= d; u++)
    {
        date = date_list[u]
        for (v = 1; v <= i; v++)
        {
            isin = isin_list[v]
            if ( (date,isin) in seen )
            {
                for (w = 1; w <= e; w++)
                {
                    exch = exch_list[w]
                    if ( (date,isin,exch) in seen )
                    {
                        for (x = 1; x <= f; x++)
                        {
                            fii = fii_list[x]
                            #check first below for records with zeroes, don't print them
                            idx = date SUBSEP isin SUBSEP exch SUBSEP fii
                            if ( (idx in BNR) || (idx in SNR) )
                            {
                                if (idx in BNR)
                                {
                                    bnr = BNR[idx]
                                    bsh = BSH[idx]
                                    brv = BRV[idx]
                                }
                                else
                                {
                                    bnr = bsh = brv = 0
                                }

                                if (idx in SNR)
                                {
                                    snr = SNR[idx]
                                    ssh = SSH[idx]
                                    srv = SRV[idx]
                                }
                                else
                                {
                                    snr = ssh = srv = 0
                                }

                                printf "%-11s\t%13s\t%20s\t%19s\t%7d\t%7d\t%14d\t%14d\t%18.2f\t%18.2f\n",
                                    date, isin, exch, fii, bnr, snr, bsh, ssh, brv, srv
                            }
                        }
                    }
                }
            }
        }
    }
}