Fitur tina basa Q sareng KDB+ ngagunakeun conto layanan real-time

Anjeun tiasa maca ngeunaan naon dasar KDB +, basa pamrograman Q, naon kaunggulan sareng kalemahanana dina kuring sateuacana. artikel sareng singget dina bubuka. Dina artikel, urang bakal nerapkeun layanan dina Q anu bakal ngolah aliran data asup jeung ngitung rupa-rupa fungsi aggregation unggal menit dina mode "real time" (ie, éta bakal boga waktu keur ngitung sagalana saméméh porsi salajengna data). Fitur utama Q téh nya éta basa vektor nu ngidinan Anjeun pikeun beroperasi teu kalawan objék tunggal, tapi kalawan arrays maranéhanana, arrays of arrays sarta objék kompléks séjénna. Basa sapertos Q sareng barayana K, J, APL kasohor ku pondokna. Seringna, program anu nyandak sababaraha layar kode dina basa akrab sapertos Java tiasa ditulis dina sababaraha baris. Ieu anu kuring hoyong nunjukkeun dina tulisan ieu.

Fitur tina basa Q sareng KDB+ ngagunakeun conto layanan real-time

perkenalan

KDB+ mangrupikeun pangkalan data kolom anu difokuskeun kana jumlah data anu ageung pisan, diurutkeun ku cara anu khusus (utamana dumasar kana waktos). Hal ieu dipaké utamana di lembaga keuangan - bank, dana investasi, pausahaan asuransi. Basa Q nyaéta basa internal KDB+ anu ngamungkinkeun anjeun tiasa dianggo sacara efektif sareng data ieu. Idéologi Q nyaéta ringkes sareng efisiensi, sedengkeun kajelasan dikorbankeun. Ieu diyakinkeun ku kanyataan yén basa vektor bakal hese ngarti dina sagala hal, sarta brevity na richness rekaman ngidinan Anjeun pikeun ningali bagian loba nu leuwih gede tina program dina hiji layar, nu pamustunganana ngajadikeun eta gampang ngartos.

Dina artikel ieu kami nerapkeun program full-fledged di Q jeung anjeun bisa jadi hoyong nyobian kaluar. Jang ngalampahkeun ieu, anjeun bakal kudu Q sabenerna. Anjeun tiasa ngundeur versi 32-bit bébas dina ramatloka kx parusahaan - www.kx.com. Aya, upami anjeun kabetot, anjeun bakal mendakan inpormasi rujukan ngeunaan Q, buku Q Pikeun Mortals jeung sagala rupa artikel dina topik ieu.

Ngarumuskeun masalah

Aya sumber nu ngirim tabel kalawan data unggal 25 milliseconds. Kusabab KDB + dipaké utamana dina keuangan, urang bakal nganggap yén ieu téh tabel transaksi (trades), nu boga kolom handap: waktu (waktu dina milliseconds), sym (designation parusahaan di bursa saham - IBM, AAPL,…), harga (harga dimana saham dibeuli), ukuran (ukuran transaksi). Interval 25 milidetik sawenang-wenang, henteu leutik teuing sareng henteu panjang teuing. Ayana ngandung harti yén data datang ka layanan geus buffered. Ieu bakal gampang pikeun nerapkeun buffering dina sisi jasa, kaasup buffering dinamis gumantung kana beban ayeuna, tapi pikeun kesederhanaan, urang bakal difokuskeun interval tetep.

Ladenan kedah ngitung unggal menit pikeun tiap simbol anu asup tina kolom sym sakumpulan fungsi ngahijikeun - harga max, harga rata-rata, ukuran jumlah, jsb. informasi mangpaat. Pikeun kesederhanaan, urang bakal nganggap yén sakabéh fungsi bisa diitung incrementally, i.e. Pikeun ménta hiji nilai anyar, éta cukup uninga dua angka - heubeul jeung nilai asup. Contona, fungsi max, rata, jumlah boga sipat ieu, tapi fungsi median henteu.

Urang ogé bakal nganggap yén aliran data asup téh waktu maréntahkeun. Ieu bakal masihan urang kasempetan pikeun ngan ukur damel sareng menit terakhir. Dina prakna, cukup pikeun tiasa damel sareng menit ayeuna sareng sateuacana upami sababaraha apdet telat. Pikeun kesederhanaan, urang moal nganggap hal ieu.

