5

私たちのプロジェクトでは、csv ファイルを postgres にインポートする必要があります。複数の種類のファイルがあり、列数が少ないファイルもあれば、列がすべて含まれているファイルもあるため、ファイルの長さが変わります。

このファイルを postgres にすばやくインポートする方法が必要です。処理の速度要件が非常に高いため、postgres の COPY FROM を使用したいと考えています (それぞれ 20K ファイル サイズで毎分約 150 ファイル)。

ファイルの列番号は固定されていないため、postgres プロシージャに渡す前にファイルを前処理する必要があります。前処理は、ファイルにない列の csv にカンマを追加するだけです。

ファイルを前処理するには、python を使用するか、Sed を使用するかの 2 つのオプションがあります。

私の最初の質問は、ファイルを前処理する最速の方法は何ですか?

2番目の質問は、sedを使用する場合、4番目、5番目のコンマフィールドの後にどのようにコンマを挿入しますか?
たとえば、ファイルに 1,23,56,we,89,2009-12-06 のようなエントリがあり、次のような最終出力でファイルを編集する必要がある場合: 1,23,56,we,,89,,2009-12-06

4

6 に答える 6

3

COPY FROMインポートする列 (および列の順序) を指定できることをご存知ですか?

COPY tablename ( column1, column2, ... ) FROM ...

Postgres レベルで、どの列をどの順序でインポートするかを直接指定するのが、通常、最も高速で効率的なインポート方法です。

sedそうは言っても、 (他の投稿で提示されたものよりも)はるかに簡単な(そして移植可能な)使用方法がありn番目のオカレンスを置き換えます。たとえば、コンマの 4 番目と 5 番目のオカレンスを二重のコンマに置き換えます。

echo '1,23,56,we,89,2009-12-06' | sed -e 's/,/,,/5;s/,/,,/4'

生成:

1,23,56,we,,89,,2009-12-06

一番右のフィールド (#5) を最初に置き換えたことに注意してください。

質問の本文でperl明示的に言及していませんが、質問に関連するタグも付けていることがわかります。perlこれは、フィールドの並べ替えやその他の処理の柔軟性を提供する実装の 1 つです。

echo '1,23,56,we,89,2009-12-06' |
  perl -F/,/ -nae 'print "$F[0],$F[1],$F[2],$F[3],,$F[4],,$F[5]"'

次のものも生成します。

1,23,56,we,,89,,2009-12-06

awk記録のために、と非常によく似ています。

echo '1,23,56,we,89,2009-12-06' |
  awk -F, '{print $1","$2","$3","$4",,"$5",,"$6}'

Python は他の人に任せます。:)

Perl の例に関する小さな注意:自動分割に-aand-Fオプションを使用しているため、コマンド文字列が短くなります。ただし、これにより、最後のフィールド ( ) に改行が埋め込まれたままになります。これは、$F[5]そのフィールドを別の場所で並べ替える必要がない限り問題ありません。chompそのような状況が発生した場合、 を介して改行をザッピングし、次にsplit手動で、最後に独自の改行文字を出力するために、もう少し入力する必要があります\n(awk上記の例ではこの問題はありません)。

perl -ne 'chomp;@F=split/,/;print "$F[0],$F[1],$F[2],$F[3],,$F[4],,$F[5]\n"'

編集(Vivinに触発されたアイデア):

COMMAS_TO_DOUBLE="1 4 5"
echo '1,23,56,we,89,2009-12-06' |
  sed -e `for f in $COMMAS_TO_DOUBLE ; do echo "s/,/,,/$f" ; done |
    sort -t/ -k4,4nr | paste -s -d ';'`

1,,23,56,we,,89,,2009-12-06

申し訳ありませんが、それに抵抗できませんでした。:)

于 2010-03-02T23:03:10.590 に答える
2

@OP、個別のフィールドと区切り文字を持つ csv ファイルを処理しています。区切り記号で分割できるツールを使用して、フィールドを簡単に操作できるようにします。いくつかの回答が示唆しているように、sedはそれらの1つではありませんが、実行できますが、複雑になると読みにくいsed正規表現が得られます。awk/Python/Perl などのツールを使用すると、フィールドや区切り記号を簡単に操作できます。特に、csv の処理に特化したモジュールを利用できます。あなたの例では、単純なPythonアプローチ(理想的にはcsvモジュールを使用しないでください)

for line in open("file"):
    line=line.rstrip() #strip new lines
    sline=line.split(",")
    if len(sline) < 8: # you want exact 8 fields
        sline.insert(4,"")
        sline.insert(6,"")
        line=','.join(sline)
    print line

出力

$ more file
1,23,56,we,89,2009-12-06

$ ./python.py
1,23,56,we,,89,,2009-12-06
于 2010-03-02T23:56:21.263 に答える
2

最初の質問に答えると、sedオーバーヘッドは少なくなりますが、苦痛になる可能性があります。awk少し良くなります(より強力です)。Perl や Python のほうがオーバーヘッドは大きくなりますが、操作はより簡単になります (Perl に関しては、それは少し主観的なことかもしれません ;)。個人的には、Perl を使用します)。

2 番目の質問に関しては、問題はもう少し複雑かもしれません。たとえば、文字列を調べて、実際に欠落しているフィールドを特定する必要はありませんか? それとも、常に4番目と5番目になることが保証されていますか?これが最初のケースである場合は、Python や Perl でこれを行うよりも、sed. さもないと:

echo "1,23,56,we,89,2009-12-06" | sed -e 's/\([^,]\+\),\([^,]\+\),\([^,]\+\),\([^,]\+\),\([^,]\+\),/\1,\2,\3,\4,,\5,,/'

または(目にやさしい):

echo "1,23,56,we,89,2009-12-06" | sed -e 's/\(\([^,]\+,\)\{3\}\)\([^,]\+\),\([^,]\+\),/\1,\3,,\4,,/'

これにより、テキストに他のコンマがないと仮定して、5 番目と 4 番目の列の後にコンマが追加されます。

または、2 つsedの s を使用して、もう少し見栄えの悪いものにすることもできます (ただし、わずかですが)。

echo "1,23,56,we,89,2009-12-06" | sed -e 's/\(\([^,]*,\)\{4\}\)/\1,/' | sed -e 's/\(\([^,]*,\)\{6\}\)/\1,/'
于 2010-03-02T22:30:45.527 に答える
0
sed 's/^([^,]*,){4}/&,/' <original.csv >output.csv

4 番目のコンマ区切りフィールドの後にコンマを追加します (の 4 回の繰り返しに一致し<anything>,、その後にコンマを追加します)。キャッチがあることに注意してください。これらの値のいずれも、カンマを含む引用符で囲まれた文字列ではないことを確認してください。

必要に応じてパイプを介して複数の置換を連鎖させるか、正規表現を変更して必要なコンマを同時に追加することができます (ただし、これはより複雑になります。置換テキストでサブグループ キャプチャを使用する必要があります)。

于 2010-03-02T22:34:57.600 に答える
0

速度についてはわかりませんが、仕事をするべき sed expr は次のとおりです。

sed -i 's/\(\([^,]*,\)\{4\}\)/\1,/' file_name

4を必要な列数に置き換えるだけです

于 2010-03-02T22:35:52.410 に答える
0

要件に応じて、このタスクと将来のタスクにETLソフトウェアを使用することを検討してください。PentahoTalendなどのツールは柔軟性に優れており、コードを 1 行も書く必要はありません。

于 2010-03-02T22:37:36.180 に答える