0

2 つの CSV ファイルがあるとします。最初の形式は次のとおりです。

id(unique int),owner_id(non-unique int),string

5,000 万から 1 億行が含まれています。数GB。

2番目の形式は次のとおりです。

integer,integer

2 番目のファイルには、10 億行のようなものが含まれています。ファイル 2 のすべての行を取得したいのですが、最初と 2 番目の列の両方の値が最初のファイルの 2 番目の列 (owner_id) のどこかに存在します。

最も効率的な方法は、メモリ内の owner_id の一意の値を取得し、2 番目のファイルから各ペアを順番にバイナリ検索することです。このようなことが BASH で実行できるかどうかはわかりませんが、Python で実行できます (2 つのファイルに単純なスクリプトを指定すると、読み取り、ロードされ、すべての有効なペアを含む 2 番目のファイルが吐き出されます)。

ただし、可能であれば、python の依存関係を追加したくありません。

4

4 に答える 4

1

これは、メモリの制約により失敗する可能性があります。3 つの列を持つファイル file1 と ID を持つ file2 というファイルを呼び出しました。コード セグメントをコピーしてファイルに貼り付け、必要に応じて名前を編集します。

ステップ 1: ファイル 1 をできるだけ小さくします。

#/bin/bash
declare -a Array
Count=0

最初の 3 番目の列は不要なので、それらを削除し、ファイルを並べ替えてから、一意のエントリのみを取得します。

InitFile ()
{
while IFS=, read ignore1 stuff ignore2; do  echo $stuff ; done < file1| sort -n | uniq >  $1
}

配列に読み込む:

InitArray ()
{
   while  read  Array[$Count]; do
     let Count++
   done < $1
}

配列内の値のバイナリ検索:

BinarySearch ()
{
   val=$1
   let idx=$Count/2
   top=$Count
   bottom=0
   while true; do
      if [ ${Array[$idx]} -eq $val ]; then return 0; fi
      lastIdx=$idx
      if [ $top  -le $bottom ]; then return 1; fi
      if [ $val -lt ${Array[$idx]} ]; then top=$idx && let idx=$idx/2;
      elif [ $val -gt ${Array[$idx]} ]; then bottom=$idx && let idx=($top+$bottom)/2; fi
      if [ $idx -eq $lastIdx ]; then let bottom=$bottom+1 ; fi
   done

}

uniqueOwnerIdFile は最初のファイルから作成され、配列に入れられます

InitFile uniqueOwnerIdFile
InitArray uniqueOwnerIdFile

2 番目のファイルの各行をループし、所有者 ID 配列で両方の値を探します。見つかったすべてを linesTheExistFile にエコーします。

while IFS=, read firstVal secondVal; do
   if BinarySearch $firstVal && BinarySearch $secondVal ; then echo "$firstVal,$secondVal" ; fi
done < file2 > linesThatExistFile
于 2013-08-19T23:59:47.223 に答える
0

bashでは、このようなものがうまくいくかもしれません。

#!/bin/bash

list=$(cut -f2 -d, file1.txt | sort -u)

while IFS=, read a b; do
  [[ $list =~ $a && $list =~ $b ]] && echo "$a,$b"
done <file2.txt >result.txt

とはいえ、性能についてはよくわかりません。

于 2013-08-19T15:51:49.520 に答える
0

パールソリューション。ファイル 1 のすべての所有者をハッシュで記憶し、ファイル 2 を調べて、両方の所有者がハッシュに存在する行を出力します。

#!/usr/bin/perl
use warnings;
use strict;

open my $F1, '<', 'file1' or die $!;
my %owner;
while (<$F1>) {
    $owner{(split /,/ => $_, 3)[1]} = 1;
}

open my $F2, '<', 'file2' or die $!;
while (my $line = <$F2>) {
    chomp $line;
    print "$line\n" if 2 == grep exists $owner{$_}, split /,/ => $line, 2;
}

Bash パイプライン。同じ出力が得られますが、大幅に遅くなります。

cut -d, -f2 file1 \
    | grep -vwFf- <(sed 's/,/\n/' file2) \
    | grep -vwFf- file2
于 2013-08-19T15:52:03.740 に答える
0

純粋なbashでの解決策についてはわかりませんが、次を使用して提供できますawk

awk -F"," 'NR==FNR{col3[$2]++;next;}{ if ($1 in col3 && $2 in col3) print $0} ' File1 File2

まず、最初のファイルの 2 列目を連想配列に読み取り、次に 2 番目のファイルの各行を、それらが配列内にあるかどうかに関係なく探します。

于 2013-08-19T15:36:25.937 に答える