Fungsi Aggregation

Fungsi agrégasi diperlukeun dibéréndélkeun di handap. Kuring nyandak saloba mungkin pikeun ningkatkeun beban dina jasa:

  • luhur - harga max - harga maksimum per menit.
  • low – harga mnt – harga minimum per menit.
  • firstPrice – harga kahiji – harga kahiji per menit.
  • harga panungtungan - harga panungtungan - harga panungtungan per menit.
  • firstSize - ukuran munggaran - ukuran dagang munggaran per menit.
  • lastSize - ukuran panungtungan - ukuran dagang panungtungan dina menit.
  • numTrades - cacah i - Jumlah trades per menit.
  • volume - jumlah ukuran - jumlah tina ukuran dagang per menit.
  • pvolume – jumlah harga – jumlah harga per menit, diperlukeun pikeun avgPrice.
  • – jumlah harga omzet*ukuran – total volume transaksi per menit.
  • avgPrice – pvolume%numTrades – harga rata-rata per menit.
  • avgSize - volume%numTrades - rata-rata ukuran dagang per menit.
  • vwap - volume elehan% - harga rata-rata per menit ditimbang ku ukuran transaksi.
  • cumVolume - jumlah volume - akumulasi ukuran transaksi sapanjang waktos.

Hayu urang langsung bahas hiji titik anu teu jelas - kumaha ngamimitian kolom ieu pikeun kahiji kalina sareng unggal menit salajengna. Sababaraha kolom tina jinis FirstPrice kedah diinisialisasi janten null unggal waktos; nilaina henteu ditangtukeun. Jinis volume anu sanés kedah disetél ka 0. Aya ogé kolom anu peryogi pendekatan gabungan - contona, cumVolume kedah disalin ti menit sateuacana, sareng kanggo anu munggaran disetel ka 0. Hayu urang nyetél sadaya parameter ieu nganggo data kamus. tipe (analog jeung rékaman):

