Kada imate Sber vagu. Korištenje Ab Initio sa Hive i GreenPlum

Prije nekog vremena suočili smo se s pitanjem odabira ETL alata za rad sa velikim podacima. Ranije korišteno Informatica BDM rješenje nam nije odgovaralo zbog ograničene funkcionalnosti. Njegova upotreba je svedena na okvir za pokretanje spark-submit komandi. Nije bilo mnogo analoga na tržištu koji su u principu bili sposobni da rade sa obimom podataka sa kojima se svakodnevno bavimo. Na kraju smo odabrali Ab Initio. Tokom pilot demonstracija, proizvod je pokazao vrlo veliku brzinu obrade podataka. Gotovo da nema informacija o Ab Initio na ruskom jeziku, pa smo odlučili da pričamo o našem iskustvu na Habréu.

Ab Initio ima mnogo klasičnih i neobičnih transformacija, čiji se kod može proširiti korištenjem vlastitog PDL jezika. Za mala preduzeća, tako moćan alat će verovatno biti preterani, a većina njegovih mogućnosti može biti skupa i neiskorišćena. Ali ako je vaša skala bliska Sberovljevoj, onda bi vam Ab Initio mogao biti zanimljiv.

Pomaže preduzeću da akumulira znanje na globalnom nivou i razvije ekosistem, a programeru da unapredi svoje veštine u ETL-u, unapredi svoje znanje u ljusci, pruža mogućnost da savlada PDL jezik, daje vizuelnu sliku procesa učitavanja i pojednostavljuje razvoj zbog obilja funkcionalnih komponenti.

U ovom postu ću govoriti o mogućnostima Ab Initia i dati uporedne karakteristike njegovog rada sa Hive i GreenPlumom.

  • Opis MDW okvira i rad na njegovom prilagođavanju za GreenPlum
  • Poređenje performansi Ab Initio između Hive i GreenPlum
  • Rad Ab Initio sa GreenPlumom u režimu skoro realnog vremena


Funkcionalnost ovog proizvoda je vrlo široka i zahtijeva dosta vremena za proučavanje. Međutim, uz odgovarajuće radne vještine i odgovarajuće postavke performansi, rezultati obrade podataka su vrlo impresivni. Korištenje Ab Initio za programera može pružiti zanimljivo iskustvo. Ovo je novi pogled na razvoj ETL-a, hibrid između vizuelnog okruženja i razvoja preuzimanja u jeziku nalik skripti.

Preduzeća razvijaju svoje ekosisteme i ovaj alat je zgodniji nego ikad. Uz Ab Initio, možete akumulirati znanje o svom trenutnom poslovanju i koristiti to znanje za proširenje starih i otvaranje novih poslova. Alternative Ab Initio uključuju okruženja za vizualni razvoj Informatica BDM i ne-vizualna razvojna okruženja Apache Spark.

Opis Ab Initio

Ab Initio, kao i drugi ETL alati, je kolekcija proizvoda.

Kada imate Sber vagu. Korištenje Ab Initio sa Hive i GreenPlum

Ab Initio GDE (Graphical Development Environment) je okruženje za programera u kojem on konfiguriše transformacije podataka i povezuje ih sa tokovima podataka u obliku strelica. U ovom slučaju, takav skup transformacija naziva se graf:

Kada imate Sber vagu. Korištenje Ab Initio sa Hive i GreenPlum

Ulazne i izlazne veze funkcionalnih komponenti su portovi i sadrže polja izračunata unutar transformacija. Nekoliko grafova povezanih tokovima u obliku strelica po redoslijedu njihovog izvođenja naziva se plan.

Postoji nekoliko stotina funkcionalnih komponenti, što je mnogo. Mnogi od njih su visoko specijalizovani. Mogućnosti klasičnih transformacija u Ab Initio su šire nego u drugim ETL alatima. Na primjer, Join ima više izlaza. Pored rezultata povezivanja skupova podataka, možete dobiti izlazne zapise ulaznih skupova podataka čiji ključevi nisu mogli biti povezani. Također možete dobiti odbijenice, greške i zapisnik operacije transformacije, koji se može čitati u istoj koloni kao tekstualna datoteka i obraditi s drugim transformacijama:

