34

我有 2 个文件。第一个文件包含数据库中表的元组的行 ID 列表。第二个文件在查询的“where”子句中包含具有这些行 ID 的 SQL 查询。

例如:

文件 1

1610657303
1610658464
1610659169
1610668135
1610668350
1610670407
1610671066

文件 2

update TABLE_X set ATTRIBUTE_A=87 where ri=1610668350;
update TABLE_X set ATTRIBUTE_A=87 where ri=1610672154;
update TABLE_X set ATTRIBUTE_A=87 where ri=1610668135;
update TABLE_X set ATTRIBUTE_A=87 where ri=1610672153;

我必须阅读文件 1 并在文件 2 中搜索与文件 1 中的行 ID 匹配的所有 SQL 命令,并将这些 SQL 查询转储到第三个文件中。

文件 1 有 1,00,000 个条目,文件 2 包含文件 1 的 10 倍,即 1,00,0000。

我用过grep -f File_1 File_2 > File_3。但这非常慢,而且速度是每小时 1000 个条目。

有没有更快的方法来做到这一点?

4

8 回答 8

54

你不需要正则表达式,所以grep -F -f file1 file2

于 2013-06-21T11:53:48.793 回答
18

一种方法awk

awk -v FS="[ =]" 'NR==FNR{rows[$1]++;next}(substr($NF,1,length($NF)-1) in rows)' File1 File2

这应该很快。在我的机器上,创建 100 万个条目的查找并将其与 300 万行进行比较只需不到 2 秒的时间。

机器规格:

Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz (8 cores)
98 GB RAM
于 2013-06-21T13:10:11.493 回答
1

我建议使用 Perl、Ruby 或 Python 等编程语言。

在 Ruby 中,读取两个文件 (f1f2) 一次的解决方案可能是:

idxes = File.readlines('f1').map(&:chomp)

File.foreach('f2') do | line |
  next unless line =~ /where ri=(\d+);$/
  puts line if idxes.include? $1
end

或使用 Perl

open $file, '<', 'f1';
while (<$file>) { chomp; $idxs{$_} = 1; }
close($file);

open $file, '<', 'f2';
while (<$file>) {
    next unless $_ =~ /where ri=(\d+);$/;
    print $_ if $idxs{$1};
}
close $file;
于 2013-06-21T12:08:17.763 回答
0

上面提到的 awk/grep 解决方案在我的机器上运行缓慢或内存不足(file1 10^6 行,file2 10^7 行)。所以我想出了一个使用 sqlite3 的 SQL 解决方案。

将 file2 转换为 CSV 格式的文件,其中第一个字段是后面的值ri=

cat file2.txt  | gawk -F= '{ print $3","$0 }' | sed 's/;,/,/' > file2_with_ids.txt

创建两个表:

sqlite> CREATE TABLE file1(rowId char(10));
sqlite> CREATE TABLE file2(rowId char(10), statement varchar(200));

从 file1 导入行 ID:

sqlite> .import file1.txt file1

使用“准备好的”版本从 file2 导入语句:

sqlite> .separator ,
sqlite> .import file2_with_ids.txt file2

file2选择 table中具有匹配 rowId 的所有语句file1

sqlite> SELECT statement FROM file2 WHERE file2.rowId IN (SELECT file1.rowId FROM file1);

可以通过在发出 select 语句之前将输出重定向到文件来轻松创建文件 3:

sqlite> .output file3.txt

测试数据:

sqlite> select count(*) from file1;
1000000
sqlite> select count(*) from file2;
10000000
sqlite> select * from file1 limit 4;
1610666927
1610661782
1610659837
1610664855
sqlite> select * from file2 limit 4;
1610665680|update TABLE_X set ATTRIBUTE_A=87 where ri=1610665680;
1610661907|update TABLE_X set ATTRIBUTE_A=87 where ri=1610661907;
1610659801|update TABLE_X set ATTRIBUTE_A=87 where ri=1610659801;
1610670610|update TABLE_X set ATTRIBUTE_A=87 where ri=1610670610;

在没有创建任何索引的情况下,选择语句在 AMD A8 1.8HGz 64 位 Ubuntu 12.04 机器上花费了大约 15 秒。

于 2013-06-21T13:33:31.907 回答
0

以前的大多数答案都是正确的,但唯一对我有用的是这个命令

grep -oi -f a.txt b.txt

在此处输入图像描述

于 2018-08-16T17:22:58.853 回答
-1

## 报告 <file 1> 中包含的所有行在 <file 2> 中丢失

IFS=$(echo -en "\n\b") && for a in $(cat < file 1>); 
do ((\!$(grep -F -c -- "$a" < file 2>))) && echo $a; 
done && unset IFS

或做提问者想要的,取消否定并重定向

(IFS=$(echo -en "\n\b") && for a in $(cat < file 1>); 
do (($(grep -F -c -- "$a" < file 2>))) && echo $a; 
done && unset IFS) >> < file 3> 
于 2014-08-12T14:07:24.307 回答
-1

也许尝试 AWK 并使用文件 1 中的数字作为键,例如简单脚本

第一个脚本将生成 awk 脚本:
awk -f script1.awk

{
   print "\$0 ~ ",$0,"{ print \$0 }" > script2.awk;
 }

然后用文件调用 script2.awk

于 2013-06-21T11:35:16.603 回答
-1

file1我可能遗漏了一些东西,但是仅仅在每个 ID 中迭代 ID、grepfile2并将匹配项存储在第三个文件中还不够吗?IE

 for ID in `cat file1`; do grep $ID file2; done > file3

这不是非常有效(因为 file2 将被一遍又一遍地读取),但它可能对您来说已经足够了。如果您想要更快的速度,我建议使用更强大的脚本语言,它可以让您读file2入地图,从而快速识别给定 ID 的行。

这是这个想法的 Python 版本:

queryByID = {}

for line in file('file2'):
  lastEquals = line.rfind('=')
  semicolon = line.find(';', lastEquals)
  id = line[lastEquals + 1:semicolon]
  queryByID[id] = line.rstrip()

for line in file('file1'):
  id = line.rstrip()
  if id in queryByID:
    print queryByID[id]
于 2013-06-21T11:43:32.680 回答