RapidMiner tippek – Adatbázis-rendszer monitorozása
Nagyjából egy hónapja jelent meg az adatbányászati és prediktív analitikai eszközök idei, Gartner által készített szokásos kiértékelése, mely a RapidMiner esetén sok újdonságot illetve változást nem hozott.
A cég idén is a vezetők között szerepel, picit több vízióval. Őszintén szólva számomra kisebb meglepetés, hogy a Radoop felvásárlásával nem ugrottak valamelyest az előző évi értékelésükhöz képest, bár az igaz, hogy a Big Data képesség ma már alapvető tulajdonsággá vált egy adatelemző szoftver esetében. A csupán minimális változás egyik okaként többek között az általunk is többször említett “lack of documentation” is feltüntetésre került, amin ez a blogbejegyzés aligha változtat, mindenesetre az alábbiakban egy igen érdekes use-caseről olvashattok, aminek egyik apropója a szintén kb. egy hónapja megjelent Gartner adattárházakra vonatkozó elemzése, amin jószerével nagyvállalati adattárház cégek szerepelnek. De mi köze a RapidMiner-nek az adattárházakhoz?
Tegyük fel, hogy egy projekt során szükségünk van egy adattárházra, amibe eddig CSV fájlokban meglévő adatokat szeretnénk eltárolni, de ilyen-olyan okok miatt nem valamely kész megoldást nyújtó klasszikus IT cég csúcsterméket választjuk, hanem mi magunk építünk egy számunkra megfelelő adattárházat pl. PostgreSQL alapokon. Miután létrehoztuk a dimenzió- és ténytáblákat illetve kialakítottuk a teljes rendszert (ügyelve többek között a karakterkódolásra és az időzóna beállításra), következhet az adatok betöltése, aminek az egyik legegyszerűbb és nagyon jól automatizálható módja SQL nyelven speciális betöltőfüggvények írása. Ezeket egyszer lefuttatva vagy akár beütemezve tölthetők be az egyszeri vagy az időszakosan előálló adatok.
Itt most teszek egy kis kitérőt, hiszen érdemes megjegyezni, hogy az adatok betöltése RapidMiner folyamatokkal is megoldható, és bizonyos esetekben akár előnyösebb választás is lehet a fenti módszernél. Nyilván szakembere válogatja, hogy ki melyik technológiát preferálja jobban, de aki nagyjából egyformán otthon van mindkét nyelvet/eszközt illetően, hamar észreveszi, hogy az egyszerűbb struktúrájú adatokat sokkal könnyebb és gyorsabb betölteni SQL függvényekkel. Ha például csak néhány dimenziótáblába és egy ténytáblába kell betöltenünk adatokat viszonylag kevés feltétel ellenőrzésével, akkor semmiképp nem javasolt RapidMiner processzt készíteni SQL függvény helyett. Viszont ha jóval összetettebb feltételrendszer mellett kell adatokat betöltenünk, kezelve számos hibalehetőséget (például hiányzó értékeket), elvégezve néhány adattranszformációt, adatszármaztatást és aggregálást, naplózva bizonyos tevékenységeket és mindezt akár bemeneti paraméterekkel vezérelve, akkor a betöltő folyamatot – már csak az átláthatósága és karbantarthatósága miatt is – célszerűbb lehet pl. RapidMiner-ben létrehozni, ahol az RM processz fájl szintén ütemezhető egy szerveren a rendszeres adatbetöltés végett. Persze egy ilyen RapidMiner folyamat korántsem lesz egyszerű, egy-egy processz XML fájljának mérete simán elérheti az 1500-3000 kódsort is (ami egyáltalán nem kevés, sőt!), viszont jóval átláthatóbb, és ha egy év múlva módosítani kell valamit, valószínűleg nemigen kell fölötte napokat ücsörögni még akkor sem, ha esetleg már hosszabb ideje nem dolgoztunk RapidMiner-rel. A fentiek miatt, és mert konkrét feladatot sem definiáltam, így egy ilyen processz részletezésétől most eltekintek. Nem célom a két módszer hatékonyságának összevetése sem (nincs is most a tarsolyomban egy adattárház), és bár elsőre a legtöbben talán azt mondanák, hogy nyilván egy SQL script rég betölti az adatokat, mire a RapidMiner futtatókörnyezete feláll, de mondjuk 70 GB adatnál ez nem biztos, hogy így van. Ehhez természetesen szükséges az adatok előzetes feldarabolása, mert a RapidMiner bemenetére pár 100 MB-os CSV-nél nagyobbat aligha ajánlott engedni, viszont ezekkel meglepően gyorsan képes végezni. És a lényeg, hogy a RapidMiner ismertebb operátorai mellett a különböző exception, makró, log és adatbázis operátorokkal a fenti speciális adatbetöltés “könnyedén” megoldható.
Az adatbetöltés mellett felmerülhet igényként az adattárház “monitorozása” is, ami alatt most a klasszikus felügyelet helyett azt értjük, hogy szeretnénk valamilyen értesítést és leírást kapni arról, ha történt adatbetöltés a rendszerbe, illetve arról is, hogy az új adatok milyen változást eredményeztek az adattáblákban, mennyire térnek el az új adatok a korábbiaktól. Ez így persze egy elég általános megfogalmazás, úgyhogy százféle megoldása lehet. A feladat részletesebb specifikálása érdekében járjuk picit körül az adatbetöltés hibadetektálásának problémáját: adott egy adattárház, tele adattáblákkal, melyek között az idő elteltével akár új is felbukkanhat. Minden adattábla tekinthető egyedinek, mivel (kezdetben legalábbis) nem tudunk róluk semmilyen információt, így azt sem, hogy hány mezővel és rekorddal rendelkeznek, illetve milyen típusú értékeket tartalmazhatnak. Tegyük fel, hogy szeretnénk a betöltött adatokra vonatkozóan outlier detektálást, amihez egy bemeneti segédtáblában rendelkezésre áll, hogy mely adattábla mely oszlopain milyen intervallumok engedélyezettek. Ha nincs ilyen információ, akkor az abban az oszlopban lévő minden érték érvényes, vagyis nem kívülálló. A végeredményben pl. táblázatos formában az adattábla azonosító és az aktuális adatbetöltéshez tartozó minimális és maximális kulcs mellett tehát szeretnénk látni az egy-egy adattábla esetén meglévő intervallumhibák darabszámát, valamint, hogy hány darab “különbség” jelentkezett az előző ellenőrzés óta, illetve egy ebből a számból számított arányszámot is az adattábla mezőinek függvényében. Ezen arányszám és az intervallumhibák számának ismeretében állapíthatjuk meg, hogy vajon az újonnan betöltött adatok “lényegesen” eltérnek-e a korábban betöltött adatoktól, vagy sem. Az eredménytáblának célszerű tartalmaznia a korábbi ellenőrzések eredményeit is minden adattáblára, hogy összevethetők legyenek az aktuális elemzésnél kapott értékek a korábban kapott értékekkel.
“Különbség” pedig adattábla mezőnként akkor keletkezik, ha egy adott oszlopra a figyelembe vett egy-egy mérőszám egy paraméterben meghatározott mérték felett eltér a korábbi (vagy eddigi vagy első) adatbetöltés során számított azonos mérőszám értékétől. Egy oszlopnál maximálisan annyi különbség keletkezhet, ahány mérőszámot definiálunk, adattábla szinten pedig ez szummázódik a mezők darabszámára. Ezután már csak azt kell definiálni, hogy milyen mérőszámokat vegyünk figyelembe a “különbségek” összeszámolásához. Minden oszlopra vizsgálhatjuk az egyedi illetve a hiányzó értékek arányát az összes betöltött rekord függvényében, szöveges mezőkre kiszámíthatunk egy rakás változót a karakterhossz mellett, például hány olyan érték van a mezőben, amely csak decimális, kisbetűs, nagybetűs vagy speciális karaktert (illetve ezek kombinációit) tartalmaz, és ezen darabszámokból képezünk egy-egy arányszámot. A speciális karakterek vizsgálatához célszerű egy makróban megadni a magyar abc (vagy egyéb előforduló nyelv) ékezetes karaktereit (külön a kis és nagybetűket) unicode formában (pl. ‘á’ = \u00e1). Dátum értékeknél vizsgálhatjuk a minimum és maximum dátum között eltelt időt. Hasonlót számíthatunk numerikus értékekre is, valamint nézhetünk különböző statisztikai próbákat (pl. w-próba az átlagra, f-próba az eloszlásra). Valós értékeknél megvizsgálhatjuk a törtrész pontosságát is (vagyis a tizedesjegyek darabszámát). Ha ezeket az attribútumokat legeneráltuk, már csak meg kell nézni, hogy a belőlük származtatott arányszámok a paraméterben megadott értéktől nagyobb mértékben különböznek-e az adattáblába korábban betöltött adatok esetén jelentkező arányszámoktól, és ha igen, akkor keletkezett egy “különbség” arányszámonként (és mezőnként). Persze akár súlyozhatjuk is az eltéréseket, pl. a hiányzó értékekben való eltérés duplán számít.
Nos, ez a feladatleírás “picit” hosszúra és talán bonyolultra sikeredett így elsőre, de a jó hír, hogy mindez RapidMiner-ben megvalósítható, kezdve onnan, hogy az adattárházból beolvassuk a benne lévő adattáblák neveit, amikből eltávolítjuk a rendszertáblákat, mert azokat nem akarjuk elemezni. Nyilván szükségünk van a jogosultságok beolvasására is, hiszen csak olyan adattáblát tudunk elemezni, melyhez van olvasási jogunk. Ezután beolvashatók az elsődleges kulcsok nevei és maximális értékei, melyek alapján csak azokat az adattáblákat elemezzük, ahol ezen értékekben történt változás. Ehhez egy, a RapidMiner Repository-ban eltárolt segédtáblát használhatunk, melyet adatbetöltés esetén minden elemzés alkalmával frissíteni szükséges az elemzett adattábla kulcsának új értékével illetve új adattáblával is, ha került ilyen az adattárházba. Az elemzéseket adattáblánként végezzük egy Loop Values operátor segítségével, amiben beolvassuk az adott adattábla újonnan betöltött rekordjait, illetve a mezők adattípusát is. Ha az idegen kulcsokat nem szeretnénk elemezni, akkor azokat kiszűrjük (az elsődleges kulcsot értelemszerűen nem elemezzük). Az idegen kulcsokra azok elnevezéséből vagy a leírásából következtethetünk (legalábbis jól definiált adattárház esetén). Adattárházról lévén szó, jó eséllyel a dátum értékeket ki kell nyernünk a megfelelő dimenziótáblákból, majd adattípustól függően legeneráljuk a fent definiált arányszámokat külön a szöveges, numerikus és dátum típusú mezőkre. Az arányszámokat össze kell vetni a korábbi adatbetöltéshez tartozó arányszámokkal, és megnézni, hogy a különbség nagyobb-e, mint a paraméterben megadott érték. Ha ezekkel megvagyunk, jöhet az intervallum vizsgálat, ami numerikus és dátum típusú mezőknél egy egyszerű min-max feltétel ellenőrzés, majd következhet a kiszámított értékek egy táblázatba ágyazása és elmentése, ami a fentiek után már gyerekjáték. A létrehozott folyamatot célszerű az adatbetöltőkkel szinkronban beütemezni, így minden adatbetöltés után azonnal lefut az elemzés, ami többek között a performancia miatt nagyon nem elhanyagolható szempont, illetve így triviálisan megállapítható minden adatbetöltésre (bemeneti CSV fájlra), hogy a benne lévő adatok mennyire “jók”.
A létrehozott folyamat egyik előnye, hogy gyakorlatilag semmilyen előzetes információt nem követel meg az elemzéshez, különösen ha nem szeretnénk outlier detektálást (ha nem definiálunk intervallumokat, az elemzés akkor is lefut, ahol minden adattáblában pontosan 0 darab outlier érték lesz). A kívül eső értékek egy része egyébként jól definiált mérőszámok esetén is detektálható: pl. ha a bemeneti adatokban az adatbevitel során történt elgépelés miatt szerepel egy 2206-os évszám 2006 helyett, akkor a minimum és maximum dátum között eltelt idő nagymértékben különbözni fog a korábbi adatbetöltés ugyanezen értékétől. Természetesen a processz számos PostgreSQL specifikus elemet és lekérdezést tartalmaz, de ezek könnyen adaptálhatók más rendszerekre.
Egy ilyen processz megépítése nyilván nem egy fél napos munka, az eredmény itt is bőven 2-3000 kódsor közé tehető, így itt sem látom értelmét kódrészletek bemutatásának. Azonban remélhetőleg a fenti leírás jó illusztrációt ad arra vonatkozóan, hogy a “The RapidMiner platform supports an extensive breadth and depth of functionality” Gartner véleményezés mennyire helytálló, illetve arra vonatkozóan is, hogy adatbányászati feladatok mellett a tágabb data science világban is bátran használható a RapidMiner. Ezzel természetesen nem azt akarom mondani, hogy ez a legjobb megoldás erre a feladatra, de abban szinte biztos vagyok, hogy kevesen gondolták volna, hogy ilyen szintű problémák is egészen jól kezelhetők RapidMiner-rel.
Még egy jó tanács a végére: ilyen bonyolultságú processzek építésénél célszerű egyedi elnevezésekkel és kommentekkel ellátni a RapidMiner operátorokat, mert egy idő után már nem lesz annyira egyértelmű, hogy annak idején pontosan mit és miért is csináltunk. Kommentek a ‘Comment’ panelben írhatók minden operátorhoz külön-külön. (Ha nem találnád ezt a panelt: a View / Show View menüpont alatt kiválasztható.)
A kép forrása.