Kada imate Sber vagu. Korištenje Ab Initio sa Hive i GreenPlum

Ili, na primjer, možete materijalizirati prijemnik podataka u obliku tabele i čitati podatke iz njega u istoj koloni.

Postoje originalne transformacije. Na primjer, transformacija Scan ima funkcionalnost sličnu analitičkim funkcijama. Postoje transformacije sa samoobjašnjavajućim nazivima: Kreiraj podatke, Čitaj Excel, Normaliziraj, Sortiraj unutar grupa, Pokreni program, Pokreni SQL, Pridruži se DB-u, itd. Grafovi mogu koristiti parametre vremena izvođenja, uključujući mogućnost prosljeđivanja parametara od ili do operativni sistem. Datoteke sa gotovim skupom parametara koji se prosljeđuju na graf nazivaju se skupovi parametara (pseti).

Kao što se i očekivalo, Ab Initio GDE ima svoje vlastito spremište pod nazivom EME (Enterprise Meta Environment). Programeri imaju priliku da rade s lokalnim verzijama koda i provjeravaju svoj razvoj u centralnom spremištu.

Moguće je, tokom izvršavanja ili nakon izvršavanja grafa, kliknuti na bilo koji tok koji povezuje transformaciju i pogledati podatke koji su prošli između ovih transformacija:

Kada imate Sber vagu. Korištenje Ab Initio sa Hive i GreenPlum

Također je moguće kliknuti na bilo koji stream i vidjeti detalje praćenja - u koliko paralela je transformacija funkcionirala, koliko je redova i bajtova učitano u koju od paralela:

Kada imate Sber vagu. Korištenje Ab Initio sa Hive i GreenPlum

Moguće je izvođenje grafa podijeliti na faze i označiti da neke transformacije treba izvršiti prvo (u nultoj fazi), sljedeće u prvoj fazi, sljedeće u drugoj fazi itd.

Za svaku transformaciju možete odabrati takozvani raspored (gdje će se izvršiti): bez paralela ili u paralelnim nitima, čiji se broj može odrediti. Istovremeno, privremene datoteke koje Ab Initio kreira kada se transformacije izvode mogu se postaviti i u sistem datoteka servera i u HDFS.

U svakoj transformaciji, na osnovu zadanog predloška, ​​možete kreirati vlastitu skriptu u PDL-u, koja je pomalo poput ljuske.

Sa PDL-om možete proširiti funkcionalnost transformacija i, posebno, možete dinamički (u vrijeme izvođenja) generirati proizvoljne fragmente koda ovisno o parametrima vremena izvršavanja.

Ab Initio takođe ima dobro razvijenu integraciju sa OS-om preko ljuske. Konkretno, Sberbank koristi linux ksh. Možete razmjenjivati ​​varijable sa ljuskom i koristiti ih kao parametre grafa. Možete pozvati izvršenje Ab Initio grafova iz ljuske i administrirati Ab Initio.

Osim Ab Initio GDE, mnogi drugi proizvodi su uključeni u isporuku. Postoji sopstveni Operativni sistem sa tvrdnjom da se zove operativni sistem. Postoji Control>Centar gdje možete planirati i pratiti tokove preuzimanja. Postoje proizvodi za razvoj na primitivnijem nivou nego što Ab Initio GDE dozvoljava.

Opis MDW okvira i rad na njegovom prilagođavanju za GreenPlum

Zajedno sa svojim proizvodima, dobavljač isporučuje proizvod MDW (Metadata Driven Warehouse), koji je konfigurator grafova dizajniran da pomogne u tipičnim zadacima popunjavanja skladišta podataka ili trezora podataka.

Sadrži prilagođene (projektno specifične) parsere metapodataka i gotove generatore koda iz kutije.

Kada imate Sber vagu. Korištenje Ab Initio sa Hive i GreenPlum
Kao ulaz, MDW prima model podataka, konfiguracionu datoteku za postavljanje veze sa bazom podataka (Oracle, Teradata ili Hive) i neke druge postavke. Dio koji je specifičan za projekat, na primjer, postavlja model u bazu podataka. Dio proizvoda koji se ne proizvodi u kutiji generira grafikone i konfiguracijske datoteke za njih učitavanjem podataka u tablice modela. U ovom slučaju, grafovi (i pseti) se kreiraju za nekoliko načina inicijalizacije i inkrementalnog rada na ažuriranju entiteta.

U slučajevima Hive i RDBMS-a, generišu se različiti grafovi za inicijalizaciju i inkrementalno ažuriranje podataka.

U slučaju Hive, dolazni delta podaci su povezani preko Ab Initio Join sa podacima koji su bili u tabeli prije ažuriranja. Učitavači podataka u MDW (i u Hive i RDBMS) ne samo da ubacuju nove podatke iz delte, već i zatvaraju periode relevantnosti podataka čiji su primarni ključevi primili delta. Osim toga, morate prepisati nepromijenjeni dio podataka. Ali to se mora učiniti jer Hive nema operacije brisanja ili ažuriranja.

Kada imate Sber vagu. Korištenje Ab Initio sa Hive i GreenPlum

U slučaju RDBMS-a, grafovi za inkrementalno ažuriranje podataka izgledaju optimalnije, jer RDBMS imaju stvarne mogućnosti ažuriranja.

Kada imate Sber vagu. Korištenje Ab Initio sa Hive i GreenPlum

Primljena delta se učitava u međutabelu u bazi podataka. Nakon toga, delta se povezuje sa podacima koji su bili u tabeli prije ažuriranja. A to se radi pomoću SQL-a koristeći generirani SQL upit. Zatim, korištenjem SQL naredbi delete+insert, novi podaci iz delte se ubacuju u ciljnu tablicu i zatvaraju se periodi relevantnosti podataka čiji su primarni ključevi primili deltu.
Nema potrebe za prepisivanjem nepromijenjenih podataka.

Tako smo došli do zaključka da u slučaju Hive-a, MDW mora ići da prepiše cijelu tabelu jer Hive nema funkciju ažuriranja. I ništa bolje od potpunog ponovnog pisanja podataka kada je izmišljeno ažuriranje. U slučaju RDBMS-a, naprotiv, kreatori proizvoda su smatrali da je potrebno povezivanje i ažuriranje tabela povjeriti upotrebi SQL-a.

Za projekat u Sberbanci kreirali smo novu, višekratnu implementaciju učitavača baze podataka za GreenPlum. Ovo je urađeno na osnovu verzije koju MDW generiše za Teradata. Teradata, a ne Oracle, je bio taj koji je bio najbliži i najbolji za ovo, jer... je takođe MPP sistem. Metode rada, kao i sintaksa, Teradata i GreenPlum-a su se pokazale sličnima.

Primjeri MDW-kritičnih razlika između različitih RDBMS-ova su sljedeći. U GreenPlumu, za razliku od Teradata, prilikom kreiranja tabela morate napisati klauzulu

distributed by

Teradata piše:

delete <table> all

, a u GreenPlumu pišu

delete from <table>

U Oracleu, u svrhu optimizacije pišu

delete from t where rowid in (<соединение t с дельтой>)

, a Teradata i GreenPlum pišu

delete from t where exists (select * from delta where delta.pk=t.pk)

Također napominjemo da je za rad Ab Initio sa GreenPlumom bilo potrebno instalirati GreenPlum klijent na sve čvorove Ab Initio klastera. To je zato što smo se povezali na GreenPlum istovremeno sa svih čvorova u našem klasteru. A da bi čitanje iz GreenPlum-a bilo paralelno i da bi svaka paralelna Ab Initio nit čitala svoj dio podataka iz GreenPlum-a, morali smo postaviti konstrukciju koju razumije Ab Initio u odjeljak “gdje” SQL upita

where ABLOCAL()

i odredite vrijednost ove konstrukcije specificiranjem čitanja parametra iz baze podataka transformacije

ablocal_expr=«string_concat("mod(t.", string_filter_out("{$TABLE_KEY}","{}"), ",", (decimal(3))(number_of_partitions()),")=", (decimal(3))(this_partition()))»

