Data mart dari Chapter Data Marts menyeragamkan bentuk data, tetapi satu sumber ketidakcocokan angka masih tersisa: definisi metrik yang ditulis ulang di mana-mana. Dashboard keuangan menghitung pendapatan dengan SUM(total), dashboard marketing menghitung ulang rumus yang sama — sampai suatu hari satu pengembang lupa menyaring pesanan batal, dan dua rapat membahas dua angka “pendapatan” yang berbeda. Semantic layer memutus masalah tersebut di akarnya: metrik didefinisikan satu kali di satu tempat, dan semua pemakai memanggil definisi tersebut.

Apa Itu Semantic Layer #

Semantic layer — disebut juga metrics layer — adalah kumpulan definisi metrik bernama yang menjadi kontrak tunggal organisasi. “Pendapatan” didefinisikan sebagai jumlah total pesanan berstatus selesai; “pelanggan aktif” didefinisikan sebagai jumlah pelanggan berbeda dengan minimal satu pesanan selesai pada periode yang diukur. Setiap dashboard, laporan, dan query analitik tidak lagi menulis rumus sendiri, melainkan memanggil metrik bernama tersebut.

Bentuk paling sederhana semantic layer adalah SQL view yang diberi nama jelas; bentuk yang lebih lengkap memakai alat khusus seperti dbt metrics yang juga mengelola dimensi, satuan waktu, dan versi definisi. Prinsipnya sama: satu definisi, banyak pemakai.

Manfaat: Konsistensi Metrik Antar Dashboard #

Manfaat pertama adalah konsistensi — seluruh dashboard yang menampilkan pendapatan dijamin membaca angka yang sama karena sumbernya satu. Manfaat kedua adalah perubahan terkendali: ketika definisi pendapatan harus berubah (misalnya pesanan retur ikut dikurangi), perubahan cukup dilakukan pada satu tempat lalu menyebar ke semua laporan, lengkap dengan jejak review pada kode definisi. Manfaat ketiga adalah kecepatan pengembangan: pengguna bisnis memanggil metrik siap pakai tanpa menerjemahkan ulang logika bisnis ke SQL setiap kali membangun grafik baru.

Implementasi dengan SQL View #

Kita definisikan dua metrik bulanan dalam satu view metrik_bulanan, lalu memakai view yang sama dari dua sudut pandang berbeda. Sebagai pembanding, sebuah query ad-hoc yang menulis ulang rumus sendiri sengaja dibiarkan lupa menyaring status.

python
import sqlite3

koneksi = sqlite3.connect(":memory:")
cur = koneksi.cursor()

cur.executescript("""
CREATE TABLE fact_pesanan (
    id_pesanan   TEXT NOT NULL,
    sk_pelanggan INTEGER NOT NULL,
    tanggal      TEXT NOT NULL,
    status       TEXT NOT NULL,
    total        INTEGER NOT NULL
);
INSERT INTO fact_pesanan VALUES
    ('ORD-1', 1, '2026-01-05', 'selesai',    150000),
    ('ORD-2', 1, '2026-01-06', 'selesai',    200000),
    ('ORD-3', 2, '2026-01-07', 'selesai',    300000),
    ('ORD-4', 2, '2026-01-08', 'dibatalkan', 100000);
""")

# semantic layer: definisi metrik ditulis sekali sebagai view
cur.execute("""
CREATE VIEW metrik_bulanan AS
SELECT
    strftime('%Y-%m', tanggal)   AS bulan,
    SUM(total)                   AS pendapatan,
    COUNT(DISTINCT sk_pelanggan) AS pelanggan_aktif
FROM fact_pesanan
WHERE status = 'selesai'
GROUP BY bulan
""")

# dashboard tim keuangan memakai definisi yang sama
print("Dashboard keuangan - pendapatan per bulan:")
for baris in cur.execute("SELECT bulan, pendapatan FROM metrik_bulanan"):
    print(" ", baris)

# dashboard tim marketing memakai definisi yang sama
print("Dashboard marketing - pelanggan aktif per bulan:")
for baris in cur.execute("SELECT bulan, pelanggan_aktif FROM metrik_bulanan"):
    print(" ", baris)

# pembanding: query ad-hoc yang menulis ulang definisi sendiri
(pendapatan_adhoc,) = cur.execute(
    "SELECT SUM(total) FROM fact_pesanan"
).fetchone()
(pendapatan_resmi,) = cur.execute(
    "SELECT pendapatan FROM metrik_bulanan"
).fetchone()
print()
print("Ad-hoc tanpa filter status :", pendapatan_adhoc)
print("Semantic layer              :", pendapatan_resmi)

Output yang Dihasilkan:

text
Dashboard keuangan - pendapatan per bulan:
  ('2026-01', 650000)
Dashboard marketing - pelanggan aktif per bulan:
  ('2026-01', 2)

Ad-hoc tanpa filter status : 750000
Semantic layer              : 650000

Mari kita telaah baris-baris kode di atas:

  1. Baris 22-31 (CREATE VIEW metrik_bulanan): seluruh keputusan bisnis dikunci di satu definisi — hanya status selesai yang dihitung, pendapatan adalah SUM(total), dan pelanggan aktif dihitung DISTINCT per bulan; view tidak menyimpan data, hanya menyimpan logika.
  2. Baris 34-41 (dua dashboard): kedua dashboard menulis query berbeda (kolom berbeda) tetapi membaca view yang sama, sehingga keduanya tidak mungkin berbeda definisi.
  3. Baris 44-52 (pembanding): query ad-hoc menjumlahkan seluruh pesanan tanpa filter status dan menghasilkan 750000 — selisih 100000 dari angka resmi 650000 berasal dari satu pesanan batal yang ikut terhitung.

Konsep dbt Metrics #

Pada proyek dbt, semantic layer dibangun lewat semantic model yang mendeklarasikan entity, measure, dan dimensi, lalu metrik yang dirakit dari measure tersebut. Cuplikan berikut adalah konsep deklarasinya — tidak dieksekusi pada bab ini karena membutuhkan proyek dbt utuh.

yaml
version: 2

semantic_models:
  - name: pesanan
    model: ref('fact_pesanan')
    defaults:
      agg_time_dimension: tanggal
    entities:
      - name: pesanan
        type: primary
        expr: id_pesanan
    measures:
      - name: total_pesanan
        agg: sum
        expr: total
    dimensions:
      - name: tanggal
        type: time
        type_params:
          time_granularity: day

metrics:
  - name: pendapatan
    label: Pendapatan
    type: simple
    type_params:
      measure: total_pesanan

Semantic model pesanan memetakan fact_pesanan ke dalam komponen metrik: entity pesanan sebagai kunci, measure total_pesanan sebagai agregasi penjumlahan kolom total, dan dimensi waktu tanggal untuk pemotongan harian hingga tahunan. Metrik pendapatan kemudian cukup merujuk measure tersebut — setiap query, apapun toolnya, menghasilkan agregasi yang identik. Aturan penyaring seperti status selesai ditambahkan pada definisi measure atau filter metrik, bukan ditulis ulang di setiap dashboard. Dokumentasi lengkap konsep ini ada di docs.getdbt.com , sedangkan sintaks CREATE VIEW yang dipakai contoh SQLite dirinci di dokumentasi SQLite .

Dengan semantic layer, lapisan warehouse kita lengkap: data dimodelkan, didistribusikan per departemen, dan metriknya terdefinisi tunggal. Pertanyaan arsitektur berikutnya berada di luar warehouse: bagaimana membandingkannya dengan pendekatan penyimpanan lain yang menampung data mentah dalam format apa pun? Chapter Data Warehouse vs Data Lake membahas perbandingan tersebut.