// list ! list – создать словарь, 0n – float null, 0N – long null, `sym – тип символ, `sym1`sym2 – список символов
initWith:`sym`time`high`low`firstPrice`lastPrice`firstSize`lastSize`numTrades`volume`pvolume`turnover`avgPrice`avgSize`vwap`cumVolume!(`;00:00;0n;0n;0n;0n;0N;0N;0;0;0.0;0.0;0n;0n;0n;0);
aggCols:reverse key[initWith] except `sym`time; // список всех вычисляемых колонок, reverse объяснен ниже

Kuring ditambahkeun sym jeung waktu kana kamus pikeun genah, ayeuna initWith mangrupakeun garis siap-dijieun tina tabel aggregated final, dimana eta tetep nyetel sym bener jeung waktu. Anjeun tiasa make eta pikeun nambahkeun baris anyar ka méja.

Urang bakal butuh aggCols nalika nyieun hiji fungsi aggregation. Daptar kudu dibalikkeun kusabab urutan ekspresi dina Q dievaluasi (ti katuhu ka kenca). Tujuanana nyaéta pikeun mastikeun itungan ti luhur ka cumVolume, sabab sababaraha kolom gumantung kana anu sateuacana.

Kolom anu kedah disalin kana menit énggal ti anu saacanna, kolom sym ditambah pikeun genah:

rollColumns:`sym`cumVolume;

Ayeuna hayu urang ngabagi kolom kana grup dumasar kana kumaha aranjeunna kedah diropéa. Tilu jenis bisa dibédakeun:

  1. Accumulators (volume, elehan, ..) - urang kudu nambahan nilai asup ka saméméhna.
  2. Kalawan titik husus (luhur, low, ..) - nilai munggaran dina menit dicokot tina data asup, sésana diitung ngagunakeun fungsi.
  3. Istirahat. Salawasna diitung ngagunakeun fungsi.

Hayu urang ngartikeun variabel pikeun kelas ieu:

accumulatorCols:`numTrades`volume`pvolume`turnover;
specialCols:`high`low`firstPrice`firstSize;

Urutan itungan

Urang bakal ngamutahirkeun tabel aggregated dina dua tahap. Pikeun efisiensi, mimitina urang ngaleutikan tabel asup jadi ngan aya hiji baris pikeun tiap karakter jeung menit. Kanyataan yén sakabéh fungsi urang téh incremental na associative jaminan yén hasil tina hambalan tambahan ieu moal robah. Anjeun tiasa ngaleutikan méja nganggo pilih:

select high:max price, low:min price … by sym,time.minute from table

Metoda ieu boga kalemahan - susunan kolom diitung geus siap. Untungna, dina Q, pilih ogé dilaksanakeun salaku fungsi dimana anjeun tiasa ngagantikeun argumen dinamis dijieun:

?[table;whereClause;byClause;selectClause]

Kuring moal ngajelaskeun sacara rinci format argumen; dina kasus urang, ngan ukur ku sareng pilih éksprési anu henteu penting sareng aranjeunna kedah janten kamus tina bentuk kolom!ekspresi. Ku kituna, fungsi nyusut bisa dihartikeun kieu:

selExpression:`high`low`firstPrice`lastPrice`firstSize`lastSize`numTrades`volume`pvolume`turnover!parse each ("max price";"min price";"first price";"last price";"first size";"last size";"count i";"sum size";"sum price";"sum price*size"); // each это функция map в Q для одного списка
preprocess:?[;();`sym`time!`sym`time.minute;selExpression];

Pikeun kajelasan, I dipaké fungsi parse, nu kabukti string kalawan éksprési Q kana nilai nu bisa diliwatan mun fungsi eval jeung nu diperlukeun dina fungsi pilih. Catet ogé yén preprocess dihartikeun salaku proyéksi (nyaéta, fungsi kalayan argumen sawaréh diartikeun) tina fungsi pilih, hiji argumen (tabel) leungit. Upami urang nerapkeun preprocess kana méja, urang bakal kéngingkeun méja anu dikomprés.

Tahap kadua ngamutahirkeun tabel aggregated. Hayu urang mimiti nulis algoritma dina pseudocode:

for each sym in inputTable
  idx: row index in agg table for sym+currentTime;
  aggTable[idx;`high]: aggTable[idx;`high] | inputTable[sym;`high];
  aggTable[idx;`volume]: aggTable[idx;`volume] + inputTable[sym;`volume];
  …

Dina Q, geus ilahar ngagunakeun map / fungsi ngurangan tinimbang loop. Tapi kumargi Q mangrupikeun basa vektor sareng urang tiasa kalayan gampang nerapkeun sadaya operasi ka sadaya simbol sakaligus, teras kana perkiraan anu munggaran urang tiasa ngalakukeun tanpa loop, ngalaksanakeun operasi dina sadaya simbol sakaligus:

idx:calcIdx inputTable;
row:aggTable idx;
aggTable[idx;`high]: row[`high] | inputTable`high;
aggTable[idx;`volume]: row[`volume] + inputTable`volume;
…

Tapi urang tiasa langkung jauh, Q gaduh operator anu unik sareng kuat - operator ngerjakeun umum. Éta ngamungkinkeun anjeun ngarobih sakumpulan nilai dina struktur data kompleks nganggo daptar indéks, fungsi sareng argumen. Dina kasus urang, éta kasampak kawas kieu:

idx:calcIdx inputTable;
rows:aggTable idx;
// .[target;(idx0;idx1;..);function;argument] ~ target[idx 0;idx 1;…]: function[target[idx 0;idx 1;…];argument], в нашем случае функция – это присваивание
.[aggTable;(idx;aggCols);:;flip (row[`high] | inputTable`high;row[`volume] + inputTable`volume;…)];

Hanjakal, pikeun napelkeun ka méja anjeun peryogi daptar baris, teu kolom, jeung anjeun kudu transpose matrix (daptar kolom kana daptar baris) ngagunakeun fungsi flip. Ieu mahal pikeun méja ageung, janten gantina urang nerapkeun tugas umum pikeun tiap kolom nyalira, nganggo fungsi peta (anu sapertos tanda kutip):

.[aggTable;;:;]'[(idx;)each aggCols; (row[`high] | inputTable`high;row[`volume] + inputTable`volume;…)];

Urang deui ngagunakeun proyéksi fungsi. Ogé dicatet yén dina Q, nyieun daptar ogé fungsi sarta kami bisa nelepon deui ngagunakeun unggal (peta) fungsi pikeun meunangkeun daptar daptar.

Pikeun mastikeun yén susunan kolom diitung henteu tetep, urang bakal nyieun ekspresi luhur dinamis. Hayu urang ngartikeun heula fungsi pikeun ngitung unggal kolom, nganggo baris sareng variabel inp pikeun ngarujuk kana data agrégat sareng input:

aggExpression:`high`low`firstPrice`lastPrice`firstSize`lastSize`avgPrice`avgSize`vwap`cumVolume!
 ("row[`high]|inp`high";"row[`low]&inp`low";"row`firstPrice";"inp`lastPrice";"row`firstSize";"inp`lastSize";"pvolume%numTrades";"volume%numTrades";"turnover%volume";"row[`cumVolume]+inp`volume");

Sababaraha kolom anu husus; nilai kahiji maranéhanana teu kudu diitung ku fungsi. Urang bisa nangtukeun yén éta téh kahiji ku baris[`numTrades] kolom - lamun ngandung 0, lajeng nilai nu kahiji. Q boga fungsi pilih - ?[Boolean list;list1;list2] - nu milih nilai tina daptar 1 atawa 2 gumantung kana kaayaan dina argumen kahiji:

// high -> ?[isFirst;inp`high;row[`high]|inp`high]
// @ - тоже обобщенное присваивание для случая когда индекс неглубокий
@[`aggExpression;specialCols;{[x;y]"?[isFirst;inp`",y,";",x,"]"};string specialCols];

Di dieu kuring disebut tugas umum kalawan fungsi kuring (hiji ekspresi dina braces Curly). Éta nampi nilai ayeuna (argumen kahiji) sareng argumen tambahan, anu kuring pas dina parameter 4.

Hayu urang tambahkeun spéker batré sacara misah, sabab fungsina sami pikeun aranjeunna:

// volume -> row[`volume]+inp`volume
aggExpression[accumulatorCols]:{"row[`",x,"]+inp`",x } each string accumulatorCols;

Ieu mangrupikeun tugas normal ku standar Q, tapi kuring napelkeun daptar nilai sakaligus. Tungtungna, hayu urang nyieun fungsi utama:

// ":",/:aggExprs ~ map[{":",x};aggExpr] => ":row[`high]|inp`high" присвоим вычисленное значение переменной, потому что некоторые колонки зависят от уже вычисленных значений
// string[cols],'exprs ~ map[,;string[cols];exprs] => "high:row[`high]|inp`high" завершим создание присваивания. ,’ расшифровывается как map[concat]
// ";" sv exprs – String from Vector (sv), соединяет список строк вставляя “;” посредине
updateAgg:value "{[aggTable;idx;inp] row:aggTable idx; isFirst_0=row`numTrades; .[aggTable;;:;]'[(idx;)each aggCols;(",(";"sv string[aggCols],'":",/:aggExpression aggCols),")]}";

Kalayan éksprési ieu, kuring dinamis nyiptakeun fungsi tina senar anu ngandung ekspresi anu kuring masihan di luhur. hasilna bakal kasampak kawas kieu:

{[aggTable;idx;inp] rows:aggTable idx; isFirst_0=row`numTrades; .[aggTable;;:;]'[(idx;)each aggCols ;(cumVolume:row[`cumVolume]+inp`cumVolume;… ; high:?[isFirst;inp`high;row[`high]|inp`high])]}

Urutan evaluasi kolom dibalikkeun sabab dina Q urutan evaluasi ti katuhu ka kenca.

Ayeuna urang gaduh dua fungsi utama anu dipikabutuh pikeun itungan, urang ngan ukur kedah nambihan sakedik infrastruktur sareng jasa parantos siap.

Léngkah ahir

Kami ngagaduhan fungsi preprocess sareng updateAgg anu ngalaksanakeun sagala padamelan. Tapi masih diperlukeun pikeun mastikeun transisi bener ngaliwatan menit jeung ngitung indexes pikeun aggregation. Anu mimiti, hayu urang ngartikeun fungsi init:

init:{
  tradeAgg:: 0#enlist[initWith]; // создаем пустую типизированную таблицу, enlist превращает словарь в таблицу, а 0# означает взять 0 элементов из нее
  currTime::00:00; // начнем с 0, :: означает, что присваивание в глобальную переменную
  currSyms::`u#`symbol$(); // `u# - превращает список в дерево, для ускорения поиска элементов
  offset::0; // индекс в tradeAgg, где начинается текущая минута 
  rollCache:: `sym xkey update `u#sym from rollColumns#tradeAgg; // кэш для последних значений roll колонок, таблица с ключом sym
 }

Urang ogé bakal nangtukeun fungsi roll, nu bakal ngarobah menit ayeuna:

roll:{[tm]
  if[currTime>tm; :init[]]; // если перевалили за полночь, то просто вызовем init
  rollCache,::offset _ rollColumns#tradeAgg; // обновим кэш – взять roll колонки из aggTable, обрезать, вставить в rollCache
  offset::count tradeAgg;
  currSyms::`u#`$();
 }

Urang bakal butuh fungsi pikeun nambahkeun karakter anyar:

addSyms:{[syms]
  currSyms,::syms; // добавим в список известных
  // добавим в таблицу sym, time и rollColumns воспользовавшись обобщенным присваиванием.
  // Функция ^ подставляет значения по умолчанию для roll колонок, если символа нет в кэше. value flip table возвращает список колонок в таблице.
  `tradeAgg upsert @[count[syms]#enlist initWith;`sym`time,cols rc;:;(syms;currTime), (initWith cols rc)^value flip rc:rollCache ([] sym: syms)];
 }

Sarta pamustunganana, fungsi upd (ngaran tradisional pikeun fungsi ieu pikeun layanan Q), nu disebut ku klien pikeun nambahkeun data:

upd:{[tblName;data] // tblName нам не нужно, но обычно сервис обрабатывает несколько таблиц 
  tm:exec distinct time from data:() xkey preprocess data; // preprocess & calc time
  updMinute[data] each tm; // добавим данные для каждой минуты
};
updMinute:{[data;tm]
  if[tm<>currTime; roll tm; currTime::tm]; // поменяем минуту, если необходимо
  data:select from data where time=tm; // фильтрация
  if[count msyms:syms where not (syms:data`sym)in currSyms; addSyms msyms]; // новые символы
  updateAgg[`tradeAgg;offset+currSyms?syms;data]; // обновим агрегированную таблицу. Функция ? ищет индекс элементов списка справа в списке слева.
 };

Éta hungkul. Ieu kode lengkep jasa kami, sakumaha anu dijanjikeun, ngan ukur sababaraha baris:

initWith:`sym`time`high`low`firstPrice`lastPrice`firstSize`lastSize`numTrades`volume`pvolume`turnover`avgPrice`avgSize`vwap`cumVolume!(`;00:00;0n;0n;0n;0n;0N;0N;0;0;0.0;0.0;0n;0n;0n;0);
aggCols:reverse key[initWith] except `sym`time;
rollColumns:`sym`cumVolume;

accumulatorCols:`numTrades`volume`pvolume`turnover;
specialCols:`high`low`firstPrice`firstSize;

selExpression:`high`low`firstPrice`lastPrice`firstSize`lastSize`numTrades`volume`pvolume`turnover!parse each ("max price";"min price";"first price";"last price";"first size";"last size";"count i";"sum size";"sum price";"sum price*size");
preprocess:?[;();`sym`time!`sym`time.minute;selExpression];