, koji se kompajlira u nešto poput

mod(sk,10)=3

, tj. morate zatražiti GreenPlum sa eksplicitnim filterom za svaku particiju. Za druge baze podataka (Teradata, Oracle), Ab Initio može automatski izvršiti ovu paralelizaciju.

Poređenje performansi Ab Initio između Hive i GreenPlum

Sberbank je sprovela eksperiment da uporedi performanse MDW generisanih grafova u odnosu na Hive iu odnosu na GreenPlum. U sklopu eksperimenta, u slučaju Hive bilo je 5 čvorova na istom klasteru kao Ab Initio, au slučaju GreenPlum-a 4 čvora na posebnom klasteru. One. Hive je imao neku hardversku prednost u odnosu na GreenPlum.

Razmotrili smo dva para grafikona koji obavljaju isti zadatak ažuriranja podataka u Hive i GreenPlum. Istovremeno su pokrenuti i grafikoni koje je generirao MDW konfigurator:

  • početno opterećenje + inkrementalno učitavanje nasumično generiranih podataka u tablicu Hive
  • početno opterećenje + inkrementalno učitavanje nasumično generiranih podataka u istu GreenPlum tabelu

U oba slučaja (Hive i GreenPlum) pokrenuli su učitavanje u 10 paralelnih niti na istom Ab Initio klasteru. Ab Initio je sačuvao međupodatke za proračune u HDFS (u smislu Ab Initio, korišćen je MFS raspored koji koristi HDFS). Jedna linija nasumično generiranih podataka zauzimala je 200 bajtova u oba slučaja.

Rezultat je bio ovakav:

Košnica:

Početno učitavanje u košnici

Redovi su umetnuti
6 000 000
60 000 000
600 000 000

Trajanje inicijalizacije
preuzimanja u sekundi
41
203
1 601

Inkrementalno učitavanje u košnici

Broj dostupnih redova u
ciljna tabela na početku eksperimenta
6 000 000
60 000 000
600 000 000

Broj delta linija primijenjenih na
ciljna tabela tokom eksperimenta
6 000 000
6 000 000
6 000 000

Trajanje inkrementalnog
preuzimanja u sekundi
88
299
2 541

GreenPlum:

Početno učitavanje u GreenPlum

Redovi su umetnuti
6 000 000
60 000 000
600 000 000

Trajanje inicijalizacije
preuzimanja u sekundi
72
360
3 631

Inkrementalno učitavanje u GreenPlum-u

Broj dostupnih redova u
ciljna tabela na početku eksperimenta
6 000 000
60 000 000
600 000 000

Broj delta linija primijenjenih na
ciljna tabela tokom eksperimenta
6 000 000
6 000 000
6 000 000

Trajanje inkrementalnog
preuzimanja u sekundi
159
199
321

Vidimo da brzina početnog učitavanja u Hive i GreenPlum linearno zavisi od količine podataka i, zbog boljeg hardvera, nešto je brža za Hive nego za GreenPlum.

Inkrementalno učitavanje u Hiveu također linearno ovisi o količini prethodno učitanih podataka dostupnih u ciljnoj tablici i odvija se prilično sporo kako volumen raste. Ovo je uzrokovano potrebom da se u potpunosti prepiše ciljna tablica. To znači da primjena malih izmjena na ogromne tabele nije dobar slučaj upotrebe za Hive.

Inkrementalno učitavanje u GreenPlumu slabo zavisi od količine prethodno učitanih podataka dostupnih u ciljnoj tabeli i odvija se prilično brzo. To se dogodilo zahvaljujući SQL Joins-u i GreenPlum arhitekturi, koja omogućava operaciju brisanja.

Dakle, GreenPlum dodaje deltu koristeći metodu delete+insert, ali Hive nema operacije brisanja ili ažuriranja, tako da je cijeli niz podataka bio prisiljen da se u potpunosti prepiše tokom inkrementalnog ažuriranja. Poređenje ćelija označenih podebljanim slovima je najupečatljivije, jer odgovara najčešćoj opciji za korištenje resursa za preuzimanje. Vidimo da je GreenPlum pobijedio Hive u ovom testu za 8 puta.

