Selamat datang di DuckDB |  juliablogger.com

 – Beragampengetahuan
12 mins read

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!

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

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *