Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/ant/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
awk关联数组快速增长_Awk_Out Of Memory_Associative Array - Fatal编程技术网

awk关联数组快速增长

awk关联数组快速增长,awk,out-of-memory,associative-array,Awk,Out Of Memory,Associative Array,我有一个为MD5SUMMS分配数字的文件,如下所示: 0 0000001732816557DE23435780915F75 1 00000035552C6F8B9E7D70F1E4E8D500 2 00000051D63FACEF571C09D98659DC55 3 0000006D7695939200D57D3FBC30D46C 4 0000006E501F5CBD4DB56CA48634A935 5 00000090B9750D99297911A0496B5134 6

我有一个为MD5SUMMS分配数字的文件,如下所示:

0   0000001732816557DE23435780915F75
1   00000035552C6F8B9E7D70F1E4E8D500
2   00000051D63FACEF571C09D98659DC55
3   0000006D7695939200D57D3FBC30D46C
4   0000006E501F5CBD4DB56CA48634A935
5   00000090B9750D99297911A0496B5134
6   000000B5AEA2C9EA7CC155F6EBCEF97F
7   00000100AD8A7F039E8F48425D9CB389
8   0000011ADE49679AEC057E07A53208C1
00000035552C6F8B9E7D70F1E4E8D500    276EC96E149571F8A27F4417D7C6BC20    9CFEFED8FB9497BAA5CD519D7D2BB5D7
00000035552C6F8B9E7D70F1E4E8D500    44E48C092AADA3B171CE899FFC6943A8    1B757742E1BF2AA5DB6890E5E338F857
另一个文件每行包含三个MD5和,如下所示:

0   0000001732816557DE23435780915F75
1   00000035552C6F8B9E7D70F1E4E8D500
2   00000051D63FACEF571C09D98659DC55
3   0000006D7695939200D57D3FBC30D46C
4   0000006E501F5CBD4DB56CA48634A935
5   00000090B9750D99297911A0496B5134
6   000000B5AEA2C9EA7CC155F6EBCEF97F
7   00000100AD8A7F039E8F48425D9CB389
8   0000011ADE49679AEC057E07A53208C1
00000035552C6F8B9E7D70F1E4E8D500    276EC96E149571F8A27F4417D7C6BC20    9CFEFED8FB9497BAA5CD519D7D2BB5D7
00000035552C6F8B9E7D70F1E4E8D500    44E48C092AADA3B171CE899FFC6943A8    1B757742E1BF2AA5DB6890E5E338F857
我想用第一个文件的整数替换第二个文件中的第一个和第三个MD5和。目前我正在尝试以下awk脚本:

awk '{OFS="\t"}FNR==NR{map[$2]=$1;next}
{print map[$1],$2,map[$3]}' mapping.txt relation.txt

问题是,尽管第一个文件在硬盘上只有5.7g,但脚本需要更多的16g ram。

如果没有足够的内存来存储第一个文件,则需要编写类似这样的内容来查找第二个文件中每个值的第一个文件:

awk 'BEGIN{OFS="\t"}
{
    val1 = val3 = ""
    while ( (getline line < "mapping.txt") > 0 ) {
        split(line,flds)
        if (flds[2] == $1) {
            val1 = flds[1]
        }
        if (flds[2] == $3) {
            val3 = flds[1]
        }
        if ( (val1 != "") && (val3 != "") ) {
            break
        }
    }
    close("mapping.txt")

    print val1,$2,val3

}' relation.txt
awk'BEGIN{OFS=“\t”}
{
val1=val3=“”
而((getline<“mapping.txt”)>0){
拆分(直线,FLD)
如果(flds[2]==1美元){
val1=flds[1]
}
如果(flds[2]==3美元){
val3=flds[1]
}
如果((val1!=“”)和&(val3!=“”){
打破
}
}
关闭(“mapping.txt”)
打印val1,$2,val3
}'relation.txt

这将是缓慢的。如果愿意,您可以添加N个getline-d行的缓存以加快速度。

这个问题可以解决,如下所示(
file1.txt
是包含整数和md5sums的文件,
file2.txt
是包含三列md5sums的文件):

对于
file1.txt
file2.txt
都有100万行长的情况,此解决方案和Ed Morton的
awk
唯一解决方案在我的系统上花费的时间大致相同。我的系统需要很长时间才能解决1.4亿行的问题,不管使用什么方法,但我为1000万行的文件运行了一个测试用例

我曾假设,依赖于
排序的解决方案(在需要时自动使用临时文件)对于大量行应该更快,因为它将是O(N log N)运行时,而如果两个文件大小相似,则为输入的每行重新读取映射文件的解决方案将是O(N^2)

计时结果

对于我尝试过的测试用例,我关于两个候选解决方案的性能关系的假设被证明是错误的。在我的系统上,基于
sort
的解决方案和仅
awk
的解决方案在100万行和1000万行输入文件中的时间相似(在30%以内),仅
awk
的解决方案在每种情况下都更快。当然,当输入文件大小增加10倍以上时,我不知道这种关系是否成立


奇怪的是,1000万行问题在两种解决方案下运行的时间大约是100万行问题的10倍,这让我感到困惑,因为我本以为两种解决方案的文件长度都是非线性的

如果文件大小导致awk内存不足,请使用其他工具或完全使用其他方法

sed命令可能会成功,但占用的内存要少得多。其思想是读取索引文件并创建执行重新映射的sed脚本,然后在生成的sed脚本上调用sed

下面的bash脚本就是这个想法的实现。它包括一些STDERR输出,以帮助跟踪进度。我喜欢为大数据集或其他耗时处理的问题生成进度跟踪输出

该脚本已经在一小部分数据上进行了测试;它可能对您的数据起作用。请试一试

#!/bin/bash

# md5-indexes.txt
# 0   0000001732816557DE23435780915F75
# 1   00000035552C6F8B9E7D70F1E4E8D500
# 2   00000051D63FACEF571C09D98659DC55
# 3   0000006D7695939200D57D3FBC30D46C
# 4   0000006E501F5CBD4DB56CA48634A935
# 5   00000090B9750D99297911A0496B5134
# 6   000000B5AEA2C9EA7CC155F6EBCEF97F
# 7   00000100AD8A7F039E8F48425D9CB389
# 8   0000011ADE49679AEC057E07A53208C1

# md5-data.txt
# 00000035552C6F8B9E7D70F1E4E8D500    276EC96E149571F8A27F4417D7C6BC20    9CFEFED8FB9497BAA5CD519D7D2BB5D7
# 00000035552C6F8B9E7D70F1E4E8D500    44E48C092AADA3B171CE899FFC6943A8    1B757742E1BF2AA5DB6890E5E338F857

# Goal replace field 1 and field 3 with indexes to md5 checksums from md5-indexes

md5_indexes='md5-indexes.txt'
md5_data='md5-data.txt'

talk()  { echo 1>&2 "$*" ; }
talkf() { printf 1>&2 "$@" ; }
track() {
  local var="$1" interval="$2"
  local val
  eval "val=\$$var"
  if (( interval == 0 || val % interval == 0 )); then
    shift 2
    talkf "$@"
  fi
  eval "(( $var++ ))"   # increment the counter
}

# Build a sedscript to translate all occurances of the 1st & 3rd MD5 sums into their
# corresponding indexes

talk "Building the sedscript from the md5 indexes.."

sedscript=/tmp/$$.sed

linenum=0
lines=`wc -l <$md5_indexes`
interval=$(( lines / 100 ))

while read index md5sum ; do
  track linenum $interval "..$linenum"
  echo "s/^[[:space:]]*[[:<:]]$md5sum[[:>:]]/$index/" >>$sedscript
  echo "s/[[:<:]]$md5sum[[:>:]]\$/$index/"            >>$sedscript
done <$md5_indexes
talk ''

sedlength=`wc -l <$sedscript`

talkf "The sedscript is %d lines\n" $sedlength

cmd="sed -E -f $sedscript -i .bak $md5_data"
talk "Invoking: $cmd"

$cmd

changes=`diff -U 0 $md5_data.bak $md5_data | tail +3 | grep -c '^+'`

talkf "%d lines changed in $md5_data\n" $changes

exit
以下是运行示例:

$ ./md5-reindex.sh
Building the sedscript from the md5 indexes..
..0..1..2..3..4..5..6..7..8
The sedscript is 18 lines
Invoking: sed -E -f /tmp/83800.sed -i .bak md5-data.txt
2 lines changed in md5-data.txt
最后,生成的文件:

$ cat md5-data.txt
1    276EC96E149571F8A27F4417D7C6BC20    9CFEFED8FB9497BAA5CD519D7D2BB5D7
1    44E48C092AADA3B171CE899FFC6943A8    1B757742E1BF2AA5DB6890E5E338F857

在您的脚本中,除了将文件拆分并分块执行之外,没有其他方法可以减少该数量。如果这是它需要的,那就是它需要的。很抱歉顺便说一句,无关-将
{OFS=“\t”}
更改为
开始{OFS=“\t”}
您不会说第二个文件有多大。如果它的行数与file1相同,那么我看不到16G RAM问题的解决方案。祝你好运。为什么第二个文件的大小很重要?脚本只会逐行打印替换内容。您超出16GB限制(估计)的程度是多少?如果只是少量,那么以更密集的格式存储md5sums或使用子字符串可能是值得的……从行长度来看,这应该相当于大约1.4亿条记录,意味着2.8亿条短字符串——其中一半长32字节,一半甚至更短。在64位系统(必须如此)上,字符串数据的指针仅为2GB,而这不是唯一的元数据。如果你想一次完成,我认为你不能用脚本语言来完成。在母语中,应该可以将其降低到(估计)6-7GB。你会接受使用公共库的C++解决方案吗?我觉得这太慢了。第二个文件包含大约4亿条记录,这意味着第一个文件将被读取4亿次。这会花很多时间。我目前已经通过创建一个mysql数据库并使用select into outfile解决了这个问题,但我觉得对于这种问题还有更多的轻量级解决方案,它很慢,如果太慢,您可以始终缓存数组中的最后N行,并且仅在所需值不存在时执行getline。谢谢,join程序正是我要找的。顺便说一句,第一个文件已按哈希排序,第三个文件已按第一行排序。所以我所要做的就是:
join-t$'\t'-12-21-o1.1,2.2,2.3-mapping.txt relation.txt | sort--parallel=4-S4g-k3>relation_step1.txt
和:
join-t$'\t'-12-23-o2.1,2.2,1.1-mapping.txt relation_step1.txt>relation_result.txt这一解决方案看起来很复杂,但无论如何我都会接受。