KÄ lasÄ«t Å”o rakstu: Es atvainojos, ka teksts ir tik garÅ” un haotisks. Lai ietaupÄ«tu jÅ«su laiku, es katru nodaļu sÄku ar ievadu āKo es uzzinÄjuā, kas vienÄ vai divos teikumos apkopo nodaļas bÅ«tÄ«bu.
"VienkÄrÅ”i parÄdiet man risinÄjumu!" Ja vÄlaties tikai redzÄt, no kurienes esmu nÄcis, pÄrejiet uz nodaļu āKļūstot izgudrojoÅ”Äkamā, taÄu, manuprÄt, ir interesantÄk un noderÄ«gÄk lasÄ«t par neveiksmÄm.
Man nesen tika uzdots izveidot procesu liela apjoma neapstrÄdÄtu DNS sekvenÄu (tehniski SNP mikroshÄmas) apstrÄdei. NepiecieÅ”amÄ«ba bija Ätri iegÅ«t datus par noteiktu Ä£enÄtisko atraÅ”anÄs vietu (sauktu par SNP) turpmÄkai modelÄÅ”anai un citiem uzdevumiem. Izmantojot R un AWK, es varÄju tÄ«rÄ«t un sakÄrtot datus dabiskÄ veidÄ, ievÄrojami paÄtrinot vaicÄjumu apstrÄdi. Tas man nebija viegli un prasÄ«ja daudzus atkÄrtojumus. Å is raksts palÄ«dzÄs jums izvairÄ«ties no dažÄm manÄm kļūdÄm un parÄdÄ«s, ar ko es beidzu.
PirmkÄrt, daži ievada skaidrojumi.
Dati
MÅ«su universitÄtes Ä£enÄtiskÄs informÄcijas apstrÄdes centrs mums sniedza datus 25 TB TSV formÄtÄ. Es saÅÄmu tos sadalÄ«tus 5 pakotnÄs, saspiestas ar Gzip, katrÄ no kurÄm bija aptuveni 240 Äetru gigabaitu faili. KatrÄ rindÄ bija dati par vienu SNP no vienas personas. KopumÄ tika pÄrsÅ«tÄ«ti dati par ~2,5 miljoniem SNP un ~60 tÅ«kstoÅ”iem cilvÄku. Papildus SNP informÄcijai failos bija daudzas kolonnas ar cipariem, kas atspoguļo dažÄdas Ä«paŔības, piemÄram, lasÄ«Å”anas intensitÄti, dažÄdu alÄļu biežumu utt. KopumÄ bija aptuveni 30 kolonnas ar unikÄlÄm vÄrtÄ«bÄm.
mÄrÄ·is
TÄpat kÄ jebkurÄ datu pÄrvaldÄ«bas projektÄ, vissvarÄ«gÄkais bija noteikt, kÄ dati tiks izmantoti. Å ajÄ gadÄ«jumÄ mÄs galvenokÄrt atlasÄ«sim modeļus un darbplÅ«smas SNP, pamatojoties uz SNP. Tas nozÄ«mÄ, ka mums vienlaikus bÅ«s nepiecieÅ”ami dati tikai par vienu SNP. Man bija jÄiemÄcÄs pÄc iespÄjas vienkÄrÅ”Äk, ÄtrÄk un lÄtÄk izgÅ«t visus ierakstus, kas saistÄ«ti ar kÄdu no 2,5 miljoniem SNP.
KÄ to nedarÄ«t
CitÄjot piemÄrotu kliÅ”eju:
Es nekļūdÄ«jos tÅ«kstoÅ” reižu, es vienkÄrÅ”i atklÄju tÅ«kstoÅ” veidu, kÄ izvairÄ«ties no datu kopas parsÄÅ”anas vaicÄjumam draudzÄ«gÄ formÄtÄ.
Pirmais mÄÄ£inÄjums
Ko esmu iemÄcÄ«jies: Nav lÄta veida, kÄ vienÄ reizÄ parsÄt 25 TB.
ApgÅ«stot kursu āLielo datu apstrÄdes uzlabotas metodesā Vanderbiltas UniversitÄtÄ, es biju pÄrliecinÄts, ka triks ir somÄ. VisticamÄk, bÅ«s nepiecieÅ”ama stunda vai divas, lai iestatÄ«tu Hive serveri, lai tas palaistu visus datus un ziÅotu par rezultÄtu. TÄ kÄ mÅ«su dati tiek glabÄti AWS S3, es izmantoju pakalpojumu Athena, kas ļauj lietot Hive SQL vaicÄjumus S3 datiem. Jums nav jÄiestata/jÄizveido Hive klasteris, un jÅ«s arÄ« maksÄjat tikai par meklÄtajiem datiem.
Kad es parÄdÄ«ju Athena savus datus un to formÄtu, es veicu dažus testus ar Å”Ädiem vaicÄjumiem:
select * from intensityData limit 10;
Un Ätri saÅÄma labi strukturÄtus rezultÄtus. Gatavs.
LÄ«dz brÄ«dim, kad mÄÄ£inÄjÄm izmantot datus savÄ darbÄ...
Man tika lÅ«gts izÅemt visu SNP informÄciju, lai pÄrbaudÄ«tu modeli. Es izpildÄ«ju vaicÄjumu:
select * from intensityData
where snp = 'rs123456';
...un sÄka gaidÄ«t. PÄc astoÅÄm minÅ«tÄm un vairÄk nekÄ 4 TB pieprasÄ«to datu es saÅÄmu rezultÄtu. Athena iekasÄ maksu pÄc atrasto datu apjoma, 5 USD par terabaitu. TÄtad Å”is vienÄ«gais pieprasÄ«jums maksÄja 20 USD un astoÅas minÅ«tes gaidÄ«Å”anas. Lai modeli darbinÄtu ar visiem datiem, mums bija jÄgaida 38 gadi un jÄmaksÄ 50 miljoni ASV dolÄru.AcÄ«mredzot, tas mums nebija piemÄrots.
VajadzÄja izmantot Parketu...
Ko esmu iemÄcÄ«jies: Esiet piesardzÄ«gs attiecÄ«bÄ uz savu parketa failu izmÄru un to organizÄciju.
Vispirms mÄÄ£inÄju labot situÄciju, pÄrvÄrÅ”ot visus TSV uz Parketa vÄ«les. Tie ir Ärti darbam ar lielÄm datu kopÄm, jo āātajos esoÅ”Ä informÄcija tiek glabÄta kolonnu formÄ: katra kolonna atrodas savÄ atmiÅas/diska segmentÄ, atŔķirÄ«bÄ no teksta failiem, kuros rindÄs ir katras kolonnas elementi. Un, ja jums ir kaut kas jÄatrod, tad vienkÄrÅ”i izlasiet nepiecieÅ”amo kolonnu. TurklÄt katrs fails kolonnÄ saglabÄ vÄrtÄ«bu diapazonu, tÄdÄļ, ja meklÄtÄ vÄrtÄ«ba nav kolonnas diapazonÄ, Spark netÄrÄs laiku visa faila skenÄÅ”anai.
Es izpildÄ«ju vienkÄrÅ”u uzdevumu AWS lÄ«me lai pÄrvÄrstu mÅ«su TSV parketa formÄtÄ, un jaunos failus ievietoja programmÄ Athena. PagÄja apmÄram 5 stundas. Bet, izpildot pieprasÄ«jumu, tÄ aizpildÄ«Å”ana prasÄ«ja aptuveni tikpat daudz laika un nedaudz mazÄk naudas. Fakts ir tÄds, ka Spark, mÄÄ£inot optimizÄt uzdevumu, vienkÄrÅ”i izsaiÅoja vienu TSV gabalu un ievietoja to savÄ parketa daļÄ. Un tÄ kÄ katrs fragments bija pietiekami liels, lai saturÄtu visus daudzu cilvÄku ierakstus, katrs fails saturÄja visus SNP, tÄpÄc Spark bija jÄatver visi faili, lai iegÅ«tu nepiecieÅ”amo informÄciju.
Interesanti, ka Parketa noklusÄjuma (un ieteicamais) kompresijas veids, snappy, nav sadalÄms. TÄpÄc katrs izpildÄ«tÄjs bija iestrÄdzis pie uzdevuma izpakot un lejupielÄdÄt visu 3,5 GB datu kopu.
SapratÄ«sim problÄmu
Ko esmu iemÄcÄ«jies: kÄrtoÅ”ana ir sarežģīta, it Ä«paÅ”i, ja dati tiek izplatÄ«ti.
Man Ŕķita, ka tagad es sapratu problÄmas bÅ«tÄ«bu. Man vajadzÄja kÄrtot datus tikai pÄc SNP kolonnas, nevis pÄc cilvÄkiem. PÄc tam vairÄki SNP tiks saglabÄti atseviÅ”Ä·Ä datu gabalÄ, un pÄc tam Parketa funkcija "viedÄ" "atvÄrta tikai tad, ja vÄrtÄ«ba ir diapazonÄ" parÄdÄ«sies visÄ savÄ krÄÅ”ÅumÄ. DiemžÄl kÄrtoÅ”ana starp miljardiem rindu, kas izkaisÄ«tas klasterÄ«, izrÄdÄ«jÄs grÅ«ts uzdevums.
Es studÄju algoritmu stundÄ koledžÄ: āUh, nevienam nerÅ«p visu Å”o ŔķiroÅ”anas algoritmu skaitļoÅ”anas sarežģītÄ«baā
Es mÄÄ£inu kÄrtot kolonnÄ 20 TB #dzirksts tabula: "KÄpÄc tas aizÅem tik ilgu laiku?" #Datu zinÄtne cÄ«Åas.
AWS noteikti nevÄlas izsniegt atmaksu iemesla dÄļ āEs esmu izklaidÄ«gs studentsā. PÄc tam, kad es kÄrtoju Amazon Glue, tas darbojÄs 2 dienas un avarÄja.
KÄ ar sadalÄ«Å”anu?
Ko esmu iemÄcÄ«jies: Spark starpsienÄm jÄbÅ«t lÄ«dzsvarotÄm.
Tad man radÄs ideja sadalÄ«t datus hromosomÄs. Ir 23 no tiem (un vÄl vairÄki, ja Åem vÄrÄ mitohondriju DNS un nekartÄtos reÄ£ionus).
Tas ļaus jums sadalÄ«t datus mazÄkos gabalos. Ja skriptÄ Glue Spark eksportÄÅ”anas funkcijai pievienojat tikai vienu rindiÅu partition_by = "chr", tad dati jÄsadala segmentos.
Genoms sastÄv no daudziem fragmentiem, ko sauc par hromosomÄm.
DiemžÄl tas neizdevÄs. HromosomÄm ir dažÄdi izmÄri, kas nozÄ«mÄ dažÄdu informÄcijas apjomu. Tas nozÄ«mÄ, ka uzdevumi, ko Spark nosÅ«tÄ«ja darbiniekiem, nebija lÄ«dzsvaroti un tika pabeigti lÄni, jo daži mezgli pabeidza agri un bija dÄ«kstÄvÄ. TomÄr uzdevumi tika izpildÄ«ti. Bet, prasot vienu SNP, nelÄ«dzsvarotÄ«ba atkal radÄ«ja problÄmas. SNP apstrÄdes izmaksas lielÄkÄs hromosomÄs (tas ir, kur mÄs vÄlamies iegÅ«t datus) ir samazinÄjuÅ”Äs tikai aptuveni 10 reizes. Daudz, bet nepietiekami.
Ko darÄ«t, ja mÄs to sadalÄm vÄl mazÄkÄs daļÄs?
Ko esmu iemÄcÄ«jies: Nekad nemÄÄ£iniet izveidot 2,5 miljonus nodalÄ«jumu.
Es nolÄmu pilnÄ«bÄ rÄ«koties un sadalÄ«ju katru SNP. Tas nodroÅ”inÄja, ka starpsienas bija vienÄda izmÄra. TÄ BIJA SLIKTA IDEJA. Es izmantoju lÄ«mi un pievienoju nevainÄ«gu lÄ«niju partition_by = 'snp'. Uzdevums sÄkÄs un sÄka izpildÄ«t. Dienu vÄlÄk es pÄrbaudÄ«ju un redzÄju, ka S3 joprojÄm nekas nav rakstÄ«ts, tÄpÄc es nogalinÄju uzdevumu. Å Ä·iet, ka Glue ierakstÄ«ja starpposma failus slÄptÄ vietÄ S3, daudz failu, varbÅ«t pÄris miljonus. RezultÄtÄ mana kļūda maksÄja vairÄk nekÄ tÅ«kstoti dolÄru un neiepriecinÄja manu mentoru.
SadalīŔana + ŔķiroŔana
Ko esmu iemÄcÄ«jies: Å Ä·iroÅ”ana joprojÄm ir sarežģīta, tÄpat kÄ Spark noregulÄÅ”ana.
Mans pÄdÄjais sadalÄ«Å”anas mÄÄ£inÄjums bija saistÄ«ts ar hromosomu sadalÄ«Å”anu un pÄc tam katra nodalÄ«juma ŔķiroÅ”anu. TeorÄtiski tas paÄtrinÄtu katru vaicÄjumu, jo vÄlamajiem SNP datiem bija jÄatrodas dažos parketa gabalos noteiktÄ diapazonÄ. DiemžÄl pat sadalÄ«to datu ŔķiroÅ”ana izrÄdÄ«jÄs grÅ«ts uzdevums. RezultÄtÄ es pÄrgÄju uz EMR pielÄgotam klasterim un izmantoju astoÅus jaudÄ«gus gadÄ«jumus (C5.4xl) un Sparklyr, lai izveidotu elastÄ«gÄku darbplÅ«smu...
# Sparklyr snippet to partition by chr and sort w/in partition
# Join the raw data with the snp bins
raw_data
group_by(chr) %>%
arrange(Position) %>%
Spark_write_Parquet(
path = DUMP_LOC,
mode = 'overwrite',
partition_by = c('chr')
)
...tomÄr uzdevums joprojÄm nebija izpildÄ«ts. Es to konfigurÄju dažÄdos veidos: palielinÄju atmiÅas sadalÄ«jumu katram vaicÄjuma izpildÄ«tÄjam, izmantoju mezglus ar lielu atmiÅas apjomu, izmantoju apraides mainÄ«gos (apraides mainÄ«gos), bet katru reizi tie izrÄdÄ«jÄs puspasÄkumi, un pamazÄm sÄka izpildÄ«tÄji. izgÄzties, lÄ«dz viss apstÄsies.
Ko esmu iemÄcÄ«jies: Dažreiz Ä«paÅ”iem datiem ir nepiecieÅ”ami Ä«paÅ”i risinÄjumi.
Katram SNP ir pozÄ«cijas vÄrtÄ«ba. Tas ir skaitlis, kas atbilst bÄzu skaitam gar tÄ hromosomu. Tas ir jauks un dabisks veids, kÄ sakÄrtot mÅ«su datus. SÄkumÄ es gribÄju sadalÄ«t pa katras hromosomas reÄ£ioniem. PiemÄram, pozÄ«cijas 1 - 2000, 2001 - 4000 utt. Bet problÄma ir tÄ, ka SNP nav vienmÄrÄ«gi sadalÄ«ti pa hromosomÄm, tÄpÄc grupu lielumi bÅ«s ļoti atŔķirÄ«gi.
RezultÄtÄ es nonÄcu pie pozÄ«ciju sadalÄ«juma kategorijÄs (rangs). Izmantojot jau lejupielÄdÄtos datus, es izpildÄ«ju pieprasÄ«jumu iegÅ«t unikÄlo SNP, to pozÄ«ciju un hromosomu sarakstu. PÄc tam es sakÄrtoju datus katrÄ hromosomÄ un savÄcu SNP noteiktÄ lieluma grupÄs (tvertnÄ). PieÅemsim, ka katrs 1000 SNP. Tas man radÄ«ja SNP attiecÄ«bas starp grupÄm uz hromosomu.
Galu galÄ es izveidoju grupas (bin) no 75 SNP, iemesls tiks paskaidrots tÄlÄk.
Ko esmu iemÄcÄ«jies: Dzirksteļu apkopoÅ”ana ir Ätra, taÄu sadalÄ«Å”ana joprojÄm ir dÄrga.
Es gribÄju nolasÄ«t Å”o mazo (2,5 miljoni rindu) datu rÄmi pakalpojumÄ Spark, apvienot to ar neapstrÄdÄtajiem datiem un pÄc tam sadalÄ«t to ar tikko pievienoto kolonnu. bin.
# Join the raw data with the snp bins
data_w_bin <- raw_data %>%
left_join(sdf_broadcast(snp_to_bin), by ='snp_name') %>%
group_by(chr_bin) %>%
arrange(Position) %>%
Spark_write_Parquet(
path = DUMP_LOC,
mode = 'overwrite',
partition_by = c('chr_bin')
)
ES izmantoju sdf_broadcast(), tÄpÄc Spark zina, ka tai jÄnosÅ«ta datu rÄmis uz visiem mezgliem. Tas ir noderÄ«gi, ja dati ir mazi un nepiecieÅ”ami visiem uzdevumiem. PretÄjÄ gadÄ«jumÄ Spark cenÅ”as bÅ«t gudrs un pÄc vajadzÄ«bas izplata datus, kas var izraisÄ«t palÄninÄjumus.
Un atkal mana ideja neizdevÄs: kÄdu laiku uzdevumi strÄdÄja, pabeidza savienÄ«bu, un tad, tÄpat kÄ izpildÄ«tÄji, kas tika uzsÄkti sadalot, tie sÄka neizdoties.
AWK pievienoŔana
Ko esmu iemÄcÄ«jies: Neguli, kad tev mÄca pamatus. Noteikti kÄds jau ir atrisinÄjis jÅ«su problÄmu astoÅdesmitajos gados.
LÄ«dz Å”im visu manu neveiksmju ar Spark iemesls bija datu juceklis klasterÄ«. IespÄjams, situÄciju var uzlabot ar iepriekÅ”Äju apstrÄdi. Es nolÄmu mÄÄ£inÄt sadalÄ«t neapstrÄdÄtos teksta datus hromosomu kolonnÄs, tÄpÄc es cerÄju nodroÅ”inÄt Spark ar āiepriekÅ” sadalÄ«tiemā datiem.
Es meklÄju vietnÄ StackOverflow, kÄ sadalÄ«t pÄc kolonnu vÄrtÄ«bÄm, un atradu tik lieliska atbilde. Izmantojot AWK, varat sadalÄ«t teksta failu pÄc kolonnu vÄrtÄ«bÄm, ierakstot to skriptÄ, nevis nosÅ«tot rezultÄtus uz stdout.
Es uzrakstÄ«ju BaÅ”a skriptu, lai to izmÄÄ£inÄtu. LejupielÄdÄja vienu no iepakotajiem TSV un pÄc tam izsaiÅoja to, izmantojot gzip un nosÅ«tÄ«ts uz awk.
Ko esmu iemÄcÄ«jies: gnu parallel - tÄ ir maÄ£iska lieta, ikvienam vajadzÄtu to izmantot.
AtdalÄ«Å”anÄs bija diezgan lÄna un kad es sÄku htoplai pÄrbaudÄ«tu jaudÄ«gas (un dÄrgas) EC2 instances izmantoÅ”anu, izrÄdÄ«jÄs, ka izmantoju tikai vienu kodolu un apmÄram 200 MB atmiÅas. Lai atrisinÄtu problÄmu un nezaudÄtu daudz naudas, mums bija jÄizdomÄ, kÄ paralÄli veikt darbu. Par laimi, absolÅ«ti pÄrsteidzoÅ”Ä grÄmatÄ Datu zinÄtne komandrindÄ Es atradu Džerona Jansensa nodaļu par paralÄlizÄciju. No tÄ es uzzinÄju par gnu parallel, ļoti elastÄ«ga metode daudzpavedienu ievieÅ”anai Unix sistÄmÄ.
Kad es sÄku sadalÄ«Å”anu, izmantojot jauno procesu, viss bija kÄrtÄ«bÄ, bet joprojÄm bija vÄjÅ” kakls - S3 objektu lejupielÄde diskÄ nebija ļoti Ätra un nebija pilnÄ«bÄ paralÄla. Lai to labotu, es rÄ«kojos Å”Ädi:
Es uzzinÄju, ka ir iespÄjams ieviest S3 lejupielÄdes stadiju tieÅ”i konveijerÄ, pilnÄ«bÄ novÄrÅ”ot starpglabÄÅ”anu diskÄ. Tas nozÄ«mÄ, ka varu izvairÄ«ties no neapstrÄdÄtu datu ierakstÄ«Å”anas diskÄ un izmantot vÄl mazÄku un lÄ«dz ar to lÄtÄku krÄtuvi AWS.
komanda aws configure set default.s3.max_concurrent_requests 50 ievÄrojami palielinÄja AWS CLI izmantoto pavedienu skaitu (pÄc noklusÄjuma ir 10).
Es pÄrgÄju uz EC2 gadÄ«jumu, kas optimizÄts tÄ«kla Ätrumam un kura nosaukumÄ ir burts n. Es atklÄju, ka apstrÄdes jaudas zudumu, izmantojot n-gadÄ«jumus, vairÄk nekÄ kompensÄ ielÄdes Ätruma palielinÄÅ”anÄs. LielÄkajai daļai uzdevumu es izmantoju c5n.4xl.
MainÄ«ts gzip par pigz, Å”is ir gzip rÄ«ks, kas var darÄ«t lieliskas lietas, lai paralÄli sÄkotnÄji neparalÄlÄtajam failu atspieÅ”anas uzdevumam (tas palÄ«dzÄja vismazÄk).
# Let S3 use as many threads as it wants
aws configure set default.s3.max_concurrent_requests 50
for chunk_file in $(aws s3 ls $DATA_LOC | awk '{print $4}' | grep 'chr'$DESIRED_CHR'.csv') ; do
aws s3 cp s3://$batch_loc$chunk_file - |
pigz -dc |
parallel --block 100M --pipe
"awk -F 't' '{print $1",..."$30">"chunked/{#}_chr"$15".csv"}'"
# Combine all the parallel process chunks to single files
ls chunked/ |
cut -d '_' -f 2 |
sort -u |
parallel 'cat chunked/*_{} | sort -k5 -n -S 80% -t, | aws s3 cp - '$s3_dest'/batch_'$batch_num'_{}'
# Clean up intermediate data
rm chunked/*
done
Å Ä«s darbÄ«bas ir apvienotas viena ar otru, lai viss darbotos ļoti Ätri. Palielinot lejupielÄdes Ätrumu un novÄrÅ”ot ierakstÄ«Å”anu diskÄ, tagad es varÄtu apstrÄdÄt 5 terabaitu pakotni tikai dažÄs stundÄs.
Nav nekÄ jaukÄka par to, ka tiek izmantoti visi AWS kodoli, par kuriem maksÄjat. Pateicoties gnu-parallel, es varu izvilkt un sadalÄ«t 19 giga CSV failu tikpat Ätri, cik vien varu to lejupielÄdÄt. Es pat nevarÄju aizdegties, lai to palaistu. #Datu zinÄtne#Linuxpic.twitter.com/Nqyba2zqEk
Å ajÄ tvÄ«tÄ vajadzÄja pieminÄt "TSV". DiemžÄl.
Tiek izmantoti tikko parsÄtie dati
Ko esmu iemÄcÄ«jies: Spark patÄ«k nesaspiesti dati un nepatÄ«k apvienot nodalÄ«jumus.
Tagad dati bija S3 neizpakotÄ (lasÄ«t: koplietotÄ) un daļÄji pasÅ«tÄ«tÄ formÄtÄ, un es varÄju vÄlreiz atgriezties SparkÄ. Mani gaidÄ«ja pÄrsteigums: man atkal neizdevÄs sasniegt to, ko gribÄju! Bija ļoti grÅ«ti Spark precÄ«zi pateikt, kÄ dati tika sadalÄ«ti. Un pat tad, kad es to izdarÄ«ju, izrÄdÄ«jÄs, ka starpsienu bija pÄrÄk daudz (95 tÅ«kstoÅ”i), un kad es to izmantoju coalesce samazinÄja to skaitu lÄ«dz saprÄtÄ«gÄm robežÄm, tas iznÄ«cinÄja manu nodalÄ«jumu. Esmu pÄrliecinÄts, ka to var labot, taÄu pÄc pÄris dienu meklÄÅ”anas nevarÄju atrast risinÄjumu. Es beidzot pabeidzu visus uzdevumus SparkÄ, lai gan tas prasÄ«ja kÄdu laiku un mani sadalÄ«tie Parquet faili nebija ļoti mazi (~200 KB). TomÄr dati bija tur, kur tie bija vajadzÄ«gi.
Par mazu un nelīdzenu, brīniŔķīgi!
VietÄjo Spark vaicÄjumu pÄrbaude
Ko esmu iemÄcÄ«jies: Spark ir pÄrÄk lielas izmaksas, risinot vienkÄrÅ”as problÄmas.
LejupielÄdÄjot datus gudrÄ formÄtÄ, varÄju pÄrbaudÄ«t Ätrumu. Iestatiet R skriptu, lai palaistu lokÄlo Spark serveri, un pÄc tam ielÄdÄja Spark datu rÄmi no norÄdÄ«tÄs Parquet grupas krÄtuves (bin). Es mÄÄ£inÄju ielÄdÄt visus datus, bet nevarÄju panÄkt, lai Sparklyr atpazÄ«tu nodalÄ«jumu.
sc <- Spark_connect(master = "local")
desired_snp <- 'rs34771739'
# Start a timer
start_time <- Sys.time()
# Load the desired bin into Spark
intensity_data <- sc %>%
Spark_read_Parquet(
name = 'intensity_data',
path = get_snp_location(desired_snp),
memory = FALSE )
# Subset bin to snp and then collect to local
test_subset <- intensity_data %>%
filter(SNP_Name == desired_snp) %>%
collect()
print(Sys.time() - start_time)
Izpilde ilga 29,415 sekundes. Daudz labÄk, bet ne pÄrÄk labi kaut ko masveida testÄÅ”anai. TurklÄt es nevarÄju paÄtrinÄt darbu ar keÅ”atmiÅu, jo, mÄÄ£inot keÅ”atmiÅÄ saglabÄt datu rÄmi, Spark vienmÄr avarÄja, pat ja datu kopai, kas sver mazÄk par 50, pieŔķīru vairÄk nekÄ 15 GB atmiÅas.
Atgriezties uz AWK
Ko esmu iemÄcÄ«jies: AWK asociatÄ«vie masÄ«vi ir ļoti efektÄ«vi.
Sapratu, ka varu sasniegt lielÄku Ätrumu. Es to atcerÄjos brÄ«niŔķīgÄ BrÅ«sa BÄrneta AWK apmÄcÄ«ba Es lasÄ«ju par lielisku funkciju ar nosaukumu "asociatÄ«vie masÄ«vi" BÅ«tÄ«bÄ tie ir atslÄgu-vÄrtÄ«bu pÄri, kas nez kÄpÄc AWK tika saukti atŔķirÄ«gi, un tÄpÄc es kaut kÄ par tiem daudz nedomÄju. RomÄns Äepļaka atgÄdinÄja, ka termins āasociatÄ«vie masÄ«viā ir daudz vecÄks par terminu āatslÄgas vÄrtÄ«bu pÄrisā. Pat ja jÅ«s meklÄjiet atslÄgas vÄrtÄ«bu pakalpojumÄ Google Ngram, jÅ«s tur neredzÄsit Å”o terminu, bet jÅ«s atradÄ«sit asociatÄ«vus masÄ«vus! TurklÄt āatslÄgas-vÄrtÄ«bas pÄrisā visbiežÄk tiek saistÄ«ts ar datu bÄzÄm, tÄpÄc ir daudz saprÄtÄ«gÄk to salÄ«dzinÄt ar hashmap. Es sapratu, ka varu izmantot Å”os asociatÄ«vos masÄ«vus, lai saistÄ«tu savus SNP ar bin tabulu un neapstrÄdÄtiem datiem, neizmantojot Spark.
Lai to izdarÄ«tu, AWK skriptÄ es izmantoju bloku BEGIN. Å is ir koda fragments, kas tiek izpildÄ«ts, pirms pirmÄ datu rinda tiek nodota skripta galvenajai daļai.
Komanda while(getline...) ielÄdÄja visas rindas no CSV grupas (bin), iestatiet pirmo kolonnu (SNP nosaukumu) kÄ asociatÄ«vÄ masÄ«va atslÄgu bin un otrÄ vÄrtÄ«ba (grupa) kÄ vÄrtÄ«ba. PÄc tam blokÄ {}, kas tiek izpildÄ«ts visÄs galvenÄ faila rindÄs, katra rinda tiek nosÅ«tÄ«ta uz izvades failu, kas saÅem unikÄlu nosaukumu atkarÄ«bÄ no grupas (bin): ..._bin_"bin[$1]"_....
MainÄ«gie batch_num Šø chunk_id sakrita ar konveijera sniegtajiem datiem, izvairoties no sacensÄ«bu stÄvokļa un katra izpildes pavediena palaiÅ”anas parallel, rakstÄ«ja savÄ unikÄlajÄ failÄ.
TÄ kÄ es izkaisÄ«ju visus neapstrÄdÄtos datus mapÄs hromosomÄs, kas palika pÄri no mana iepriekÅ”ÄjÄ eksperimenta ar AWK, tagad es varÄtu uzrakstÄ«t citu Bash skriptu, lai apstrÄdÄtu vienu hromosomu vienlaikus un nosÅ«tÄ«tu dziļÄkus sadalÄ«tos datus uz S3.
DESIRED_CHR='13'
# Download chromosome data from s3 and split into bins
aws s3 ls $DATA_LOC |
awk '{print $4}' |
grep 'chr'$DESIRED_CHR'.csv' |
parallel "echo 'reading {}'; aws s3 cp "$DATA_LOC"{} - | awk -v chr=""$DESIRED_CHR"" -v chunk="{}" -f split_on_chr_bin.awk"
# Combine all the parallel process chunks to single files and upload to rds using R
ls chunked/ |
cut -d '_' -f 4 |
sort -u |
parallel "echo 'zipping bin {}'; cat chunked/*_bin_{}_*.csv | ./upload_as_rds.R '$S3_DEST'/chr_'$DESIRED_CHR'_bin_{}.rds"
rm chunked/*
Skriptam ir divas sadaļas parallel.
PirmajÄ sadaÄ¼Ä dati tiek nolasÄ«ti no visiem failiem, kas satur informÄciju par vÄlamo hromosomu, pÄc tam Å”ie dati tiek sadalÄ«ti pa pavedieniem, kas sadala failus atbilstoÅ”Äs grupÄs (bin). Lai izvairÄ«tos no sacensÄ«bu apstÄkļiem, kad vienÄ failÄ raksta vairÄki pavedieni, AWK nodod failu nosaukumus, lai rakstÄ«tu datus dažÄdÄs vietÄs, piemÄram, chr_10_bin_52_batch_2_aa.csv. RezultÄtÄ diskÄ tiek izveidoti daudzi mazi faili (Å”im nolÅ«kam izmantoju terabaitu EBS apjomus).
Konveijers no otrÄs sekcijas parallel iziet cauri grupÄm (bin) un apvieno to atseviŔķos failus kopÄjÄ CSV c catun pÄc tam nosÅ«ta tos eksportam.
Apraide R?
Ko esmu iemÄcÄ«jies: JÅ«s varat sazinÄties stdin Šø stdout no R skripta, un tÄpÄc izmantojiet to konveijerÄ.
JÅ«s, iespÄjams, pamanÄ«jÄt Å”o rindiÅu savÄ Bash skriptÄ: ...cat chunked/*_bin_{}_*.csv | ./upload_as_rds.R.... Tas pÄrvÄrÅ” visus sasaistÄ«tos grupu failus (bin) tÄlÄk esoÅ”ajÄ R skriptÄ. {} ir Ä«paÅ”a tehnika parallel, kas visus datus, ko tÄ sÅ«ta uz norÄdÄ«to straumi, ievieto tieÅ”i paÅ”Ä komandÄ. Opcija {#} nodroÅ”ina unikÄlu pavediena ID, un {%} apzÄ«mÄ darba vietas numuru (atkÄrtoti, bet nekad vienlaikus). Visu opciju sarakstu var atrast dokumentÄcija.
Kad mainÄ«gais file("stdin") pÄrsÅ«tÄ«ts uz readr::read_csv, dati, kas tulkoti R skriptÄ, tiek ielÄdÄti rÄmÄ«, kas pÄc tam atrodas formÄ .rds- failu izmantoÅ”ana aws.s3 rakstÄ«ts tieÅ”i uz S3.
RDS ir kaut kas lÄ«dzÄ«gs jaunÄkajai Parketa versijai bez skaļruÅu uzglabÄÅ”anas iespÄjÄm.
PÄc Bash skripta pabeigÅ”anas es saÅÄmu komplektu .rds-faili, kas atrodas S3, kas ļÄva man izmantot efektÄ«vu saspieÅ”anu un iebÅ«vÄtos veidus.
Neskatoties uz bremžu R izmantoÅ”anu, viss nostrÄdÄja ļoti Ätri. Nav pÄrsteidzoÅ”i, ka R daļas, kas lasa un raksta datus, ir ļoti optimizÄtas. PÄc pÄrbaudes vienÄ vidÄja izmÄra hromosomÄ C5n.4xl instancÄ darbs tika pabeigts aptuveni divÄs stundÄs.
S3 Ierobežojumi
Ko esmu iemÄcÄ«jies: Pateicoties viedÄ ceļa ievieÅ”anai, S3 var apstrÄdÄt daudzus failus.
Es uztraucos, vai S3 spÄs apstrÄdÄt daudzos failus, kas uz to tika pÄrsÅ«tÄ«ti. Es varÄtu padarÄ«t failu nosaukumus saprotamus, bet kÄ S3 tos meklÄtu?
S3 mapes ir paredzÄtas tikai demonstrÄÅ”anai, patiesÄ«bÄ sistÄma neinteresÄ simbolu /. No S3 FAQ lapas.
Å Ä·iet, ka S3 apzÄ«mÄ ceļu uz konkrÄtu failu kÄ vienkÄrÅ”u atslÄgu sava veida hash tabulÄ vai uz dokumentu balstÄ«tÄ datu bÄzÄ. Spaini var uzskatÄ«t par tabulu, un failus var uzskatÄ«t par ierakstiem Å”ajÄ tabulÄ.
TÄ kÄ Ätrums un efektivitÄte ir svarÄ«ga peļÅas gÅ«Å”anai Amazon, nav pÄrsteigums, ka Ŕī atslÄgas kÄ faila ceļa sistÄma ir ÄrkÄrtÄ«gi optimizÄta. MÄÄ£inÄju atrast lÄ«dzsvaru: lai man nebÅ«tu jÄiesniedz daudz pieprasÄ«jumu, bet lai pieprasÄ«jumi tiktu izpildÄ«ti Ätri. IzrÄdÄ«jÄs, ka vislabÄk ir izgatavot apmÄram 20 tÅ«kstoÅ”us bin failu. DomÄju, ka, ja turpinÄsim optimizÄt, varam panÄkt Ätruma pieaugumu (piemÄram, izveidojot speciÄlu spaini tikai datiem, tÄdÄjÄdi samazinot uzmeklÄÅ”anas tabulas izmÄru). TaÄu turpmÄkiem eksperimentiem nebija ne laika, ne naudas.
KÄ ir ar savstarpÄjo saderÄ«bu?
Ko es uzzinÄju: galvenais izŔķÄrdÄta laika iemesls ir priekÅ”laicÄ«ga uzglabÄÅ”anas metodes optimizÄÅ”ana.
Å ajÄ brÄ«dÄ« ir ļoti svarÄ«gi sev uzdot jautÄjumu: "KÄpÄc izmantot patentÄtu faila formÄtu?" Iemesls ir ielÄdes Ätrums (gzip CSV failu ielÄde prasÄ«ja 7 reizes ilgÄku laiku) un saderÄ«ba ar mÅ«su darbplÅ«smÄm. Es varu pÄrskatÄ«t, vai R var viegli ielÄdÄt Parketa (vai Arrow) failus bez Spark slodzes. Ikviens mÅ«su laboratorijÄ izmanto R, un, ja man ir nepiecieÅ”ams konvertÄt datus citÄ formÄtÄ, man joprojÄm ir oriÄ£inÄlie teksta dati, lai es varÄtu vienkÄrÅ”i palaist konveijeru vÄlreiz.
Darba sadale
Ko esmu iemÄcÄ«jies: NemÄÄ£iniet optimizÄt darbus manuÄli, ļaujiet to darÄ«t datoram.
Esmu atkļūdojis darbplÅ«smu vienÄ hromosomÄ, tagad man ir jÄapstrÄdÄ visi pÄrÄjie dati.
Es gribÄju izvirzÄ«t vairÄkus EC2 gadÄ«jumus konvertÄÅ”anai, taÄu tajÄ paÅ”Ä laikÄ es baidÄ«jos iegÅ«t ļoti nelÄ«dzsvarotu slodzi dažÄdos apstrÄdes darbos (tÄpat kÄ Spark cieta no nelÄ«dzsvarotÄm starpsienÄm). TurklÄt es neinteresÄjos palielinÄt vienu gadÄ«jumu katrÄ hromosomÄ, jo AWS kontiem noklusÄjuma ierobežojums ir 10 gadÄ«jumi.
Tad es nolÄmu uzrakstÄ«t skriptu R valodÄ, lai optimizÄtu apstrÄdes darbus.
PirmkÄrt, es palÅ«dzu S3 aprÄÄ·inÄt, cik daudz vietas katra hromosoma aizÅÄma.
library(aws.s3)
library(tidyverse)
chr_sizes <- get_bucket_df(
bucket = '...', prefix = '...', max = Inf
) %>%
mutate(Size = as.numeric(Size)) %>%
filter(Size != 0) %>%
mutate(
# Extract chromosome from the file name
chr = str_extract(Key, 'chr.{1,4}.csv') %>%
str_remove_all('chr|.csv')
) %>%
group_by(chr) %>%
summarise(total_size = sum(Size)/1e+9) # Divide to get value in GB
# A tibble: 27 x 2
chr total_size
<chr> <dbl>
1 0 163.
2 1 967.
3 10 541.
4 11 611.
5 12 542.
6 13 364.
7 14 375.
8 15 372.
9 16 434.
10 17 443.
# ā¦ with 17 more rows
Tad es uzrakstÄ«ju funkciju, kas Åem kopÄjo izmÄru, sajauc hromosomu secÄ«bu, sadala tÄs grupÄs num_jobs un norÄda, cik dažÄdi ir visu apstrÄdes darbu izmÄri.
num_jobs <- 7
# How big would each job be if perfectly split?
job_size <- sum(chr_sizes$total_size)/7
shuffle_job <- function(i){
chr_sizes %>%
sample_frac() %>%
mutate(
cum_size = cumsum(total_size),
job_num = ceiling(cum_size/job_size)
) %>%
group_by(job_num) %>%
summarise(
job_chrs = paste(chr, collapse = ','),
total_job_size = sum(total_size)
) %>%
mutate(sd = sd(total_job_size)) %>%
nest(-sd)
}
shuffle_job(1)
# A tibble: 1 x 2
sd data
<dbl> <list>
1 153. <tibble [7 Ć 3]>
Tad es skrÄju cauri tÅ«kstoÅ” jaukÅ”anas reizÄm, izmantojot purrr, un izvÄlÄjos labÄko.
TÄpÄc es nonÄcu pie uzdevumu kopuma, kas bija ļoti lÄ«dzÄ«ga izmÄra. Tad atlika tikai ietÄ«t manu iepriekÅ”Äjo BaÅ”a skriptu lielÄ cilpÄ for. Å Ä«s optimizÄcijas rakstÄ«Å”ana aizÅÄma apmÄram 10 minÅ«tes. Un tas ir daudz mazÄk, nekÄ es tÄrÄtu manuÄlai uzdevumu izveidei, ja tie bÅ«tu nelÄ«dzsvaroti. TÄpÄc es domÄju, ka man bija taisnÄ«ba ar Å”o sÄkotnÄjo optimizÄciju.
for DESIRED_CHR in "16" "9" "7" "21" "MT"
do
# Code for processing a single chromosome
fi
BeigÄs pievienoju izslÄgÅ”anas komandu:
sudo shutdown -h now
... un viss izdevÄs! Izmantojot AWS CLI, es izvirzÄ«ju gadÄ«jumus, izmantojot opciju user_data iedeva viÅiem apstrÄdei savu uzdevumu Bash skriptus. Tie darbojÄs un izslÄdzÄs automÄtiski, tÄpÄc es nemaksÄju par papildu apstrÄdes jaudu.
Ko esmu iemÄcÄ«jies: API ir jÄbÅ«t vienkÄrÅ”ai izmantoÅ”anas viegluma un elastÄ«bas labad.
Beidzot es saÅÄmu datus pareizajÄ vietÄ un formÄ. Atlika tikai pÄc iespÄjas vienkÄrÅ”ot datu izmantoÅ”anas procesu, lai kolÄÄ£iem bÅ«tu vieglÄk. Es gribÄju izveidot vienkÄrÅ”u API pieprasÄ«jumu izveidei. Ja nÄkotnÄ es izlemÅ”u pÄriet no .rds uz Parketa failiem, tad Å”ai problÄmai vajadzÄtu bÅ«t man, nevis maniem kolÄÄ£iem. Å im nolÅ«kam es nolÄmu izveidot iekÅ”Äjo R paketi.
Izveidojiet un dokumentÄjiet ļoti vienkÄrÅ”u pakotni, kurÄ ir tikai dažas datu piekļuves funkcijas, kas sakÄrtotas ap funkciju get_snp. Es arÄ« izveidoju vietni saviem kolÄÄ£iem pkgdown, lai viÅi varÄtu viegli skatÄ«t piemÄrus un dokumentÄciju.
ViedÄ keÅ”atmiÅa
Ko esmu iemÄcÄ«jies: Ja jÅ«su dati ir labi sagatavoti, saglabÄÅ”ana keÅ”atmiÅÄ bÅ«s vienkÄrÅ”a!
TÄ kÄ viena no galvenajÄm darbplÅ«smÄm izmantoja to paÅ”u analÄ«zes modeli SNP pakotnei, es nolÄmu izmantot binning savÄ labÄ. PÄrsÅ«tot datus, izmantojot SNP, visa informÄcija no grupas (bin) tiek pievienota atgrieztajam objektam. Tas nozÄ«mÄ, ka vecie vaicÄjumi var (teorÄtiski) paÄtrinÄt jaunu vaicÄjumu apstrÄdi.
# Part of get_snp()
...
# Test if our current snp data has the desired snp.
already_have_snp <- desired_snp %in% prev_snp_results$snps_in_bin
if(!already_have_snp){
# Grab info on the bin of the desired snp
snp_results <- get_snp_bin(desired_snp)
# Download the snp's bin data
snp_results$bin_data <- aws.s3::s3readRDS(object = snp_results$data_loc)
} else {
# The previous snp data contained the right bin so just use it
snp_results <- prev_snp_results
}
...
Veidojot pakotni, es izmantoju daudzus etalonus, lai salÄ«dzinÄtu Ätrumu, izmantojot dažÄdas metodes. Iesaku to neatstÄt novÄrtÄ, jo dažkÄrt rezultÄti ir negaidÄ«ti. PiemÄram, dplyr::filter bija daudz ÄtrÄk nekÄ rindu tverÅ”ana, izmantojot uz indeksÄÅ”anu balstÄ«tu filtrÄÅ”anu, un vienas kolonnas izgÅ«Å”ana no filtrÄta datu rÄmja bija daudz ÄtrÄka nekÄ indeksÄÅ”anas sintakses izmantoÅ”ana.
LÅ«dzu, Åemiet vÄrÄ, ka objekts prev_snp_results satur atslÄgu snps_in_bin. Å is ir visu unikÄlo SNP masÄ«vs grupÄ (bin), kas ļauj Ätri pÄrbaudÄ«t, vai jums jau ir dati no iepriekÅ”ÄjÄ vaicÄjuma. Tas arÄ« atvieglo visu grupas (bin) SNP cilpu, izmantojot Å”o kodu:
# Get bin-mates
snps_in_bin <- my_snp_results$snps_in_bin
for(current_snp in snps_in_bin){
my_snp_results <- get_snp(current_snp, my_snp_results)
# Do something with results
}
rezultÄtus
Tagad mÄs varam (un esam sÄkuÅ”i nopietni) palaist modeļus un scenÄrijus, kas mums iepriekÅ” nebija pieejami. LabÄkais ir tas, ka maniem laboratorijas kolÄÄ£iem nav jÄdomÄ par sarežģījumiem. ViÅiem vienkÄrÅ”i ir funkcija, kas darbojas.
Un, lai gan iepakojums viÅiem aiztaupa detaļas, es mÄÄ£inÄju padarÄ«t datu formÄtu pietiekami vienkÄrÅ”u, lai viÅi to varÄtu saprast, ja es rÄ«t pÄkÅ”Åi pazustu...
Ätrums manÄmi pieaudzis. MÄs parasti skenÄjam funkcionÄli nozÄ«mÄ«gus genoma fragmentus. IepriekÅ” mÄs to nevarÄjÄm izdarÄ«t (tas izrÄdÄ«jÄs pÄrÄk dÄrgi), bet tagad, pateicoties grupu (bin) struktÅ«rai un keÅ”atmiÅai, viena SNP pieprasÄ«jums vidÄji aizÅem mazÄk nekÄ 0,1 sekundi, un datu lietojums ir tik liels. zemas, ka S3 izmaksas ir zemesrieksti.
Nesen manÄ laboratorijÄ tika mainÄ«ts strÄ«ds par 25+ TB neapstrÄdÄtu genotipÄÅ”anas datu. Kad es sÄku, SNP vaicÄjuma izmantoÅ”ana aizÅÄma 8 minÅ«tes un maksÄja 20 $. PÄc AWK+ lietoÅ”anas #rstats apstrÄde tagad aizÅem mazÄk nekÄ 10 sekundes un maksÄ 0.00001 USD. Mans personÄ«gais #Lielie dati uzvarÄt. pic.twitter.com/ANOXVGrmkk
Å is raksts nepavisam nav ceļvedis. RisinÄjums izrÄdÄ«jÄs individuÄls un gandrÄ«z noteikti nav optimÄls. DrÄ«zÄk tas ir ceļojuma apraksts. Es vÄlos, lai citi saprastu, ka Å”Ädi lÄmumi nerodas lÄ«dz galam, tie ir izmÄÄ£inÄjumu un kļūdu rezultÄts. TurklÄt, ja meklÄjat datu zinÄtnieku, Åemiet vÄrÄ, ka Å”o rÄ«ku efektÄ«vai lietoÅ”anai ir nepiecieÅ”ama pieredze un pieredze maksÄ naudu. Esmu laimÄ«ga, ka man bija iespÄjas maksÄt, bet daudziem citiem, kas to paÅ”u darbu var izdarÄ«t labÄk par mani, naudas trÅ«kuma dÄļ nekad nebÅ«s iespÄjas pat mÄÄ£inÄt.
Lielo datu rÄ«ki ir daudzpusÄ«gi. Ja jums ir laiks, gandrÄ«z noteikti varat uzrakstÄ«t ÄtrÄku risinÄjumu, izmantojot viedas datu tÄ«rÄ«Å”anas, uzglabÄÅ”anas un ieguves metodes. Galu galÄ tas ir saistÄ«ts ar izmaksu un ieguvumu analÄ«zi.
Ko es uzzinÄju:
nav lÄta veida, kÄ vienÄ reizÄ parsÄt 25 TB;
esiet piesardzÄ«gs ar savu Parketa failu izmÄru un to organizÄciju;
Spark starpsienÄm jÄbÅ«t lÄ«dzsvarotÄm;
KopumÄ nekad nemÄÄ£iniet izveidot 2,5 miljonus nodalÄ«jumu;
Å Ä·iroÅ”ana joprojÄm ir sarežģīta, tÄpat kÄ Spark iestatÄ«Å”ana;
dažreiz Ä«paÅ”iem datiem ir nepiecieÅ”ami Ä«paÅ”i risinÄjumi;
Dzirksteļu apkopoÅ”ana ir Ätra, taÄu sadalÄ«Å”ana joprojÄm ir dÄrga;
neguli, kad tev mÄca pamatus, iespÄjams, kÄds jau ir atrisinÄjis tavu problÄmu astoÅdesmitajos gados;
gnu parallel - tÄ ir maÄ£iska lieta, tÄ jÄizmanto ikvienam;
Spark patīk nesaspiesti dati un nepatīk apvienot nodalījumus;
Spark ir pÄrÄk lielas izmaksas, risinot vienkÄrÅ”as problÄmas;
AWK asociatīvie masīvi ir ļoti efektīvi;
jÅ«s varat sazinÄties stdin Šø stdout no R skripta un tÄpÄc izmantojiet to konveijerÄ;
Pateicoties viedÄ ceļa ievieÅ”anai, S3 var apstrÄdÄt daudzus failus;
Galvenais laika tÄrÄÅ”anas iemesls ir priekÅ”laicÄ«ga uzglabÄÅ”anas metodes optimizÄÅ”ana;
nemÄÄ£iniet optimizÄt uzdevumus manuÄli, ļaujiet to darÄ«t datoram;
API ir jÄbÅ«t vienkÄrÅ”ai izmantoÅ”anas viegluma un elastÄ«bas labad;
Ja jÅ«su dati ir labi sagatavoti, keÅ”atmiÅas saglabÄÅ”ana bÅ«s vienkÄrÅ”a!