Ada satu momen yang hampir selalu sama di setiap gudang MRO yang saya audit datanya.
Purchasing membuka PO untuk bearing 6205ZZ. Seminggu kemudian, PO lain keluar untuk "BRG 6205-2Z". Dua minggu berikutnya, "Bearing 6205 ZZ SKF". Tiga baris berbeda di sistem. Satu barang yang persis sama di rak.
Stok tercatat 3 unit. Fisiknya 47.
Ini bukan masalah orang malas. Ini masalah skema. Standar internasional seperti ISO 55000 tentang manajemen aset sudah lama menempatkan kualitas data aset sebagai syarat dasar pengambilan keputusan berbasis risiko — bukan sebagai pekerjaan administratif yang bisa ditunda. Dan di situlah master data suku cadang berhenti jadi urusan admin gudang, lalu jadi urusan engineering.
Landasannya bukan opini saya. Penelitian yang mengintegrasikan standar ISO 55000 dengan model manajemen pemeliharaan menunjukkan bahwa implementasi model maintenance yang tepat secara langsung memenuhi persyaratan standar tersebut — dan efeknya terasa di pengurangan biaya serta kualitas keputusan operasional.
Saya mengangkat tema ini karena celahnya nyata. Di komunitas dev, kita punya ratusan artikel tentang data quality untuk analytics dan machine learning. Nyaris tidak ada yang membahas data quality untuk gudang sparepart pabrik. Padahal problemnya identik: entity resolution, normalisasi, deduplikasi, validasi skema. Bedanya cuma satu — di sini, false negative-nya berbentuk mesin produksi yang berhenti karena bearing "tidak ada stok" padahal ada 47 di rak.
Data yang buruk tidak membuat sistem gagal seketika. Ia membuat sistem gagal perlahan, di tempat yang tidak Anda awasi, dengan biaya yang tidak pernah masuk laporan.
1. Kenapa Master Data Sparepart Selalu Berantakan
Sebelum masuk ke kode, penting memahami akar masalahnya. Karena kalau Anda menulis skrip deduplikasi tanpa paham kenapa duplikatnya muncul, Anda cuma membersihkan sekali lalu kotor lagi bulan depan.
Input bebas adalah bug, bukan fitur
Sebagian besar sistem ERP di Indonesia mengizinkan field deskripsi item diisi bebas.
Tidak ada constraint. Tidak ada validasi. Tidak ada autocomplete.
Hasilnya bisa ditebak: satu barang, sepuluh cara penulisan. Tergantung siapa yang input, jam berapa, dan sedang buru-buru atau tidak.
Tidak ada satu pun yang jadi pemilik data
Purchasing merasa itu urusan gudang. Gudang merasa itu urusan maintenance. Maintenance merasa itu urusan IT. IT merasa itu urusan siapa pun yang punya akses ERP.
Data tanpa owner akan selalu membusuk.
Migrasi sistem membawa serta sampahnya
Ganti ERP tidak membersihkan apa pun. Sampah dari sistem lama diimpor apa adanya ke sistem baru, lalu bercampur dengan sampah baru.
Sekarang Anda punya dua generasi duplikat.
2. Merancang Skema Penamaan yang Tidak Ambigu
Skema penamaan adalah fondasinya. Kalau bagian ini salah, semua otomasi di atasnya cuma menunda masalah. Prinsipnya sederhana: setiap atribut punya slot tetap, dan setiap slot punya vocabulary terkontrol.
Struktur berbasis slot
Format yang terbukti stabil di lapangan menggunakan pemisahan atribut yang eksplisit:
[NOUN]-[MODIFIER]-[SIZE]-[MATERIAL]-[BRAND]-[PARTNUMBER]
Contoh konkret:
BEARING-BALL-6205-STEEL-SKF-6205-2Z
VALVE-BALL-2IN-SS316-KITZ-UTKM-2
CABLE-NYY-4X10MM-CU-SUPREME-NYY4X10
Kenapa ini bekerja? Karena posisi menentukan makna. Parser tidak perlu menebak apakah "6205" itu ukuran atau part number — posisinya sudah menjawab.
Vocabulary terkontrol untuk noun
Ini bagian yang paling sering dilewati orang. Anda butuh daftar tertutup untuk kata benda utama.
| Istilah bebas yang ditemukan di lapangan | Noun terstandar |
|---|---|
| bearing, bering, laher, klaher | BEARING |
| motor, dinamo, elektromotor | MOTOR |
| pompa, pump, pumping unit | PUMP |
| kabel, cable, wire | CABLE |
| kunci pas, wrench, spanner | WRENCH |
| sarung tangan, glove, hand protection | GLOVE |
Daftar ini tidak boleh bisa ditambah oleh sembarang user. Penambahan noun baru harus lewat approval — persis seperti menambah enum baru di database schema.
Aturan satuan yang tidak boleh dilanggar
Satuan adalah sumber duplikat yang diremehkan.
2IN dan 2" dan 50MM dan 50 mm bisa merujuk ke barang yang sama. Tetapkan satu kanonik, konversi sisanya di layer normalisasi.
3. Implementasi Normalisasi dengan Python
Sekarang bagian yang menyenangkan. Normalisasi adalah proses mengubah teks bebas jadi bentuk kanonik yang bisa dibandingkan secara deterministik. Ini dijalankan sebelum deduplikasi, bukan sesudahnya.
Pipeline normalisasi dasar
import re
import unicodedata
NOUN_MAP = {
"bering": "BEARING", "laher": "BEARING", "klaher": "BEARING",
"brg": "BEARING", "bearing": "BEARING",
"dinamo": "MOTOR", "elektromotor": "MOTOR", "motor": "MOTOR",
"pompa": "PUMP", "pump": "PUMP",
"kabel": "CABLE", "cable": "CABLE",
}
UNIT_MAP = {
r'(\d+(?:\.\d+)?)\s*"': lambda m: f"{m.group(1)}IN",
r'(\d+(?:\.\d+)?)\s*inch(?:es)?': lambda m: f"{m.group(1)}IN",
r'(\d+(?:\.\d+)?)\s*mm\b': lambda m: f"{m.group(1)}MM",
}
def normalize(raw: str) -> str:
"""Ubah deskripsi bebas jadi bentuk kanonik."""
if not raw:
return ""
# Buang aksen dan karakter non-ASCII
text = unicodedata.normalize("NFKD", raw)
text = text.encode("ascii", "ignore").decode("ascii")
text = text.upper().strip()
# Normalisasi satuan sebelum tokenisasi
for pattern, repl in UNIT_MAP.items():
text = re.sub(pattern, repl, text, flags=re.IGNORECASE)
# Rapikan separator
text = re.sub(r"[/,;]+", " ", text)
text = re.sub(r"\s*-\s*", "-", text)
text = re.sub(r"\s+", " ", text)
# Petakan noun ke bentuk terstandar
tokens = text.split()
tokens = [NOUN_MAP.get(t.lower(), t) for t in tokens]
return " ".join(tokens)
Perhatikan urutannya. Normalisasi satuan harus terjadi sebelum tokenisasi, karena 2 " dengan spasi akan pecah jadi dua token dan informasinya hilang.
Membangun fingerprint untuk pencocokan
Setelah dinormalisasi, buat fingerprint yang mengabaikan urutan kata:
def fingerprint(normalized: str) -> str:
"""Fingerprint tak bergantung urutan token."""
tokens = sorted(set(normalized.split()))
return "|".join(tokens)
# BEARING 6205 SKF -> "6205|BEARING|SKF"
# SKF BEARING 6205 -> "6205|BEARING|SKF" (identik)
Dua deskripsi dengan fingerprint sama hampir pasti barang yang sama. Ini menangkap sekitar 60-70% duplikat tanpa perlu fuzzy matching sama sekali.
4. Deduplikasi SKU: Dari Exact Match ke Fuzzy Matching
Fingerprint menangkap yang mudah. Sisanya butuh pendekatan berbeda, karena typo dan singkatan tidak akan pernah menghasilkan fingerprint identik. Di sinilah master data suku cadang butuh strategi berlapis, bukan satu algoritma tunggal.
Lapis pertama: blocking untuk efisiensi
Membandingkan 50.000 item satu sama lain berarti 1,25 miliar perbandingan. Tidak realistis.
Blocking memecah data jadi kelompok kecil berdasarkan kunci kasar, lalu perbandingan hanya dilakukan di dalam kelompok:
from collections import defaultdict
def build_blocks(items: list[dict]) -> dict:
"""Kelompokkan item berdasarkan noun + token numerik pertama."""
blocks = defaultdict(list)
for item in items:
norm = item["normalized"]
tokens = norm.split()
noun = next((t for t in tokens if t in NOUN_MAP.values()), "UNKNOWN")
num = next((t for t in tokens if any(c.isdigit() for c in t)), "NONUM")
blocks[f"{noun}::{num}"].append(item)
return blocks
Dengan blocking, 50.000 item biasanya pecah jadi ribuan blok kecil berisi 5-50 item. Perbandingan turun drastis.
Lapis kedua: similarity scoring
Di dalam setiap blok, hitung kemiripan:
from rapidfuzz import fuzz
def score_pair(a: str, b: str) -> float:
"""Skor gabungan dari beberapa metrik."""
token_set = fuzz.token_set_ratio(a, b)
partial = fuzz.partial_ratio(a, b)
return 0.7 * token_set + 0.3 * partial
def find_duplicates(block: list[dict], threshold: float = 88.0):
pairs = []
for i in range(len(block)):
for j in range(i + 1, len(block)):
s = score_pair(block[i]["normalized"], block[j]["normalized"])
if s >= threshold:
pairs.append((block[i]["sku"], block[j]["sku"], round(s, 1)))
return pairs
Ambang 88 adalah titik awal, bukan angka suci. Kalibrasikan dengan sampel yang sudah diverifikasi manual.
Lapis ketiga: part number sebagai penentu
Ini aturan yang mengalahkan semua skor kemiripan.
Kalau dua item punya part number manufaktur yang sama persis setelah dinormalisasi, mereka duplikat. Titik. Berapa pun skor teksnya.
Sebaliknya, kalau part number-nya berbeda dan keduanya valid, mereka bukan duplikat — meski deskripsinya 99% mirip.
def resolve_conflict(a: dict, b: dict, text_score: float) -> str:
pn_a = a.get("part_number_norm")
pn_b = b.get("part_number_norm")
if pn_a and pn_b:
return "DUPLICATE" if pn_a == pn_b else "DISTINCT"
if text_score >= 95:
return "DUPLICATE"
if text_score >= 88:
return "REVIEW"
return "DISTINCT"
Bucket REVIEW itu penting. Jangan pernah auto-merge sesuatu yang ambigu. Biaya salah merge jauh lebih besar daripada biaya duplikat yang lolos.
5. Validasi Otomatis: Mencegah Data Kotor Masuk Lagi
Pembersihan tanpa pencegahan adalah pekerjaan sia-sia. Enam bulan setelah proyek cleansing selesai, datanya akan kotor lagi kalau tidak ada gerbang validasi di titik input.
Skema validasi dengan Pydantic
from pydantic import BaseModel, field_validator
from typing import Optional
import re
ALLOWED_NOUNS = set(NOUN_MAP.values())
SKU_PATTERN = re.compile(r"^[A-Z]{3,10}-[A-Z0-9\-]{2,40}$")
class SparePartRecord(BaseModel):
sku: str
noun: str
modifier: Optional[str] = None
size: Optional[str] = None
brand: Optional[str] = None
part_number: Optional[str] = None
uom: str
@field_validator("noun")
@classmethod
def noun_must_be_controlled(cls, v: str) -> str:
v = v.upper()
if v not in ALLOWED_NOUNS:
raise ValueError(
f"Noun '{v}' tidak ada di vocabulary terkontrol. "
f"Ajukan penambahan lewat proses approval."
)
return v
@field_validator("sku")
@classmethod
def sku_format(cls, v: str) -> str:
if not SKU_PATTERN.match(v.upper()):
raise ValueError(f"Format SKU tidak valid: {v}")
return v.upper()
@field_validator("uom")
@classmethod
def uom_controlled(cls, v: str) -> str:
allowed = {"PCS", "SET", "MTR", "KG", "LTR", "BOX", "ROLL"}
v = v.upper()
if v not in allowed:
raise ValueError(f"UOM '{v}' tidak dikenali")
return v
Validasi ini dipasang di API layer, bukan di UI. Karena data masuk lewat banyak pintu: form manual, upload Excel, integrasi supplier, migrasi batch.
Metrik kualitas data yang perlu dipantau
| Metrik | Cara hitung | Target sehat |
|---|---|---|
| Completeness | % record dengan field wajib terisi | > 98% |
| Duplicate rate | Duplikat terkonfirmasi / total SKU aktif | < 2% |
| Noun compliance | % record dengan noun dari vocabulary | 100% |
| Part number coverage | % record punya part number valid | > 85% |
| Orphan SKU | SKU tanpa transaksi 24 bulan terakhir | dipantau, bukan target |
Pasang ini sebagai dashboard yang dilihat mingguan. Bukan laporan tahunan.
6. Panduan Implementasi Bertahap
Bagian ini adalah urutan kerja yang sudah terbukti tidak menimbulkan kekacauan operasional. Kuncinya: jangan pernah mengubah data produksi sebelum tahap validasi selesai.
Langkah 1 — Ekstraksi dan profiling
Tarik seluruh master item dari ERP ke staging. Jangan sentuh sumbernya.
Hitung distribusi: berapa persen field kosong, berapa banyak nilai unik per kolom, pola apa yang muncul. Ini menentukan seberapa parah masalahnya.
Estimasi waktu: 3-5 hari untuk 50.000 SKU.
Langkah 2 — Bangun vocabulary dari data nyata
Jangan mengarang daftar noun dari kepala. Ekstrak token yang paling sering muncul, urutkan berdasarkan frekuensi, lalu petakan secara manual bersama tim maintenance.
Estimasi waktu: 1-2 minggu, dan ini bagian yang tidak bisa dipercepat.
Langkah 3 — Jalankan normalisasi di staging
Terapkan pipeline normalisasi. Simpan hasilnya di kolom terpisah, jangan menimpa data asli.
Kolom asli adalah jaring pengaman Anda.
Langkah 4 — Deduplikasi dengan review manusia
Jalankan blocking dan scoring. Keluarkan tiga bucket: auto-merge, review, distinct.
Bucket review wajib dilihat manusia yang paham barangnya. Biasanya orang gudang senior, bukan analis data.
Estimasi waktu: tergantung volume bucket review, umumnya 2-4 minggu.
Langkah 5 — Pasang gerbang validasi
Deploy skema Pydantic di semua jalur input. Uji dengan data yang sengaja dibuat salah.
Kalau data kotor masih bisa lolos, gerbangnya belum selesai.
Langkah 6 — Migrasi terkontrol
Terapkan hasil ke sistem produksi dengan mapping lama-ke-baru yang tersimpan permanen. Transaksi historis harus tetap bisa ditelusuri.
Jangan pernah menghapus SKU lama. Tandai sebagai MERGED_INTO.
Langkah 7 — Monitoring berkelanjutan
Jadwalkan job mingguan yang menghitung metrik kualitas dan mengirim alert kalau ada penurunan.
Tanpa langkah ini, enam bulan lagi Anda mengulang dari langkah satu.
7. Kesalahan yang Sering Terjadi
Beberapa jebakan yang saya lihat berulang di berbagai proyek. Sebagian terlihat sepele di awal, tapi biayanya muncul belakangan.
Auto-merge tanpa review
Godaan terbesar. Skornya 91, kelihatan mirip, langsung gabung.
Lalu ketahuan itu dua bearing dengan clearance berbeda. Salah satunya untuk aplikasi high-speed. Mesinnya rusak.
Menghapus SKU lama
Riwayat transaksi lima tahun jadi orphan. Analisis konsumsi jadi kacau. Audit tidak bisa menelusuri.
Selalu soft-delete dengan pointer ke SKU pengganti.
Menganggap ini proyek IT
Ini proyek engineering yang kebetulan pakai kode. Tanpa keterlibatan orang maintenance yang tahu bedanya 6205ZZ dan 6205RS, algoritma secanggih apa pun akan salah.
Mengabaikan bahasa campuran
Data di Indonesia penuh campuran Indonesia-Inggris-istilah lokal. "Laher", "seal", "gland packing", "vanbelt".
Pipeline yang hanya menangani bahasa Inggris akan melewatkan setengah duplikatnya.
8. Integrasi dengan Alur Kerja Modern
Setelah master data bersih, nilainya baru terasa saat dipakai sistem lain. Data bersih bukan tujuan akhir — ia adalah prasyarat untuk hal-hal yang lebih menarik.
Pencarian semantik untuk katalog
Dengan noun terstandar dan atribut terstruktur, Anda bisa membangun pencarian yang paham konteks. Vector embedding di atas data kotor menghasilkan hasil kotor; di atas data bersih, hasilnya jauh lebih akurat.
Prediksi kebutuhan sparepart
Model konsumsi hanya masuk akal kalau satu barang punya satu SKU. Duplikat memecah histori konsumsi jadi beberapa seri pendek yang tidak bisa dimodelkan.
Integrasi supplier dan e-procurement
Katalog terstandar memungkinkan pertukaran data otomatis dengan supplier. Ini juga fondasi teknis kalau Anda membangun katalog produk yang harus bisa dicrawl mesin pencari dengan benar — topik yang bersinggungan dengan performa frontend, dan untuk itu saya sarankan membaca panduan Core Web Vitals dari Addy Osmani, engineer Google yang banyak menulis soal performa web.
Traceability untuk audit
Setiap perubahan SKU tercatat. Setiap merge punya jejak. Ini yang dicari auditor saat verifikasi sistem manajemen aset.
FAQ
Berapa lama proyek standardisasi master data untuk 50.000 SKU?
Realistisnya 3-6 bulan untuk siklus penuh sampai monitoring berjalan. Yang memakan waktu bukan koding, tapi review manual bucket ambigu dan penyusunan vocabulary bersama tim lapangan.
Apakah bisa pakai LLM untuk deduplikasi?
Bisa membantu di tahap penyusunan vocabulary dan penanganan bahasa campuran. Tapi untuk keputusan merge, pendekatan deterministik berbasis part number tetap lebih aman dan bisa diaudit. LLM sebagai pengusul, manusia sebagai pemutus.
Bagaimana kalau part number dari supplier tidak konsisten?
Normalisasi part number secara terpisah: buang spasi, tanda hubung, dan prefix merek. Simpan versi asli dan versi ternormalisasi di kolom berbeda. Pencocokan pakai versi ternormalisasi, tampilan pakai versi asli.
Apakah perlu tools komersial atau cukup Python?
Untuk di bawah 100.000 SKU, Python dengan pandas dan rapidfuzz sudah lebih dari cukup. Tools komersial masuk akal kalau Anda punya banyak entitas legal, multi-plant dengan aturan berbeda, atau kebutuhan governance yang kompleks.
Bagaimana meyakinkan manajemen untuk mendanai ini?
Hitung biaya nyatanya: nilai stok mati akibat duplikat, frekuensi pembelian darurat, dan jam kerja yang habis mencari barang yang sebenarnya ada. Angka-angka ini biasanya cukup mengejutkan untuk membuka anggaran.
Apakah ini hanya relevan untuk pabrik besar?
Tidak. Justru di operasi menengah efeknya lebih terasa, karena tidak ada tim data khusus dan setiap pembelian darurat langsung memukul arus kas.
Data Bersih Adalah Keputusan, Bukan Kebetulan
Menutup artikel ini, ada satu hal yang perlu ditegaskan: tidak ada master data yang rapi karena kebetulan. Ia rapi karena seseorang memutuskan skemanya, menegakkan validasinya, dan menolak kompromi saat ada yang minta pengecualian "cuma sekali ini saja".
W. Edwards Deming, statistikawan Amerika yang metodenya menjadi fondasi revolusi kualitas manufaktur Jepang pascaperang dan melahirkan banyak praktik yang kini kita sebut continuous improvement, meninggalkan kalimat yang relevan persis untuk konteks ini:
"In God we trust; all others must bring data."
Deming tidak sedang bicara soal database. Ia sedang bicara soal budaya kerja — bahwa keputusan operasional harus berpijak pada bukti, bukan intuisi atau kebiasaan. Tapi kalimat itu punya konsekuensi teknis yang keras: data yang dibawa harus bisa dipercaya. Duplikat SKU, satuan tidak konsisten, dan penamaan bebas membuat data secara teknis ada, tapi secara praktis tidak layak jadi dasar keputusan. Relevansi Deming di sini bukan nostalgia — pendekatan sistemiknya terhadap variasi proses adalah persis yang dibutuhkan saat menstandarkan penamaan ribuan komponen di lingkungan pemeliharaan industri.
Mulai dari yang kecil. Satu kategori. Satu vocabulary. Satu gerbang validasi.
Lalu naikkan skalanya perlahan.
Artikel ini disusun berdasarkan praktik pengelolaan katalog komponen industri di lingkungan MRO. Untuk konteks operasional pengadaan sparepart industri di Indonesia, referensi lapangan diambil dari praktik PT Duta Swarna Dwipa, supplier B2B kebutuhan MRO yang beroperasi di Karawang, Jawa Barat.
Top comments (0)