Saya memiliki file yang bertambah sekitar 200.000 baris sehari, dan semuanya terbentuk dengan blok tiga baris seperti itu:
1358726575123 # key
Joseph Muller # name
carpenter # job
9973834728345
Andres Smith
student
7836472098652
Mariah Anthony
dentist
Sekarang, saya memiliki file lain dari mana saya mengekstrak sekitar 10.000 pola kunci, seperti 1358726575123
. Kemudian saya menjalankan for
loop dengan pola-pola ini dan harus memeriksanya terhadap file pertama. Jika file tidak mengandung pola seperti itu, saya menyimpan pola di file ketiga untuk diproses lebih lanjut:
for number in $(grep -o '[0-9]\{12\}' file2); do # finds about 10.000 keys
if ! grep -q ^$number$ file1; then # file1 is a huge file
printf "$number\n" >>file3 # we'll process file3 later
fi
done
Kode contoh menangkap sebuah file besar 10.000 kali, dan saya menjalankan loop ini sekitar satu menit sekali, sepanjang hari .
Karena file besar terus bertambah, apa yang bisa saya lakukan untuk membuat semua ini lebih cepat dan menghemat CPU? Saya ingin tahu apakah menyortir file dengan kuncinya (jika demikian, bagaimana?) Atau menggunakan db sebagai ganti teks biasa akan membantu ...
Jawaban:
Jawaban ini didasarkan pada
awk
jawaban yang diposting oleh potong ..Ini dua kali lebih cepat dari
comm
metode (pada sistem saya), untuk 6 juta baris yang sama dalam file-utama dan 10 ribu kunci ... (sekarang diperbarui untuk menggunakan FNR, NR)Meskipun
awk
lebih cepat dari sistem Anda saat ini, dan akan memberi Anda dan komputer Anda ruang bernapas, ketahuilah bahwa ketika pemrosesan data sekuat yang Anda jelaskan, Anda akan mendapatkan hasil keseluruhan terbaik dengan beralih ke basis data khusus; misalnya. SQlite, MySQL ...sumber
file1 -> mainfile
danfile2 -> keys
dengan gawk dan mawk, dan menghasilkan kunci yang salah.awk
memungkinkan Anda untuk membaca dalam serangkaian file .. dalam hal ini yang seri memiliki 3 file di dalamnya Output pergi ke.stdout
mainfile
, DAN itu juga akan mencetak kunci apa pun darikeys
file yang TIDAK ada dimainfile
... Itu mungkin yang terjadi ... (Saya akan melihat sedikit lebih jauh ke dalamnya ...$RANDOM
untuk diunggah.Masalahnya, tentu saja, adalah Anda menjalankan grep pada file besar 10.000 kali. Anda harus membaca kedua file hanya sekali. Jika Anda ingin tetap berada di luar bahasa skrip, Anda dapat melakukannya dengan cara ini:
comm
pada daftar yang diurutkan untuk mendapatkan apa yang ada di daftar keduaSesuatu seperti ini:
Lihat
man comm
.Jika Anda dapat memotong file besar setiap hari (seperti file log), Anda dapat menyimpan cache nomor yang diurutkan dan tidak perlu menguraikannya setiap saat.
sumber
{12}
.. OP telah menggunakan 12, tetapi kunci contohnya 13 panjang ...<(grep...sort)
nama file tersebut.tail -n +$linenum
untuk menampilkan data terbaru. Dengan begitu Anda hanya akan memproses sekitar 200.000 baris setiap hari .. Saya baru saja mengujinya dengan 6 juta baris dalam file-utama dan 10 ribu kunci ... waktu : 0m0.016s nyata, pengguna 0m0.008s, sys 0m0.008sYa, pasti menggunakan database. Mereka dibuat persis untuk tugas-tugas seperti ini.
sumber
Ini mungkin bekerja untuk Anda:
EDIT:
Skrip yang diubah untuk memungkinkan duplikat dan kunci tidak dikenal di kedua file, masih menghasilkan kunci dari file pertama yang tidak ada di file kedua:
sumber
Dengan data sebanyak itu, Anda harus benar-benar beralih ke database. Sementara itu, satu hal yang harus Anda lakukan untuk mencapai kinerja yang layak adalah tidak mencari
file1
secara terpisah untuk setiap kunci. Jalankan tunggalgrep
untuk mengekstrak semua kunci yang tidak dikecualikan sekaligus. Karena itugrep
juga mengembalikan garis yang tidak mengandung kunci, filter itu.(
-Fx
Berarti mencari seluruh baris, secara harfiah-f -
berarti membaca daftar pola dari input standar.)sumber
-v
(-Fxv
) bisa mengurusnya.comm
.Ijinkan saya untuk memperkuat apa yang dikatakan orang lain, "Bawalah kamu ke database!"
Ada binari MySQL yang tersedia secara bebas untuk sebagian besar platform.
Kenapa tidak SQLite? Berbasis memori, memuat flat-file saat Anda memulainya, lalu menutupnya setelah Anda selesai. Ini berarti bahwa jika komputer Anda rusak atau proses SQLite hilang, demikian juga semua data.
Masalah Anda terlihat seperti hanya beberapa baris SQL, dan akan berjalan dalam milidetik!
Setelah menginstal MySQL (yang saya sarankan di atas pilihan lain), saya akan mengeluarkan $ 40 untuk SQL Cookbook O'Reilly dari Anthony Molinaro, yang memiliki banyak pola masalah, mulai dengan
SELECT * FROM table
pertanyaan sederhana , dan melalui agregat dan beberapa gabungan.sumber
Saya tidak yakin apakah ini adalah hasil persis yang Anda cari, tetapi mungkin cara termudah adalah:
Anda juga bisa menggunakan:
Masing-masing membuat file pola sementara yang digunakan untuk mengumpulkan angka-angka dari file besar (
file1
).sumber
grep -vf
sajagrep -f
.Saya sepenuhnya setuju dengan Anda mendapatkan database (MySQL cukup mudah digunakan). Sebelum Anda menjalankannya, saya menyukai
comm
solusi Angus , tetapi begitu banyak orang yang mencobagrep
dan membuat kesalahan sehingga saya pikir saya akan menunjukkan (atau setidaknya satu) cara yang benar untuk melakukannyagrep
.Yang pertama
grep
mendapatkan kunci. Yang ketigagrep
(di<(...)
) mengambil semua kunci yang digunakan dalam file besar, dan<(...)
melewati seperti file sebagai argumen-f
dalam grep kedua. Itu menyebabkan yang keduagrep
menggunakannya sebagai daftar garis yang cocok. Ini kemudian menggunakan ini untuk mencocokkan inputnya (daftar kunci) dari pipa (pertamagrep
), dan mencetak semua kunci yang diekstrak dari file kunci dan bukan (-v
) file besar.Tentu saja Anda dapat melakukan ini dengan file sementara Anda harus melacak dan ingat untuk menghapus:
Ini mencetak semua baris
allkeys
yang tidak muncul diusedkeys
.sumber
grep: Memory exhausted
comm
, dalam urutan itu.File key tidak berubah? Maka Anda harus menghindari mencari entri lama lagi dan lagi.
Dengan
tail -f
Anda bisa mendapatkan output dari file yang sedang tumbuh.grep -f membaca pola dari file, satu baris sebagai pola.
sumber
Tidak akan memposting jawaban saya karena saya pikir jumlah data seperti itu tidak boleh diproses dengan skrip shell, dan jawaban yang tepat untuk menggunakan database sudah diberikan. Namun sejak sekarang ada 7 pendekatan lain ...
Membaca file pertama dalam memori, lalu mencari file kedua untuk angka dan memeriksa apakah nilai disimpan dalam memori. Seharusnya lebih cepat dari beberapa
grep
s, jika Anda memiliki cukup memori untuk memuat seluruh file, yaitu.sumber
Saya setuju dengan @ jan-steinman bahwa Anda harus menggunakan database untuk tugas semacam ini. Ada banyak cara untuk meretas bersama solusi dengan skrip shell seperti jawaban lain tunjukkan, tetapi melakukannya dengan cara itu akan menyebabkan banyak kesengsaraan jika Anda akan menggunakan dan memelihara kode untuk jangka waktu lebih lama daripada hanya proyek membuang satu hari.
Dengan asumsi Anda berada di kotak Linux maka kemungkinan besar Anda telah menginstal Python secara default yang mencakup pustaka sqlite3 pada Python v2.5. Anda dapat memeriksa versi Python Anda dengan:
Saya sarankan menggunakan pustaka sqlite3 karena ini adalah solusi berbasis file sederhana yang ada untuk semua platform (termasuk di dalam browser web Anda!) Dan tidak memerlukan server untuk diinstal. Pada dasarnya nol-konfigurasi dan nol-pemeliharaan.
Di bawah ini adalah skrip python sederhana yang akan mem-parsing format file yang Anda berikan sebagai contoh dan kemudian melakukan kueri "pilih semua" sederhana dan hasilkan semua yang disimpan dalam db.
Ya, ini berarti Anda harus belajar beberapa SQL , tetapi itu akan sangat bermanfaat dalam jangka panjang. Selain itu, alih-alih mem-parsing file log Anda, mungkin Anda bisa menulis data langsung ke database sqlite Anda.
sumber
/usr/bin/sqlite3
bekerja dengan cara yang sama untuk skrip shell ( packages.debian.org/squeeze/sqlite3 ), meskipun saya belum pernah menggunakannya./usr/bin/sqlite3
skrip shell, namun saya sarankan menghindari skrip shell kecuali untuk program membuang sederhana dan alih-alih menggunakan bahasa seperti python yang memiliki penanganan kesalahan yang lebih baik dan lebih mudah untuk mempertahankan dan tumbuh.