【问题标题】:filtering data in a flat file with millions of records过滤包含数百万条记录的平面文件中的数据
【发布时间】:2015-05-17 01:36:00
【问题描述】:

我有一个压缩文件tradedata.txt.gz,其中包含数百万条记录。该文件有大约 50 个字段,由 | 分隔。第45个字段可以包含0000000200030004和空值(null)等值。我想过滤文件并仅获取值为 0000,0002 和空白值的那些行。我想使用awkperl 或任何其他语言以最快的方式完成此操作。

例如,数据看起来像这样(我只显示几个字段以进行说明)。

abc|234|test|0000|test2|1
abc|2343|test1|0002|test2|1
abc|2345|test3|0004|test2|1
abc|2346|test4|0004|test2|1
abc|2347|test5|0003|test2|1
abc|2348|test6||test2|1
abc|234|test|0003|test2|1

过滤数据后的结果应该是:

abc|234|test|0000|test2|1
abc|2343|test1|0002|test2|1
abc|2348|test6||test2|1

如您所见,我只提取值为 0000,0002 且为空白的记录。 有人可以使用 awk、perl 或任何其他最快的语言来帮助解决这个请求吗?

【问题讨论】:

  • 你有没有尝试过?
  • 我是一名预言机开发人员。我尝试使用 oracle,但 oracle 加载工具功能不足以拥有复杂的过滤器。我的一个朋友告诉我,这可以在 unix 中使用 awk、perl 等来完成,但我不知道这些语言。
  • 那我怕你问错地方了。 Stack Overflow 旨在帮助您 - 作为一名程序员 - 找出问题并解决它们。这不是为你编写代码。

标签: perl awk filtering


【解决方案1】:

使用awk

$ awk -F'|' '$4=="0000"||$4=="0002"||$4==""' file
abc|234|test|0000|test2|1
abc|2343|test1|0002|test2|1
abc|2348|test6||test2|1

$4 更改为$45 作为您的实际输入文件。

使用perl

$ perl -F'\|' -lane 'print if grep $F[3] eq $_, ("0002", "0000", "")' file
abc|234|test|0000|test2|1
abc|2343|test1|0002|test2|1
abc|2348|test6||test2|1

$F[3] 更改为$F[44] 作为您的实际输入文件。

更新:

正如下面评论中提到的hobbs,如果现有解决方案不够快,您可以尝试以下方法:

perl -F'\|' -lane 'print if $F[3] =~ /\A(?:0002|0000|)\z/' file

【讨论】:

  • print if $F[3] =~ /\A(?:0002|0000|)\z/ 可能比您的 grep 更快,可能足以处理 4500 万条记录。
  • 感谢@hobbs 提供替代解决方案。我不确定正则表达式是否会更快。但我会在答案中包含您的评论。欣赏它。
  • 我对它进行了基准测试,它更快。正则表达式引擎的开销被grep 必须在每一行上调用eq 三次,并进行更多的堆栈操作——检查正则表达式是每行单个操作的事实所抵消:)
  • @hobbs 啊,这是有道理的。再次感谢! :)
【解决方案2】:

一站式测试

awk -F'|' '$4~/^(000(0|2)|)$/' file
abc|234|test|0000|test2|1
abc|2343|test1|0002|test2|1
abc|2348|test6||test2|1

【讨论】:

  • @EdMorton 在一个随机生成的大型文件中,awk -F'|' '$1~/(000[02])/' 提供了37.3sawk -F'|' '$1~/(000(0|2))/' 提供了35.8s。所以差别不大,但同意[02] 更具可读性。
猜你喜欢
  • 2015-05-13
  • 2010-11-27
  • 1970-01-01
  • 1970-01-01
  • 2010-09-11
  • 1970-01-01
  • 2015-12-14
  • 1970-01-01
  • 2010-09-13
相关资源
最近更新 更多