Data cleansing przed migracją - jak nie przenosić śmieci
Każda migracja sklepu B2B ma kuszący skrót: "weź wszystko ze starej bazy i wrzuć do nowej". Brzmi rozsądnie, oszczędza czas planowania, kończy się 3-6 miesiącami dodatkowej pracy w hypercare po cutoverze. Nieaktywni klienci od 2018 roku, 800 duplikatów SKU z błędnych importów, produkty bez kategorii, opisy ściągnięte z pierwszej wersji excela w 2014 roku - to wszystko jest balastem, który spowalnia wyszukiwarkę, myli klientów i fałszuje raporty. Widziałem migracje, w których 40% klientów w nowej bazie nigdy się nie zalogowało, bo nigdy nie planowało wrócić. Dobry data cleansing przed migracją wyrzuca 20-40% danych jako śmieci i sklep startuje na nowej platformie z czystym backendem. Inwestycja 4-8 tygodni przed migracją zwraca się trzykrotnie w pierwszym kwartale po cutoverze.
Spis treści (6)
Dlaczego migrujemy tylko wartościowe
Argument jest prosty: stara baza zawsze ma więcej śmieci, niż się zdaje na pierwszy rzut oka. Migracja "wszystkiego" to klonowanie problemów do nowej platformy. Po cutoverze okazuje się, że nowy sklep ma te same bóle co stary - tylko w nowszej wersji frameworka.
Co zazwyczaj wisi w bazie sklepu B2B z pięcioletnią historią. Produkty wycofane, ale wciąż w katalogu z flagą "active" - 10-30% katalogu. Duplikaty SKU powstałe z błędnych importów albo łączenia kategorii - 2-10%. Klienci nieaktywni powyżej 2 lat bez zamówienia - 30-50% bazy klientów. Zamówienia testowe sprzed launchu albo z debugowania, których nikt nie usunął - 1-3%. Kategorie puste albo z jednym produktem (porzucone pomysły marketingu) - 5-15%. Atrybuty produktów, których używa 5% katalogu - 30-50% definicji atrybutów. Promocje, kupony, kampanie wygasłe od lat - 90%+ tabel kampanii.
Koszt przeniesienia tego do nowej platformy ma kilka wymiarów. Wydajność - reindexer Magento iteruje przez wszystkie produkty, 100 tys. aktywnych plus 50 tys. wycofanych zajmuje mu 50% dłużej, bez żadnej wartości dla biznesu. Wyszukiwarka - klient szuka, dostaje produkty wycofane, frustracja i porzucenie. Raportowanie - "ilu mamy aktywnych klientów" - odpowiedź zafałszowana o 30% przez konta, które już nigdy nic nie kupią. UX panelu admina - merchandiser przewija 50 tys. wycofanych, żeby znaleźć 20 tys. aktywnych. Compliance - RODO wymaga "data minimization" i prawa do zapomnienia, nieaktywni klienci sprzed 10 lat to teoretycznie problem prawny.
ROI z cleansing wychodzi pozytywny prawie zawsze. Inwestycja 2-6 tygodni pracy data analyst plus biznesu. Zwrot: 30-50% szybsza platforma po migracji, łatwiejsze utrzymanie, czystsze raporty, mniej pytań od merchandiserów typu "czemu ten produkt jest w wyszukiwarce". Realne oszczędności miesięczne w czasie zespołu.
Audyt jakości katalogu
Pierwszy krok cleansingu to pomiar, nie szacowanie. Trzeba dokładnie wiedzieć, ile śmieci masz w bazie, zanim zaczniesz dyskusję, co z nimi zrobić.
Metryki, które wyciągam SQL-em z Magento:
-- Produkty bez nazwy lub z generyczną nazwą
SELECT COUNT(*) FROM catalog_product_entity_varchar
WHERE attribute_id = (SELECT attribute_id FROM eav_attribute WHERE attribute_code = 'name')
AND (value IS NULL OR value = '' OR value LIKE 'Produkt %');
-- Produkty bez opisu
SELECT COUNT(*) FROM catalog_product_entity
WHERE entity_id NOT IN (
SELECT entity_id FROM catalog_product_entity_text
WHERE attribute_id = X AND LENGTH(value) > 100
);
-- Produkty bez zdjęcia
SELECT COUNT(*) FROM catalog_product_entity
WHERE entity_id NOT IN (SELECT entity_id FROM catalog_product_entity_media_gallery_value_to_entity);
-- Produkty bez kategorii
SELECT COUNT(*) FROM catalog_product_entity
WHERE entity_id NOT IN (SELECT product_id FROM catalog_category_product);
-- Produkty bez stanu magazynowego od 2 lat
SELECT COUNT(*) FROM catalog_product_entity p
JOIN cataloginventory_stock_item s ON s.product_id = p.entity_id
WHERE s.qty = 0 AND s.updated_at < DATE_SUB(NOW(), INTERVAL 2 YEAR);
Dashboard quality, który zwykle dostarczam biznesowi przed migracją:
| Metryka | Magento przed | Cel po cleansingu |
|---|---|---|
| Produktów total | 80 000 | 55 000 |
| Z opisem (>100 znaków) | 60% | 95% |
| Ze zdjęciem | 75% | 98% |
| Przypisanych do kategorii | 88% | 100% |
| Z dostępnym stanem (lub planowany dropship) | 65% | 90% |
| Z unikalnym SKU | 99% | 100% |
| Z poprawnymi atrybutami | 70% | 95% |
Decyzje per próg, które wynikają z audytu. Powyżej 30% kategorii ma 1-5 produktów - reorganizacja taksonomii przy migracji, nie warto przenosić rozproszonego katalogu. Produkty bez zdjęcia - flaga "wymaga zdjęcia" przed publikacją w nowym sklepie, lista do merchandiserów. Produkty 0 stanu powyżej 2 lat bez zamówienia - archive, nie migrowane.
Mapowanie danych przy migracji - mapowanie wykonujesz po cleansingu, nie przed.
Duplikaty SKU - deduplikacja
Duplikaty SKU to klasyczny problem migracji. Powstają z trzech źródeł. Pierwsze - importy z błędami, ten sam SKU dodany dwa razy z drobnymi różnicami w nazwie. Drugie - łączenie sklepów, sklep A miał ART-001, sklep B miał ten sam produkt jako ART001. Trzecie - ręczne wpisywanie danych przez handlowca, literówki, niespójne formatowanie.
Wykrywanie duplikatów ma dwa poziomy.
Exact match jest banalny:
SELECT sku, COUNT(*) FROM catalog_product_entity
GROUP BY sku HAVING COUNT(*) > 1;
Łatwe do wykrycia, łatwe do połączenia. Decyzja redukuje się do "który rekord zostaje".
Fuzzy match wymaga więcej pracy, ale łapie znacznie więcej przypadków. Często duplikaty mają różne SKU, ale są tym samym produktem: ART-001 versus ART-0001 (zero prefix), KER-100 versus KER100 (bez myślnika), tknH-23 versus TKnH-23 (różnica case). Wykrywanie idzie skryptem w Pythonie z bibliotekami rapidfuzz albo fuzzywuzzy:
import pandas as pd
from rapidfuzz import fuzz
products = pd.read_csv('products.csv')
def find_duplicates(products, threshold=85):
duplicates = []
for i, p1 in products.iterrows():
for j, p2 in products.iterrows():
if i >= j:
continue
sku1 = p1['sku'].upper().replace('-', '').replace(' ', '')
sku2 = p2['sku'].upper().replace('-', '').replace(' ', '')
if fuzz.ratio(sku1, sku2) > threshold:
if fuzz.ratio(p1['name'], p2['name']) > 70:
duplicates.append((p1['sku'], p2['sku']))
return duplicates
Próg podobieństwa SKU 85% plus podobieństwo nazwy 70% daje sensowne wyniki, mało false positive. Próg niższy generuje za dużo kandydatów do ręcznego review, wyższy gubi realne duplikaty.
Workflow merge duplikatów ma pięć kroków. Wykrycie kandydatów (lista par SKU). Ręczny review przez merchandisera - czy to faktycznie ten sam produkt, czy podobny, ale różny. Decyzja, który SKU zostawiamy (zwykle ten z bogatszą kartoteką - więcej atrybutów, więcej zdjęć, dłuższy opis). Migracja danych: zamówienia historyczne mapowane na zachowany SKU, stany sumują się, atrybuty przenoszone z bogatszego rekordu. Redirect 301 dla URL-a usuniętego SKU, żeby nie psuć SEO.
Skala: typowy sklep B2B z 50 tys. SKU ma w bazie 500-2000 par duplikatów. Manualny review zajmuje 2-3 tygodnie pracy merchandisera. Bez review nie wolno automatycznie mergować, bo skrypt nie odróżni dwóch wariantów tej samej śruby M8 od dwóch różnych śrub o podobnych kodach.
Klienci nieaktywni - kasujemy czy archiwizujemy
Definicja "nieaktywnego" klienta to decyzja biznesowa, nie techniczna. W moich audytach używam czterech wymiarów łącznie: brak zamówienia przez X miesięcy (typowo 24), brak logowania przez Y miesięcy (typowo 18), brak otwarcia maili marketingowych, jeśli mierzysz, brak interakcji z handlowcem (notatki w CRM). Klient niespełniający wszystkich czterech kryteriów to twardo nieaktywny.
Co z nimi zrobić - cztery opcje, z różnym profilem ryzyka i pracy.
Migrujemy wszystkich. Plus: jasna polityka, klient się odezwie, wszystko zostaje, nic nie tracimy. Minus: 30-50% bazy to dead weight, raporty zafałszowane, pojemność systemu nieefektywnie wykorzystana. Sensowne dla mniejszych sklepów albo branż z bardzo długim cyklem życia klienta (sprzęt budowlany, gdzie klient kupuje raz na pięć lat).
Archiwizujemy nieaktywnych do osobnej tabeli. Plus: dane są, ale nie wpływają na raportowanie operacyjne. Minus: utrzymanie archiwum, kwestie RODO. Sensowne dla większości sklepów średniej wielkości.
Kasujemy z procedurą RODO. Plus: czysto, RODO-friendly, mniej do utrzymania. Minus: nie odzyskasz danych - jeśli klient wróci, historia stracona. Wymaga procedury z 30-dniowym grace period i powiadomieniem.
Anonimizujemy. Dane techniczne (zamówienia, kwoty) zostają dla raportów, personal info usunięte. Plus: zachowanie statystyk bez przetwarzania danych osobowych. Minus: tracisz potencjalne leady marketingowe. Często best of both worlds dla średnich sklepów.
Procedura, którą rekomenduję dla typowej migracji. Identyfikacja nieaktywnych powyżej 24 miesięcy bez zamówienia. Komunikacja: "Robimy reset bazy, jeśli chcesz zostać klientem - zaloguj się w ciągu 30 dni". Po 30 dniach: aktywne logowanie oznacza migrację do nowego sklepu, brak reakcji oznacza archiwizację do osobnej bazy (do raportów historycznych), dane osobowe anonimizowane po 12 miesiącach (RODO retention period).
Pułapki RODO, których warto być świadomym. Klient, który nigdy nie zamówił (założył konto, nigdy nie kupił) - prawnie nie musisz go przechowywać. Klient, który zamówił - musisz przechowywać dla celów księgowych (5 lat ustawowo) i do czasu cofnięcia zgody na przetwarzanie danych. Decyzja "kasujemy klienta sprzed 7 lat" - tak, jeśli upłynął obowiązkowy okres retencji.
Zamówienia - jak głęboko cofać historię
Zamówienia historyczne mają wartość, ale do pewnego momentu. Wartość krzywą można rozpisać czasowo.
Zamówienia z ostatnich 12 miesięcy są krytyczne: klient widzi w panelu, dział handlowy analizuje, raporty miesięczne i kwartalne na nich się opierają. 12-24 miesiące to nadal ważne dane - klient powtarza zamówienia, analiza trendów, ofertowanie. 24-60 miesięcy to okazjonalne wykorzystanie: yearly reporting, sales coaching, sprawdzanie historii ważnych klientów. Powyżej 60 miesięcy dane potrzebne tylko dla audytu i obowiązku prawnego.
Decyzja per okres, którą zwykle proponuję:
| Okres | Decyzja |
|---|---|
| 0-24 miesięcy | Pełna migracja (data, items, ceny, statusy) |
| 24-60 miesięcy | Migracja sumaryczna (data, total, klient) bez line items |
| Powyżej 60 miesięcy | Archive do osobnej DB, dostęp na specjalne życzenie |
Konsekwencje. Klient w panelu widzi pełną historię ostatnich 24 miesięcy plus podsumowania starszych okresów. Sales raporting ma pełne dane z 24 miesięcy plus sumarki ze starszych. Audyt albo specyficzny historical query (kontrola, sprawa sądowa) idzie do archive DB przez dedicated admin tool.
Wymogi prawne, których nie wolno pominąć. Faktura VAT przechowywana 5 lat (ustawa o podatku VAT). Dokumenty księgowe 5 lat. Korekty 5 lat. Dane osobowe klienta w zamówieniu - tak długo, jak zamówienie wymaga przechowywania.
Archive DB w mojej praktyce. Osobna instancja MySQL z partycjonowaniem per rok. Read-only po roku - żadnych update'ów ani delete'ów, tylko select. Backup raz na rok do storage typu S3 Glacier (tanio, ale slow restore). Restore na żądanie audytora albo kontroli skarbówki.
Plan cutover migracji - cleansing jest fazą przed cutover, nie po.
Decyzje biznesowe - kto akceptuje co wyrzucamy
Data cleansing to nie operacja techniczna - to seria decyzji biznesowych, które technologia tylko wykonuje. Brak jasnej własności tych decyzji generuje pretensje po cutoverze.
Kto powinien akceptować co, w mojej praktyce:
| Decyzja | Kto akceptuje |
|---|---|
| Lista nieaktywnych klientów do archiwizacji | Head of Sales plus CFO |
| Lista produktów wycofanych do usunięcia | Head of Procurement plus Merchandiser |
| Lista zamówień do archiwum | CFO plus Accounting Lead |
| Lista kategorii do reorganizacji | Marketing Manager plus UX |
| Polityka anonimizacji | DPO plus Legal |
Format decision document, którego używam, jest prosty, ale zostawia audit trail:
# Decision: Archiwizacja klientów nieaktywnych
Kontekst: Migracja z Magento 2.3 na 2.4.7. 12 tys. klientów ma powyżej 24 miesięcy bez zamówienia.
Propozycja:
1. Mail do wszystkich nieaktywnych: "Chcesz zostać klientem?"
2. 30 dni grace period
3. Klienci, którzy się zalogowali - migrowani
4. Klienci bez reakcji - archiwum, anonimizacja po 12 miesiącach
Wpływ:
- Aktywna baza: 8 tys. klientów (z 20 tys.)
- Wydajność: +25% szybkość sklepu (mniej rekordów do indeksowania)
- RODO: zgodnie z retention policy
Ryzyka:
- Niektórzy klienci wrócą i będą skarżyć "gdzie moja historia"
- Mitigation: archive accessible przez admin tool
Akceptacja:
- Head of Sales: ___________
- CFO: ___________
- DPO: ___________
Data wdrożenia: [data]
Pułapki braku formalnych decyzji. Zespół techniczny podejmuje decyzje biznesowe na własną odpowiedzialność - biznes potem narzeka po cutoverze. Brak audit trail, kto co zatwierdził. Trudność cofnięcia decyzji - po anonimizacji nie ma odwrotu, danych nie da się odzyskać.
Best practice: wszystkie decyzje cleansingu dokumentowane w Confluence albo Notion, akceptowane przez biznes z datą i podpisem, archived na okres migracji plus rok po.
FAQ
Czy mogę nie przenosić zamówień starszych niż 2 lata? Częściowo tak. Zamówienia powyżej 5 lat można archiwizować albo usuwać (RODO i ograniczenia księgowe minimalne). Zamówienia 2-5 lat archiwizujesz w osobnej bazie, dostęp na żądanie. Zamówienia poniżej 2 lat migrujesz pełne dla operacyjnego klienta. To nie jest decyzja czarno-biała, tylko stopniowa redukcja głębi danych.
Jak wykryć duplikaty produktów o różnych SKU?
Fuzzy matching - biblioteki rapidfuzz albo fuzzywuzzy w Pythonie. Porównaj SKU znormalizowane (bez znaków specjalnych, lowercase) plus nazwa plus EAN. Próg podobieństwa 80-90%, niżej generuje za dużo false positive. Manualny review każdego kandydata jest obowiązkowy - automatyka nigdy nie będzie 100% pewna.
Czy RODO pozwala mi skasować nieaktywnych klientów? Tak, RODO wymaga "data minimization" - dane przechowywane tylko do potrzeb i okresu retencji. Nieaktywni klienci powyżej 5 lat bez zamówienia: wymóg legalny do przechowywania wygasł po terminach księgowych. Procedura: powiadomienie 30 dni, opcja sprzeciwu, soft delete, final delete po 12 miesiącach.
Czy archive DB liczy się do compliance RODO? Tak - archive DB to wciąż "przetwarzanie danych osobowych", jeśli zawiera personal info. Trzy strategie. Anonimizacja przy archive (zostaje order summary bez danych osobowych). Pseudonimizacja (klient ma ID w archive, dane personal w osobnej DB z restricted access). Pełna encryption at rest dla archive z dostępem tylko dla audytora.
Ile czasu trwa typowy data cleansing przed migracją? Dla średniego sklepu B2B (50 tys. SKU, 20 tys. klientów, 200 tys. zamówień historycznych): 4-8 tygodni. Podział czasu: tydzień audytu, dwa tygodnie technicznego cleansing, dwa tygodnie review biznesu, tydzień finalizacji. Bez tego cleansing sama migracja trwa dwukrotnie dłużej w fazie hypercare, więc to nie jest oszczędność czasu, tylko jego przesunięcie.
Co dalej
- Migracje platform e-commerce: Migracje e-commerce
- Mapowanie danych: Mapowanie danych przy migracji
- Plan cutover: Plan cutover migracji
O autorze
Jakub Owsianka
Architekt rozwiązania silnika platform B2B. Zaczynał po stronie biznesu (własne sklepy), potem deweloper, dziś projektuje wdrożenia dla sklepów z katalogami w dziesiątkach tysięcy SKU. W ostatnich latach wdrożył AI-development w zespole i funkcjonalności oparte o AI bezpośrednio w silniku sklepu.
Czytaj dalej w temacie wydajności
Wszystkie wpisyMasz pytanie do tego artykułu?
Dodatkowy kontekst, problem z własnym wdrożeniem, druga opinia - napisz wprost. Odpowiadam osobiście w 1-2 dni robocze.