Ekstensi hll menambahkan tipe data HyperLogLog ke ApsaraDB RDS for PostgreSQL, memungkinkan Anda memperkirakan jumlah nilai unik (kardinalitas) pada set data besar dengan tingkat kesalahan di bawah 1% dan penggunaan penyimpanan minimal. Satu nilai hll berukuran 1.280 byte dapat merepresentasikan miliaran elemen unik—sehingga sangat praktis untuk analitik skala tinggi seperti menghitung jumlah tayangan halaman (PV) dan pengunjung unik (UV).
Prasyarat
Sebelum memulai, pastikan bahwa:
Instans RDS Anda menjalankan PostgreSQL 11 atau versi yang lebih baru.
Ekstensi hll tidak didukung pada PostgreSQL 17.
Jika versi mesin utama Anda memenuhi persyaratan tetapi ekstensi tetap tidak tersedia, perbarui versi mesin minor. Lihat Perbarui versi mesin minor.
Kapan menggunakan hll alih-alih COUNT DISTINCT
COUNT DISTINCT hanya menjawab satu pertanyaan tetap per kueri: "Berapa banyak nilai unik yang muncul dalam set data ini?" Jika Anda perlu menjawab pertanyaan tersebut untuk berbagai rentang waktu—hari ini, minggu ini, 30 hari terakhir, atau jendela bergulir 7 hari—Anda harus memindai ulang data mentah untuk setiap kueri.
hll bekerja secara berbeda. Ekstensi ini menyimpan sketsa ringkas dari suatu set data. Setelah Anda menyimpan sketsa harian, Anda dapat melakukan union saat kueri untuk menjawab pertanyaan apa pun terkait rentang waktu tanpa menyentuh data mentah. Hal ini membuat hll sangat cocok untuk beban kerja analitik di mana:
Data event mentah terlalu besar untuk diagregasi berulang kali
Anda memerlukan jumlah UV atau PV untuk rentang tanggal arbitrer
Hasil perkiraan dapat diterima (akurasi dapat dikonfigurasi melalui
hll_set_defaults)
Untuk algoritma lengkapnya, lihat HyperLogLog: the analysis of a near-optimal cardinality estimation algorithm. Untuk kode sumber ekstensi upstream, lihat citusdata/postgresql-hll.
Cara kerja hashing
Sebelum menambahkan nilai ke struktur hll, Anda harus meng-hash-nya menggunakan salah satu fungsi hll_hash_*. hll menyimpan nilai hash, bukan nilai mentah—dengan cara inilah hll mencapai ukuran ringkas sekaligus penyimpanan yang agnostik terhadap tipe data.
Mencoba menambahkan integer mentah tanpa hashing akan menghasilkan error:
SELECT 1234 || hll_empty();
-- ERROR: operator does not exist: integer || hll
-- HINT: No operator matches the given name and argument type(s).
-- You might need to add explicit type casts.Selalu bungkus nilai input dengan pemanggilan hll_hash_* yang sesuai sebelum meneruskannya ke operasi hll.
Aktifkan ekstensi hll
Sambungkan ke database Anda dan jalankan:
CREATE EXTENSION hll;Panduan cepat
Contoh berikut membangun set hll minimal langkah demi langkah, lalu mengambil kardinalitasnya.
-- Buat tabel dengan kolom hll
CREATE TABLE helloworld (id integer, visitors hll);
-- Masukkan hll kosong
INSERT INTO helloworld (id, visitors) VALUES (1, hll_empty());
-- Tambahkan integer yang telah di-hash (misalnya, ID pengguna numerik)
UPDATE helloworld
SET visitors = hll_add(visitors, hll_hash_integer(12345))
WHERE id = 1;
-- Tambahkan nilai teks yang telah di-hash (misalnya, token session)
UPDATE helloworld
SET visitors = hll_add(visitors, hll_hash_text('session-abc'))
WHERE id = 1;
-- Perkirakan jumlah nilai unik
SELECT hll_cardinality(visitors) FROM helloworld WHERE id = 1;
-- hll_cardinality
-- -----------------
-- 2
-- (1 row)Operasi dasar
Buat tabel dengan bidang hll:
create table agg (id int primary key, userids hll);Konversi data INT ke data hll_hashval:
select 1::hll_hashval;Perkirakan UV untuk rentang tanggal
Contoh ini menunjukkan pola analitik PV/UV yang umum. Ide utamanya: simpan satu sketsa hll per hari, lalu lakukan union sketsa saat kueri untuk menjawab pertanyaan apa pun terkait rentang tanggal.
Langkah 1: Buat tabel dan isi sketsa harian
CREATE TABLE access_date (acc_date date UNIQUE, userids hll);
-- Hari 0: pengguna 1–10.000
INSERT INTO access_date
SELECT current_date, hll_add_agg(hll_hash_integer(user_id))
FROM generate_series(1, 10000) t(user_id);
-- Hari -1: pengguna 5.000–20.000
INSERT INTO access_date
SELECT current_date - 1, hll_add_agg(hll_hash_integer(user_id))
FROM generate_series(5000, 20000) t(user_id);
-- Hari -2: pengguna 9.000–40.000
INSERT INTO access_date
SELECT current_date - 2, hll_add_agg(hll_hash_integer(user_id))
FROM generate_series(9000, 40000) t(user_id);Langkah 2: Kueri UV untuk satu hari
Operator # mengembalikan perkiraan kardinalitas secara langsung.
SELECT #userids FROM access_date WHERE acc_date = current_date;
-- ?column?
-- ------------------
-- 9725.85273370708
-- (1 row)
SELECT #userids FROM access_date WHERE acc_date = current_date - 1;
-- ?column?
-- ------------------
-- 14968.6596883279
-- (1 row)
SELECT #userids FROM access_date WHERE acc_date = current_date - 2;
-- ?column?
-- ------------------
-- 29361.5209149911
-- (1 row)Langkah 3: Kueri UV untuk rentang tanggal
Lakukan union sketsa harian terlebih dahulu, lalu perkirakan kardinalitas. Pendekatan ini secara tepat memperhitungkan pengguna yang muncul di beberapa hari.
-- Pengunjung unik selama 3 hari terakhir (menghapus duplikat lintas hari)
SELECT hll_cardinality(hll_union_agg(userids))
FROM access_date
WHERE acc_date >= current_date - 2;Langkah 4: Hitung jendela UV bergulir 7 hari
Gunakan fungsi jendela untuk menghitung jumlah pengunjung unik bergulir setiap hari tanpa memindai ulang data mentah.
SELECT
acc_date,
#hll_union_agg(userids) OVER seven_days AS rolling_uv
FROM access_date
WINDOW seven_days AS (ORDER BY acc_date ASC ROWS 6 PRECEDING);Referensi
Fungsi hash
Hash setiap nilai input sebelum menambahkannya ke struktur hll. Pilih fungsi yang sesuai dengan tipe data kolom Anda.
| Function | Input type | Example |
|---|---|---|
hll_hash_boolean | boolean | hll_hash_boolean(true) |
hll_hash_smallint | smallint | hll_hash_smallint(4) |
hll_hash_integer | integer | hll_hash_integer(21474836) |
hll_hash_bigint | bigint | hll_hash_bigint(9007199254740992) |
hll_hash_text | text | hll_hash_text('user@example.com') |
Semua fungsi mengembalikan hll_hashval, satu-satunya tipe yang diterima oleh operator dan fungsi agregat hll.
Operator
hll Operator
| Operator | Description | Example |
|---|---|---|
= | Equality | hll_add_agg(1::hll_hashval) = hll_add_agg(2::hll_hashval) |
!= / <> | Inequality | — |
|| | Union (gabungkan dua set hll) | hll_add_agg(1::hll_hashval) || hll_add_agg(2::hll_hashval) |
# | Perkiraan kardinalitas | #hll_add_agg(1::hll_hashval) |
hll_hashval Operator
| Operator | Description | Example |
|---|---|---|
= | Equality | 1::hll_hashval = 2::hll_hashval |
!= / <> | Inequality | 1::hll_hashval <> 2::hll_hashval |
Fungsi agregat dan utilitas
| Function | Description | Example |
|---|---|---|
hll_empty() | Mengembalikan hll kosong | hll_empty() |
hll_add(hll, hll_hashval) | Menambahkan nilai hash ke hll | hll_add(set, hll_hash_integer(42)) |
hll_add_agg(hll_hashval) | Agregat: membangun hll dari kumpulan nilai hash | SELECT hll_add_agg(hll_hash_integer(user_id)) FROM events |
hll_cardinality(hll) | Mengembalikan perkiraan jumlah nilai unik | SELECT hll_cardinality(visitors) |
hll_union(hll, hll) | Menggabungkan dua nilai hll | hll_union(hll_add_agg(1::hll_hashval), hll_add_agg(2::hll_hashval)) |
hll_union_agg(hll) | Agregat: menggabungkan beberapa nilai hll | SELECT hll_union_agg(daily_sketch) FROM daily_uniques |
hll_set_defaults(log2m, regwidth, expthresh, sparseon) | Mengonfigurasi kompromi antara akurasi dan penyimpanan | SELECT hll_set_defaults(15, 5, -1, 1) |
hll_print(hll) | Mengembalikan informasi debug untuk nilai hll | SELECT hll_print(hll_add_agg(1::hll_hashval)) |