Bash 用GREP对数据进行子集划分
我有一个非常大的文本文件(16GB),我想尽快将其子集。 这是一个涉及的数据样本Bash 用GREP对数据进行子集划分,bash,awk,grep,subset,Bash,Awk,Grep,Subset,我有一个非常大的文本文件(16GB),我想尽快将其子集。 这是一个涉及的数据样本 0 M 4 0 0 0 Q 0 10047345 3080290,4098689 50504886,4217515 9848058,1084315 50534229,4217515 50591618,4217515 26242582,2597528 34623075,3279130 68893581,5149883 50628761,421
0 M 4 0
0 0 Q 0 10047345 3080290,4098689 50504886,4217515 9848058,1084315 50534229,4217515 50591618,4217515 26242582,2597528 34623075,3279130 68893581,5149883 50628761,4217517 32262001,3142702 35443881,3339757
0 108 C 0 50628761
0 1080 C 0 50628761
1 M 7 0
1 0 Q 0 17143989
2 M 15 1
2 0 Q 0 17143989 4219157,1841361,853923,1720163,1912374,1755325,4454730 65548702,4975721 197782,39086 54375043,4396765 31589696,3091097 6876504,851594 3374640,455375 13274885,1354902 31585771,3091016 61234218,4723345 31583582,3091014
2 27 C 0 31589696
每行的第一个数字是sessionID,任何带有“M”的行都表示会话的开始(数据按会话分组)。M后面的数字是一天,第二个数字是用户ID,用户可以有多个会话
我想提取与特定用户相关的所有行,对于每个会话,这些行包括所有行,直到遇到下一个“M”行(可以是任意数量的行)。作为第二项任务,我还想提取与特定日期相关的所有会话行
例如,对于上述数据,要提取用户ID“0”的记录,输出将是:
0 M 4 0
0 0 Q 0 10047345 3080290,4098689 50504886,4217515 9848058,1084315 50534229,4217515 50591618,4217515 26242582,2597528 34623075,3279130 68893581,5149883 50628761,4217517 32262001,3142702 35443881,3339757
0 108 C 0 50628761
0 1080 C 0 50628761
1 M 7 0
1 0 Q 0 17143989
要提取第7天的记录,输出为:
1 M 7 0
1 0 Q 0 17143989
我相信,对于我迄今为止所取得的成就,有一个更优雅、更简单的解决方案,如果能得到一些反馈和建议,那就太好了。多谢各位
我试过的
我尝试使用pcrgrep-M直接应用此模式(在两个M之间匹配数据),但很难在换行符之间实现此功能。我仍然怀疑这可能是最快的选择,所以任何关于这是否可能的指导都是非常好的
下一部分内容非常分散,如果您已经有了更好的解决方案,则无需继续阅读
如果上述操作失败,我将问题分为两部分:
- 第1部分:隔离所有“M”行以获得属于该用户/天的会话列表
- grep方法很快(然后需要弄清楚如何使用这些数据)
time grep-c“M\t.*\t$user\u id”trainSample.txt>>sessions.txt
- 创建数组的awk方法很慢
time myarr=$(awk'/M\t.*\t$user\u id/{print$1}'trainSample.txt
- 第2部分:在第1部分创建的列表中提取属于会话的所有行
- 继续使用awk方法,我对每个都运行了grep,但这太慢了(需要几天才能完成16GB)
- 与上面的每个会话ID运行一次grep相比,在一个grep命令中使用所有会话ID要快得多(我使用8个sessionid以[1 | 2 | 3 | | | 8]格式运行它,并且每个会话ID单独运行的时间相同,即快8倍)。然而,我需要弄清楚如何动态地执行此操作
似乎您正在处理某种平面文件,我认为bash不是适合此工作的工具。我会尝试将您的数据加载到数据库中,然后根据您的意愿查询您的数据。为了使问题更完美,请添加您的给定数据的预期输出input@dood其最终目标是将数据文件子集为a然后只将相关数据加载到数据库中。由于数据库太大,将所有内容加载到数据库中的时间太长。你可能是对的,bash不是正确的工具,尽管我被grep相对于其他方法的速度所吸引(我也用python脚本试过)@fedorqui我现在编辑了这个问题,希望这更清楚。可以“Day”吗重复一遍?我的意思是,你能不能有第7天的条目,然后是第15天的条目,然后是第7天的其他条目?这是一个很好的解决方案,谢谢!在1/41的数据块上运行这些条目需要20秒,假设它以大约14分钟的时间线性扩展,我认为这是相当合理的。如果有人有任何速度提升howev呃,我很高兴听到他们的声音。有趣的解决方案,干得好!也许你可以用一个名称来代替
p
,使其观点更相关:switch
,flag
或类似的东西。另外,awk-v id=0'$2=“M”{flag=$4=id}标志'file
将允许将id作为变量提供。@user2071737,类似的perl
解决方案将是perl-ae'$p=$F[3]==0如果$F[1]eq“M”;如果$p'file
和perl-ae'$p=$F[2]==7如果$F[1]eq“M”;分别打印if$p'文件
。。你能检查一下它的运行情况吗?如果几天不能重复,那么为了提高效率,当p
在第二个脚本中从true变为false时,你可以退出。@Sundeep这就是问题所在。好吧,我运行了几次,第一部分的平均速度约为25秒,第二部分的平均速度约为32秒,因此速度较慢而不是awk替代方案
for i in "${!myarr[@]}";
do
grep "^${myarr[$i]}\t" trainSample.txt >> sessions.txt
echo -ne "Session $i\r"
done
$ awk '$2=="M"{p=$4==0}p' file
0 M 4 0
0 0 Q 0 10047345 3080290,4098689 50504886,4217515 9848058,1084315 50534229,4217515 50591618,4217515 26242582,2597528 34623075,3279130 68893581,5149883 50628761,4217517 32262001,3142702 35443881,3339757
0 108 C 0 50628761
0 1080 C 0 50628761
1 M 7 0
1 0 Q 0 17143989
$ awk '$2=="M"{p=$3==7}p' file
1 M 7 0
1 0 Q 0 17143989