Rad Ab Initio sa GreenPlumom u režimu skoro realnog vremena

U ovom eksperimentu ćemo testirati sposobnost Ab Initio-a da ažurira GreenPlum tablicu nasumično generiranim komadima podataka u skoro realnom vremenu. Razmotrimo GreenPlum tabelu dev42_1_db_usl.TESTING_SUBJ_org_finval, sa kojom ćemo raditi.

Koristit ćemo tri Ab Initio grafa za rad s njim:

1) Graph Create_test_data.mp – kreira datoteke podataka u HDFS sa 10 redova u 6 paralelnih niti. Podaci su nasumični, njihova struktura je organizovana za umetanje u našu tabelu

Kada imate Sber vagu. Korištenje Ab Initio sa Hive i GreenPlum

Kada imate Sber vagu. Korištenje Ab Initio sa Hive i GreenPlum

2) Graf mdw_load.day_one.current.dev42_1_db_usl_testing_subj_org_finval.pset – MDW generiran graf inicijalizacijom umetanja podataka u našu tablicu u 10 paralelnih niti (koriste se testni podaci generirani grafom (1))

Kada imate Sber vagu. Korištenje Ab Initio sa Hive i GreenPlum

3) Graph mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset – graf koji je generisao MDW za inkrementalno ažuriranje naše tabele u 10 paralelnih niti koristeći dio svježe primljenih podataka (delta) generiranih grafom (1)

Kada imate Sber vagu. Korištenje Ab Initio sa Hive i GreenPlum

Pokrenimo donju skriptu u NRT modu:

  • generirati 6 test linija
  • izvršite početno opterećenje ubacite 6 testnih redova u praznu tabelu
  • ponovite inkrementalno preuzimanje 5 puta
    • generirati 6 test linija
    • izvrši inkrementalno umetanje 6 testnih redova u tabelu (u ovom slučaju, valid_to_ts vrijeme isteka je postavljeno na stare podatke i noviji podaci sa istim primarnim ključem su umetnuti)

Ovaj scenario oponaša način stvarnog rada određenog poslovnog sistema - prilično veliki dio novih podataka pojavljuje se u realnom vremenu i odmah se ulijeva u GreenPlum.

Sada pogledajmo zapisnik skripte:

Započni Create_test_data.input.pset u 2020-06-04 11:49:11
Završi Create_test_data.input.pset u 2020-06-04 11:49:37
Započnite mdw_load.day_one.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 11:49:37
Završi mdw_load.day_one.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 11:50:42
Započni Create_test_data.input.pset u 2020-06-04 11:50:42
Završi Create_test_data.input.pset u 2020-06-04 11:51:06
Započnite mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 11:51:06
Završi mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 11:53:41
Započni Create_test_data.input.pset u 2020-06-04 11:53:41
Završi Create_test_data.input.pset u 2020-06-04 11:54:04
Započnite mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 11:54:04
Završi mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 11:56:51
Započni Create_test_data.input.pset u 2020-06-04 11:56:51
Završi Create_test_data.input.pset u 2020-06-04 11:57:14
Započnite mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 11:57:14
Završi mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 11:59:55
Započni Create_test_data.input.pset u 2020-06-04 11:59:55
Završi Create_test_data.input.pset u 2020-06-04 12:00:23
Započnite mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 12:00:23
Završi mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 12:03:23
Započni Create_test_data.input.pset u 2020-06-04 12:03:23
Završi Create_test_data.input.pset u 2020-06-04 12:03:49
Započnite mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 12:03:49
Završi mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 12:06:46

Ispada ova slika:

Graf
Vrijeme početka
Kraj vremena
dužina

Create_test_data.input.pset
04.06.2020 11: 49: 11
04.06.2020 11: 49: 37
00:00:26

mdw_load.day_one.current.
dev42_1_db_usl_testing_subj_org_finval.pset
04.06.2020 11: 49: 37
04.06.2020 11: 50: 42
00:01:05

Create_test_data.input.pset
04.06.2020 11: 50: 42
04.06.2020 11: 51: 06
00:00:24

