Tìm số lần xuất hiện của user_name trong file CSV 13M line
- Published on
- Le Hoang Tam--2 min read
Overview
Đề bài toán: Tìm số lần xuất hiện của user_name
trong file CSV File CSV có khoản hơn 13 triệu dòng
dữ liệu (nặng khoảng 500Mb)
# CSV file
"user_name","suspect_flag"
aadilab,suspect_conversations_flag
aadilab,suspect_searches_flag
Mình có benchmark 1 số cách:
require 'benchmark'
def ben_csv
@csv = CSV.read("db/suspect_workers_flag_super_fake.csv")
Benchmark.bmbm do |x|
x.report("select array:") {
p @csv.select {|x, y| x == "zylafl"}.count
}
end
end
def ben_file
@csv_str = File.read("db/suspect_workers_flag_super_fake.csv")
Benchmark.bmbm do |x|
x.report("string regex:") {
p @csv_str.scan(/zylafl\,/).count
}
end
end
def ben_shellscript
Benchmark.bmbm do |x|
x.report("shel script:") {
p `grep -o 'zylafl,' db/suspect_workers_flag_super_fake.csv | wc -l`
}
end
end
Result:
Rehearsal -------------------------------------------------
string regex: 3
0.273001 0.001638 0.274639 ( 0.275356)
---------------------------------------- total: 0.274639sec
Rehearsal ------------------------------------------------
shel script: " 3\n"
3.452150 0.595941 13.451730 ( 9.518582)
-------------------------------------- total: 13.451730sec
Rehearsal -------------------------------------------------
select array: 3
4.287471 0.338820 4.626291 ( 4.680256)
---------------------------------------- total: 4.626291sec
Như vậy, nếu đọc file CSV như 1 chuỗi và dùng regex thì tốc độ nhanh nhất. Một số riskies:
- Có nhiều request và hệ thống sẽ load file CSV lên để đọc, do chưa có cơ chế cache nên sẽ tốn khá nhiều tài nguyên
- Tốc độ sẽ bị giảm xuống, RAM, CPU sẽ được dùng nhiều hơn nếu có nhiều dữ liệu hơn và có thể dẫn đến
Not responding
trên server
Another solution from HaVS: Tạo file CSV mới, trong file mới này sẽ tổng kết lại số lần xuất hiện của user_name.
# CSV file
"user_name", "count"
abc,3
abd,2
abf,2
Khi cần mình sẽ gọi file mới để lấy value ra.
Cần tạo worker để update file mới vào mỗi tối hoặc 1 khung thời gian nào đó
Trigger callback khi record được insert vào db (có thể sẽ khó nếu dùng data từ database khác)
Risk:
- Data có thể không được up-to-date
Bạn còn cách nào khác hay hơn không?