aggExpression:`high`low`firstPrice`lastPrice`firstSize`lastSize`avgPrice`avgSize`vwap`cumVolume!("row[`high]|inp`high";"row[`low]&inp`low";"row`firstPrice";"inp`lastPrice";"row`firstSize";"inp`lastSize";"pvolume%numTrades";"volume%numTrades";"turnover%volume";"row[`cumVolume]+inp`volume");
@[`aggExpression;specialCols;{"?[isFirst;inp`",y,";",x,"]"};string specialCols];
aggExpression[accumulatorCols]:{"row[`",x,"]+inp`",x } each string accumulatorCols;
updateAgg:value "{[aggTable;idx;inp] row:aggTable idx; isFirst_0=row`numTrades; .[aggTable;;:;]'[(idx;)each aggCols;(",(";"sv string[aggCols],'":",/:aggExpression aggCols),")]}"; / '

init:{
  tradeAgg::0#enlist[initWith];
  currTime::00:00;
  currSyms::`u#`symbol$();
  offset::0;
  rollCache:: `sym xkey update `u#sym from rollColumns#tradeAgg;
 };
roll:{[tm]
  if[currTime>tm; :init[]];
  rollCache,::offset _ rollColumns#tradeAgg;
  offset::count tradeAgg;
  currSyms::`u#`$();
 };
addSyms:{[syms]
  currSyms,::syms;
  `tradeAgg upsert @[count[syms]#enlist initWith;`sym`time,cols rc;:;(syms;currTime),(initWith cols rc)^value flip rc:rollCache ([] sym: syms)];
 };

upd:{[tblName;data] updMinute[data] each exec distinct time from data:() xkey preprocess data};
updMinute:{[data;tm]
  if[tm<>currTime; roll tm; currTime::tm];
  data:select from data where time=tm;
  if[count msyms:syms where not (syms:data`sym)in currSyms; addSyms msyms];
  updateAgg[`tradeAgg;offset+currSyms?syms;data];
 };

Tés

Hayu urang pariksa kinerja jasa. Jang ngalampahkeun ieu, hayu urang ngajalankeun eta dina prosés misah (nempatkeun kode dina file service.q) jeung nelepon fungsi init:

q service.q –p 5566

q)init[]

Dina konsol sejen, mimitian prosés Q kadua teras sambungkeun ka kahiji:

h:hopen `:host:5566
h:hopen 5566 // если оба на одном хосте

Kahiji, hayu urang nyieun daptar simbol - 10000 lembar jeung nambahkeun fungsi pikeun nyieun tabel acak. Dina konsol kadua:

syms:`IBM`AAPL`GOOG,-9997?`8
rnd:{[n;t] ([] sym:n?syms; time:t+asc n#til 25; price:n?10f; size:n?10)}

Kuring ditambahkeun tilu lambang nyata daptar pikeun make deui gampang néangan aranjeunna dina tabél. Fungsi rnd nyiptakeun tabel acak kalawan n jajar, dimana waktu beda-beda ti t nepi ka t + 25 milliseconds.

Ayeuna anjeun tiasa nyobian ngirim data ka jasa (tambahkeun sapuluh jam munggaran):

{h (`upd;`trade;rnd[10000;x])} each `time$00:00 + til 60*10

Anjeun tiasa pariksa dina jasa yén tabél parantos diropéa:

c 25 200
select from tradeAgg where sym=`AAPL
-20#select from tradeAgg where sym=`AAPL

Hasil:

sym|time|high|low|firstPrice|lastPrice|firstSize|lastSize|numTrades|volume|pvolume|turnover|avgPrice|avgSize|vwap|cumVolume
--|--|--|--|--|--------------------------------
AAPL|09:27|9.258904|9.258904|9.258904|9.258904|8|8|1|8|9.258904|74.07123|9.258904|8|9.258904|2888
AAPL|09:28|9.068162|9.068162|9.068162|9.068162|7|7|1|7|9.068162|63.47713|9.068162|7|9.068162|2895
AAPL|09:31|4.680449|0.2011121|1.620827|0.2011121|1|5|4|14|9.569556|36.84342|2.392389|3.5|2.631673|2909
AAPL|09:33|2.812535|2.812535|2.812535|2.812535|6|6|1|6|2.812535|16.87521|2.812535|6|2.812535|2915
AAPL|09:34|5.099025|5.099025|5.099025|5.099025|4|4|1|4|5.099025|20.3961|5.099025|4|5.099025|2919

Hayu urang ayeuna ngalaksanakeun uji beban pikeun milarian sabaraha data anu tiasa diolah ku jasa per menit. Hayu atuh ngingetkeun yén urang nyetel interval update ka 25 milliseconds. Sasuai, jasa kedah (rata-rata) pas kana sahenteuna 20 milliseconds per update pikeun masihan pamaké waktu pikeun ménta data. Lebetkeun ieu dina prosés kadua:

tm:10:00:00.000
stressTest:{[n] 1 string[tm]," "; times,::h ({st:.z.T; upd[`trade;x]; .z.T-st};rnd[n;tm]); tm+:25}
start:{[n] times::(); do[4800;stressTest[n]]; -1 " "; `min`avg`med`max!(min times;avg times;med times;max times)}

4800 nyaéta dua menit. Anjeun tiasa nyobian ngajalankeun heula pikeun 1000 baris unggal 25 milidetik:

start 1000

Dina kasus kuring, hasilna sakitar sababaraha milliseconds per update. Janten kuring langsung ningkatkeun jumlah baris jadi 10.000:

start 10000

Hasil:

min| 00:00:00.004
avg| 9.191458
med| 9f
max| 00:00:00.030

Deui, euweuh husus, tapi ieu 24 juta garis per menit, 400 rébu per detik. Pikeun leuwih ti 25 milliseconds, update ngalambatkeun turun ngan 5 kali, katingalina lamun menit robah. Hayu urang ningkatkeun ka 100.000:

start 100000

Hasil:

min| 00:00:00.013
avg| 25.11083
med| 24f
max| 00:00:00.108
q)sum times
00:02:00.532

Sakumaha anjeun tiasa tingali, jasa éta bieu tiasa Cope, tapi kumaha oge, eta manages tetep ngambang. Sapertos volume data (240 juta baris per menit) ageung pisan; dina kasus sapertos kitu, biasa ngaluncurkeun sababaraha klon (atanapi puluhan klon) jasa, anu masing-masing ngan ukur ngolah bagian tina karakter. Leungit, hasilna nyaeta impressive pikeun basa diinterpretasi nu museurkeun utamana dina neundeun data.

Patarosan tiasa timbul naha waktos tumbuh non-linier kalayan ukuran unggal pembaruan. Alesanna nyaéta fungsi ngaleutikan saleresna mangrupikeun fungsi C, anu langkung éfisién tibatan updateAgg. Dimimitian tina ukuran apdet anu tangtu (sakitar 10.000), updateAgg ngahontal siling na teras waktos palaksanaanna henteu gumantung kana ukuran pembaruan. Kusabab léngkah awal Q yén jasa éta tiasa nyerna volume data sapertos kitu. Ieu nyorot kumaha pentingna milih algoritma anu leres nalika damel sareng data ageung. Titik anu sanés nyaéta panyimpen data anu leres dina mémori. Lamun data teu disimpen columnarly atawa teu maréntahkeun ku waktu, urang bakal jadi akrab jeung hal saperti TLB cache miss - henteuna alamat kaca memori dina cache alamat processor. Milarian alamat butuh sakitar 30 kali langkung lami upami gagal, sareng upami datana sumebar, éta tiasa ngalambatkeun jasa sababaraha kali.

kacindekan

Dina tulisan ieu, kuring nunjukkeun yén pangkalan data KDB + sareng Q cocog henteu ngan ukur pikeun nyimpen data anu ageung sareng gampang ngaksésna ngaliwatan pilihan, tapi ogé pikeun nyiptakeun jasa ngolah data anu sanggup nyerna ratusan juta baris / gigabyte data bahkan dina hiji prosés Q tunggal. Basa Q sorangan ngamungkinkeun pikeun palaksanaan pisan singket tur efisien algoritma patali ngolah data alatan alam vektor na, diwangun-di juru SQL dialek jeung set pisan suksés fungsi perpustakaan.

Kuring bakal perhatikeun yén di luhur mangrupikeun bagian tina naon anu tiasa dilakukeun ku Q, éta ogé gaduh fitur unik anu sanés. Salaku conto, protokol IPC anu saderhana pisan anu mupus wates antara prosés Q individu sareng ngamungkinkeun anjeun ngagabungkeun ratusan prosés ieu kana jaringan tunggal, anu tiasa ditempatkeun dina puluhan server di bagian anu béda-béda dunya.

sumber: www.habr.com

Tambahkeun komentar