mdw_load.regular.current.
dev42_1_db_usl_testing_subj_org_finval.pset
04.06.2020 11: 51: 06
04.06.2020 11: 53: 41
00:02:35

Create_test_data.input.pset
04.06.2020 11: 53: 41
04.06.2020 11: 54: 04
00:00:23

mdw_load.regular.current.
dev42_1_db_usl_testing_subj_org_finval.pset
04.06.2020 11: 54: 04
04.06.2020 11: 56: 51
00:02:47

Create_test_data.input.pset
04.06.2020 11: 56: 51
04.06.2020 11: 57: 14
00:00:23

mdw_load.regular.current.
dev42_1_db_usl_testing_subj_org_finval.pset
04.06.2020 11: 57: 14
04.06.2020 11: 59: 55
00:02:41

Create_test_data.input.pset
04.06.2020 11: 59: 55
04.06.2020 12: 00: 23
00:00:28

mdw_load.regular.current.
dev42_1_db_usl_testing_subj_org_finval.pset
04.06.2020 12: 00: 23
04.06.2020 12: 03: 23
00:03:00

Create_test_data.input.pset
04.06.2020 12: 03: 23
04.06.2020 12: 03: 49
00:00:26

mdw_load.regular.current.
dev42_1_db_usl_testing_subj_org_finval.pset
04.06.2020 12: 03: 49
04.06.2020 12: 06: 46
00:02:57

Vidimo da se 6 inkrementnih linija obrađuje za 000 minute, što je prilično brzo.
Ispostavilo se da su podaci u ciljnoj tabeli raspoređeni na sljedeći način:

select valid_from_ts, valid_to_ts, count(1), min(sk), max(sk) from dev42_1_db_usl.TESTING_SUBJ_org_finval group by valid_from_ts, valid_to_ts order by 1,2;

Kada imate Sber vagu. Korištenje Ab Initio sa Hive i GreenPlum
Možete vidjeti korespondenciju umetnutih podataka vremenu pokretanja grafikona.
To znači da možete pokrenuti inkrementalno učitavanje podataka u GreenPlum u Ab Initio sa vrlo visokom frekvencijom i promatrati veliku brzinu umetanja ovih podataka u GreenPlum. Naravno, neće biti moguće pokrenuti se jednom u sekundi, jer Ab Initio, kao i svaki ETL alat, zahtijeva vrijeme da se "pokrene" kada se pokrene.

zaključak

Ab Initio se trenutno koristi u Sberbanci za izgradnju objedinjenog semantičkog sloja podataka (ESS). Ovaj projekat podrazumijeva izgradnju objedinjene verzije stanja različitih bankarskih poslovnih subjekata. Informacije dolaze iz različitih izvora, čije su replike pripremljene na Hadoop-u. Na osnovu poslovnih potreba izrađuje se model podataka i opisuju transformacije podataka. Ab Initio učitava informacije u ESN i preuzeti podaci ne samo da su od interesa za poslovanje sami po sebi, već služe i kao izvor za izgradnju baza podataka. Istovremeno, funkcionalnost proizvoda vam omogućava da koristite različite sisteme kao prijemnik (Hive, Greenplum, Teradata, Oracle), što omogućava jednostavnu pripremu podataka za poslovanje u različitim formatima koji su mu potrebni.

Mogućnosti Ab Initia su široke, na primjer, uključeni MDW okvir omogućava izgradnju tehničkih i poslovnih istorijskih podataka iz kutije. Za programere, Ab Initio omogućava da ne izmišljaju točak, već da koriste mnoge postojeće funkcionalne komponente, koje su u suštini biblioteke potrebne za rad sa podacima.

Autor je stručnjak za profesionalnu zajednicu Sberbank SberProfi DWH/BigData. Profesionalna zajednica SberProfi DWH/BigData odgovorna je za razvoj kompetencija u oblastima kao što su Hadoop ekosistem, Teradata, Oracle DB, GreenPlum, kao i BI alati Qlik, SAP BO, Tableau itd.

izvor: www.habr.com

Dodajte komentar