Selamat datang di DuckDB | juliablogger.com – Beragampengetahuan
Oleh: Blog Bogumił Kamiński
Repost dari:
Saya sering menulis di blog ini tentang DataFrames.jl. Kali ini saya memutuskan
untuk mengganti mode saya ke kueri SQL lama yang bagus.
Inspirasi dari postingan adalah tindak lanjut dari pembicaraan
“Manipulasi Data di Julia untuk Pengguna Pandas” yang saya luncurkan minggu lalu
Data Science Summit 2022. Dalam pembicaraan itu, saya menjelaskan caranya
DataFrames.jl dibandingkan dengan panda.
Setelah pembicaraan, saya berpikir untuk memeriksa bagaimana perbandingannya
DuckDB, manajer basis data SQL OLAP bekerja dengan baik
sistem.
Dalam posting ini, saya menunjukkan bagaimana skenario analisis sampel dapat diterapkan di
DataFrames.jl dan DuckDB serta tingkat integrasinya.
Kode dijalankan di Julia 1.8.2, CSV.jl 0.10.8, DataFrames.jl 1.4.4 dan
DuckDB.jl 0.6.0 di laptop dengan RAM 32 GB. Saya melakukan tes menggunakan 8 core.
Ketika saya sedang mempersiapkan pembicaraan “Manipulasi Data di Julia untuk Pengguna Pandas”
Saya ingin memilih beberapa kumpulan data yang tidak terlalu besar (sehingga semuanya
cepat) tidak terlalu kecil (agar tidak terlalu cepat).
Jadi saya pergi ke Kaggle dan mencari tupel dengan: 5 hingga 10 GB data, data masuk
File CSV, beberapa (tetapi tidak banyak) file. Sortir tupel tersebut berdasarkan hotness dan
salah satu daftar teratas adalah: Instagram dataset, yang terdiri dari tiga tabel:
instagram_posts.csv: 42 juta baris informasi kiriman individu;instagram_locations.csv: 1,2 juta baris informasi lokasi;instagram_profiles.csv: 4,5 juta baris informasi profil pengguna.
Anda dapat menemukan kumpulan datanya di sini.
Untuk setiap postingan, kami dapat mencocokkan profil orang yang dibuat dan lokasi
dimana itu dibuat? Oleh karena itu, saya memutuskan untuk melakukan hal berikut untuk pengujian:
- membaca data dari disk ke dalam RAM;
- hapus semua baris dengan data yang hilang di pos;
- jatuhkan semua baris dengan data yang hilang dalam catatan dan jika ada catatan duplikat
simpan hanya satu dari mereka; - jatuhkan semua baris dengan data yang hilang di posisinya;
- bergabung dengan posting dan profil kiri;
- kiriman dan lokasi gabung kiri;
- menghitung beberapa statistik agregat pada data pos berdasarkan negara.
Di bawah ini saya tunjukkan bagaimana tugas-tugas ini dapat dilakukan di DataFrames.jl dan
DuckDB.
(sebagai catatan tambahan – tidak dapat melakukan ini “sebagaimana adanya” di panda saya
laptop ketika saya kehabisan RAM dan beberapa langkah dalam proses ini berhasil
terlalu panjang; jadi dalam pembicaraan saya di konferensi, saya menyajikan sedikit berbeda
naskah)
Kami mulai dengan Julia untuk mempelajari datanya. Mari kita lakukan di Julia dulu:
julia> using DataFrames
julia> using CSV
julia> using Statistics
julia> describe(CSV.read("instagram_posts.csv", DataFrame, limit=100), :eltype)
10×2 DataFrame
Row │ variable eltype
│ Symbol Type
─────┼─────────────────────────────────────────
1 │ sid Int64
2 │ sid_profile Int64
3 │ post_id String15
4 │ profile_id Int64
5 │ location_id Int64
6 │ cts String31
7 │ post_type Int64
8 │ description Union{Missing, String}
9 │ numbr_likes Int64
10 │ number_comments Int64
julia> describe(CSV.read("instagram_profiles.csv", DataFrame, limit=100), :eltype)
11×2 DataFrame
Row │ variable eltype
│ Symbol Type
─────┼─────────────────────────────────────────────
1 │ sid Int64
2 │ profile_id Int64
3 │ profile_name String31
4 │ firstname_lastname String31
5 │ description Union{Missing, String}
6 │ following Union{Missing, Int64}
7 │ followers Union{Missing, Int64}
8 │ n_posts Union{Missing, Int64}
9 │ url Union{Missing, String}
10 │ cts String31
11 │ is_business_account Union{Missing, Bool}
julia> describe(CSV.read("instagram_locations.csv", DataFrame, limit=100), :eltype)
23×2 DataFrame
Row │ variable eltype
│ Symbol Type
─────┼──────────────────────────────────────────────────
1 │ sid Int64
2 │ id Int64
3 │ name String
4 │ street Union{Missing, String}
5 │ zip Union{Missing, String15}
6 │ city Union{Missing, String}
7 │ region Missing
8 │ cd Union{Missing, String3}
9 │ phone Union{Missing, String31}
10 │ aj_exact_city_match Union{Missing, Bool}
11 │ aj_exact_country_match Union{Missing, Bool}
12 │ blurb String
13 │ dir_city_id Union{Missing, String15}
14 │ dir_city_name Union{Missing, String}
15 │ dir_city_slug Union{Missing, String}
16 │ dir_country_id Union{Missing, String3}
17 │ dir_country_name Union{Missing, String15}
18 │ lat Union{Missing, Float64}
19 │ lng Union{Missing, Float64}
20 │ primary_alias_on_fb String
21 │ slug String
22 │ website String
23 │ cts String31
Karena kerangka data memiliki banyak kolom, saya telah meringkasnya hanya dengan menyimpan elemennya
Tipe. Saya memuat 100 baris data pertama untuk diuji.
Sekarang tugas serupa di DuckDB:
julia> using DuckDB
julia> con = DBInterface.connect(DuckDB.DB, ":memory:")
DuckDB.DB(":memory:")
julia> DBInterface.execute(con,
"""
DESCRIBE
SELECT *
FROM 'instagram_posts.csv'
LIMIT 100
""")
10×6 DataFrame
Row │ column_name column_type null key default extra
│ String? String? String? String? String? String?
─────┼──────────────────────────────────────────────────────────────────
1 │ sid INTEGER YES missing missing missing
2 │ sid_profile INTEGER YES missing missing missing
3 │ post_id VARCHAR YES missing missing missing
4 │ profile_id BIGINT YES missing missing missing
5 │ location_id BIGINT YES missing missing missing
6 │ cts TIMESTAMP YES missing missing missing
7 │ post_type INTEGER YES missing missing missing
8 │ description VARCHAR YES missing missing missing
9 │ numbr_likes INTEGER YES missing missing missing
10 │ number_comments INTEGER YES missing missing missing
julia> DBInterface.execute(con,
"""
DESCRIBE
SELECT *
FROM 'instagram_profiles.csv'
LIMIT 100
""")
11×6 DataFrame
Row │ column_name column_type null key default extra
│ String? String? String? String? String? String?
─────┼──────────────────────────────────────────────────────────────────────
1 │ sid INTEGER YES missing missing missing
2 │ profile_id BIGINT YES missing missing missing
3 │ profile_name VARCHAR YES missing missing missing
4 │ firstname_lastname VARCHAR YES missing missing missing
5 │ description VARCHAR YES missing missing missing
6 │ following INTEGER YES missing missing missing
7 │ followers INTEGER YES missing missing missing
8 │ n_posts INTEGER YES missing missing missing
9 │ url VARCHAR YES missing missing missing
10 │ cts VARCHAR YES missing missing missing
11 │ is_business_account BOOLEAN YES missing missing missing
julia> DBInterface.execute(con,
"""
DESCRIBE
SELECT *
FROM 'instagram_locations.csv'
LIMIT 100
""")
23×6 DataFrame
Row │ column_name column_type null key default extra
│ String? String? String? String? String? String?
─────┼─────────────────────────────────────────────────────────────────────────
1 │ sid INTEGER YES missing missing missing
2 │ id BIGINT YES missing missing missing
3 │ name VARCHAR YES missing missing missing
4 │ street VARCHAR YES missing missing missing
5 │ zip VARCHAR YES missing missing missing
6 │ city VARCHAR YES missing missing missing
7 │ region VARCHAR YES missing missing missing
8 │ cd VARCHAR YES missing missing missing
9 │ phone VARCHAR YES missing missing missing
10 │ aj_exact_city_match BOOLEAN YES missing missing missing
11 │ aj_exact_country_match BOOLEAN YES missing missing missing
12 │ blurb VARCHAR YES missing missing missing
13 │ dir_city_id VARCHAR YES missing missing missing
14 │ dir_city_name VARCHAR YES missing missing missing
15 │ dir_city_slug VARCHAR YES missing missing missing
16 │ dir_country_id VARCHAR YES missing missing missing
17 │ dir_country_name VARCHAR YES missing missing missing
18 │ lat DOUBLE YES missing missing missing
19 │ lng DOUBLE YES missing missing missing
20 │ primary_alias_on_fb VARCHAR YES missing missing missing
21 │ slug VARCHAR YES missing missing missing
22 │ website VARCHAR YES missing missing missing
23 │ cts TIMESTAMP YES missing missing missing
Perhatikan bagaimana kita telah melihat betapa bagusnya DuckDB terintegrasi dengan Julia. Anda mendapatkan
satu DataFrame Akibatnya Anda dapat bekerja dengannya jika Anda mau.
Mari kita uji kinerja operasi yang diminta dari ujung ke ujung di keduanya
ekosistem.
Dimulai dengan larutan Julia murni:
julia> @time begin
posts = CSV.read("instagram_posts.csv", DataFrame,
select=[:profile_id, :location_id, :number_comments])
profiles = CSV.read("instagram_profiles.csv", DataFrame,
select=[:profile_id, :n_posts])
locations = CSV.read("instagram_locations.csv", DataFrame,
select=[:id, :dir_country_name])
posts2 = dropmissing(posts)
profiles2 = combine(groupby(dropmissing(profiles), :profile_id),
:n_posts => maximum => :n_posts)
locations2 = dropmissing(locations)
leftjoin!(posts2, profiles2, on="profile_id")
leftjoin!(posts2, locations2, on="location_id" => "id")
gdf = groupby(posts2, "dir_country_name", sort=true, skipmissing=true)
combine(gdf, [:n_posts, :number_comments] .=> mean∘skipmissing)
end
23.323866 seconds (514.97 k allocations: 5.622 GiB, 3.30% gc time)
235×3 DataFrame
Row │ dir_country_name n_posts_mean_skipmissing number_comments_mean_skipmissing
│ String? Float64 Float64
─────┼──────────────────────────────────────────────────────────────────────────────────
1 │ Afghanistan 445.58 8.10767
2 │ Albania 524.789 6.83736
3 │ Algeria 353.933 9.9979
4 │ American Samoa 117.692 7.87879
5 │ Andorra 486.206 7.01296
6 │ Angola 469.621 7.48282
7 │ Anguilla 1206.22 4.77193
8 │ Antarctica 1165.97 20.3073
9 │ Antigua 638.995 8.05999
10 │ Argentina 727.673 11.0821
11 │ Armenia 663.196 4.76728
⋮ │ ⋮ ⋮ ⋮
226 │ Uruguay 560.936 8.00079
227 │ Uzbekistan 445.975 8.84245
228 │ Vanuatu 539.349 4.63688
229 │ Vatican City 583.498 7.05353
230 │ Venezuela 551.79 9.4976
231 │ Vietnam 582.829 4.46671
232 │ Western Sahara 643.888 4.6676
233 │ Yemen 411.5 27.9416
234 │ Zambia 411.779 7.09239
235 │ Zimbabwe 518.17 8.3875
214 rows omitted
Sekarang bandingkan dengan DuckDB:
julia> @time DBInterface.execute(con,
"""
SELECT dir_country_name,
mean(n_posts) FILTER (WHERE n_posts IS NOT NULL) n_posts_mean,
mean(number_comments) FILTER (WHERE number_comments IS NOT NULL) number_comments_mean
FROM (SELECT po.number_comments, pr.n_posts, loc.dir_country_name
FROM (SELECT profile_id, location_id, number_comments FROM 'instagram_posts.csv'
WHERE profile_id IS NOT NULL
AND location_id IS NOT NULL
AND number_comments IS NOT NULL
) po
LEFT JOIN (SELECT profile_id, max(n_posts) n_posts
FROM 'instagram_profiles.csv'
WHERE profile_id IS NOT NULL
AND n_posts IS NOT NULL
GROUP BY profile_id) pr
ON po.profile_id = pr.profile_id
LEFT JOIN (SELECT id, dir_country_name FROM 'instagram_locations.csv'
WHERE id IS NOT NULL
AND dir_country_name IS NOT NULL) loc
ON po.location_id = loc.id)
WHERE dir_country_name IS NOT NULL
GROUP BY dir_country_name
ORDER BY dir_country_name
""")
93.220900 seconds (166.60 k allocations: 8.578 MiB, 0.11% compilation time)
235×3 DataFrame
Row │ dir_country_name n_posts_mean number_comments_mean
│ String? Float64? Float64?
─────┼──────────────────────────────────────────────────────────
1 │ Afghanistan 445.58 8.10767
2 │ Albania 524.789 6.83736
3 │ Algeria 353.933 9.9979
4 │ American Samoa 117.692 7.87879
5 │ Andorra 486.206 7.01296
6 │ Angola 469.621 7.48282
7 │ Anguilla 1206.22 4.77193
8 │ Antarctica 1165.97 20.3073
9 │ Antigua 638.995 8.05999
10 │ Argentina 727.673 11.0821
11 │ Armenia 663.196 4.76728
⋮ │ ⋮ ⋮ ⋮
226 │ Uruguay 560.936 8.00079
227 │ Uzbekistan 445.975 8.84245
228 │ Vanuatu 539.349 4.63688
229 │ Vatican City 583.498 7.05353
230 │ Venezuela 551.79 9.4976
231 │ Vietnam 582.829 4.46671
232 │ Western Sahara 643.888 4.6676
233 │ Yemen 411.5 27.9416
234 │ Zambia 411.779 7.09239
235 │ Zimbabwe 518.17 8.3875
214 rows omitted
Kami menemukan bahwa kami mendapatkan hasil yang sama. Performa lebih buruk. Namun, biarkan
kami memisahkan data yang masuk ke bagian RAM menjadi proses tersendiri.
Di sini kita akan menggunakan fitur DuckDB yang sangat bagus sehingga Anda dapat mendaftarkan data
bingkai meja.
Kita mulai lagi dengan Julia:
julia> @time begin
posts2 = dropmissing(posts)
profiles2 = combine(groupby(dropmissing(profiles), :profile_id),
:n_posts => maximum => :n_posts)
locations2 = dropmissing(locations)
leftjoin!(posts2, profiles2, on="profile_id")
leftjoin!(posts2, locations2, on="location_id" => "id")
gdf = groupby(posts2, "dir_country_name", sort=true, skipmissing=true)
combine(gdf, [:n_posts, :number_comments] .=> mean∘skipmissing)
end;
5.632483 seconds (1.61 k allocations: 4.065 GiB, 2.94% gc time)
Sekarang periksa DuckDB:
julia> DuckDB.register_data_frame(con, posts, "posts")
julia> DuckDB.register_data_frame(con, profiles, "profiles")
julia> DuckDB.register_data_frame(con, locations, "locations")
julia> @time DBInterface.execute(con,
"""
SELECT dir_country_name,
mean(n_posts) FILTER (WHERE n_posts IS NOT NULL) n_posts_mean,
mean(number_comments) FILTER (WHERE number_comments IS NOT NULL) number_comments_mean
FROM (SELECT po.number_comments, pr.n_posts, loc.dir_country_name
FROM (SELECT profile_id, location_id, number_comments
FROM posts
WHERE profile_id IS NOT NULL
AND location_id IS NOT NULL
AND number_comments IS NOT NULL
) po
LEFT JOIN (SELECT profile_id, max(n_posts) n_posts
FROM (SELECT profile_id, n_posts
FROM profiles
WHERE n_posts IS NOT NULL)
GROUP BY profile_id) pr
ON po.profile_id = pr.profile_id
LEFT JOIN (SELECT id, dir_country_name
FROM locations
WHERE id IS NOT NULL
AND dir_country_name IS NOT NULL) loc
ON po.location_id = loc.id)
GROUP BY dir_country_name
ORDER BY dir_country_name
""");
1.818248 seconds (616.46 k allocations: 24.675 MiB, 14.41% compilation time)
Seperti yang Anda lihat kali ini DuckDB lebih cepat dari Julia. Selain itu kami menemukan itu
sebagian besar waktu awal dihabiskan untuk membaca data dari disk dan
analisis di kedua ekosistem cukup cepat.
Saya melakukan lebih banyak penelitian tentang masalah ini dan kesimpulan utama untuk
Perbedaan performanya adalah:
- DuckDB mengeksekusi kueri sekaligus, sedangkan di DataFrames.jl API-nya
bersemangat, wujudkan semua tabel perantara; ketika saya membagi kueri SQL besar
ke dalam langkah-langkah untuk mewujudkan tabel perantara, perbedaan kinerjanya adalah
secara signifikan lebih kecil. - bergabung lebih cepat di DuckDB (ini adalah masalah yang diketahui di DataFrames.jl yang kami
masih perlu menambahkan dukungan multithreading untuk beberapa algoritme kami
asalkan); - split-apply-combine lebih cepat di DataFrames.jl.
Bagi saya, kesimpulan utama dari tes ini adalah:
- DuckDB terintegrasi dengan baik dengan Julia dan DataFrames.jl. Seperti yang telah Anda lihat
Anda dapat mendaftarkan kerangka data sebagai tabel di DuckDB dan mendapatkan hasil kueri sebagai
bingkai data. - DuckDB sangat cepat. Anda dapat menghargai perbedaan ini terutama jika
Anda melakukan penggabungan besar (ini akan meningkat di masa mendatang DataFrames.jl)
dan ketika Anda melakukan kueri kompleks (ini tidak akan membaik
DataFrames.jl dalam waktu dekat – desain paket saat ini sangat menarik
dan tidak mendukung pengoptimalan kueri agregat). - Saya menemukan kode DataFrmes.jl lebih mudah dibaca, tapi mungkin saya bias di sini.
Ilmuwan data yang paham SQL mungkin akan menemukan lebih banyak kode DuckDB
alam.
Selamat meretas dengan Julia dan DuckDB!
Terkait
Software Terbaru Saat Ini
Aplikasi yang sedang trend saat ini
object oriented programming, programming language, programming adalah, web programming, belajar programming, tournament software, software, software adalah, contoh software, apa itu software, pengertian software, aplikasi, aplikasi penghasil uang, aplikasi bokep, aplikasi video, programming
#Selamat #datang #DuckDB #juliablogger.com