Is féidir leat léamh faoi cad é an bonn KDB+, an teanga ríomhchlárúcháin Q, cad iad na láidreachtaí agus na laigí atá agam i mo cheann roimhe seo agus go hachomair sa réamhrá. San alt, cuirfimid seirbhís ar Q i bhfeidhm a phróiseálfaidh an sruth sonraí isteach agus a ríomhfaidh feidhmeanna comhiomlánaithe éagsúla gach nóiméad i mód “fíor-ama” (ie, beidh am aige gach rud a ríomh roimh an gcéad chuid eile de na sonraí). Is í an phríomhghné de Q ná gur teanga veicteoireach í a ligeann duit oibriú ní le réada aonair, ach lena n-eagair, a n-eagair eagair agus réada casta eile. Tá clú ar theangacha ar nós Q agus a ghaolta K, J, APL as a ngiorracht. Go minic, is féidir clár a thógann roinnt scáileáin de chód i dteanga aithnidiúil cosúil le Java a scríobh orthu i roinnt línte. Is é seo ba mhaith liom a léiriú san Airteagal seo.

Réamhrá
Is bunachar sonraí colún é KDB+ atá dírithe ar mhéideanna an-mhór sonraí, arna ordú ar bhealach sonrach (de réir ama go príomha). Úsáidtear é go príomha in institiúidí airgeadais - bainc, cistí infheistíochta, cuideachtaí árachais. Is í an teanga Q teanga inmheánach KDB+ a ligeann duit oibriú go héifeachtach leis na sonraí seo. Is é an idé-eolaíocht Q gontacht agus éifeachtúlacht, cé go bhfuil soiléireacht íobairt. Tá údar leis seo toisc go mbeidh sé deacair teanga an veicteora a thuiscint i gcás ar bith, agus mar gheall ar a ghiorracht agus ar shaibhreas an taifeadta is féidir leat cuid i bhfad níos mó den chlár a fheiceáil ar scáileán amháin, rud a fhágann go mbeidh sé níos éasca le tuiscint ar deireadh thiar.
San Airteagal seo cuirimid clár iomlán i bhfeidhm i Q agus b'fhéidir gur mhaith leat triail a bhaint as. Chun seo a dhéanamh, beidh an Q iarbhír uait. Is féidir leat an leagan 32-giotán saor in aisce a íoslódáil ar shuíomh Gréasáin na cuideachta kx - . Anseo, má tá suim agat, gheobhaidh tú eolas tagartha ar Q, an leabhar agus ailt éagsúla ar an ábhar seo.
An fhadhb a fhoirmiú
Tá foinse ann a sheolann tábla le sonraí gach 25 milleasoicind. Ós rud é go n-úsáidtear KDB+ go príomha i gcúrsaí airgeadais, glacfaimid leis gur tábla idirbheart (trádálacha) é seo a bhfuil na colúin seo a leanas aige: am (am i milleasoicindí), sym (ainmniú cuideachta ar an stocmhalartán - IBM, AAPL,…), praghas (an praghas ar a ceannaíodh na scaireanna), méid (méid an idirbhirt). Tá an t-eatramh 25 milleasoicind treallach, ní ró-bheag agus ní ró-fhada. Ciallaíonn a láithreacht go dtagann na sonraí chuig an tseirbhís maolánach cheana féin. Bheadh sé éasca maolán a chur i bhfeidhm ar thaobh na seirbhíse, lena n-áirítear maolán dinimiciúil ag brath ar an ualach atá ann faoi láthair, ach le haghaidh simplíochta, díreoimid ar eatramh seasta.
Ní mór don tseirbhís sraith feidhmeanna comhiomlánaithe a chomhaireamh gach nóiméad do gach siombail a thagann isteach ón gcolún sim - praghas uasta, meánphraghas, méid na suime, etc. eolas úsáideach. Ar mhaithe le simplíocht, glacfaimid leis gur féidir gach feidhm a ríomh go hincriminteach, i.e. chun luach nua a fháil, is leor dhá uimhir a bheith ar eolas - an seanluach agus na luachanna isteach. Mar shampla, tá an airí seo ag na feidhmeanna uas, meán, suim, ach níl an t-airí sin ag an bhfeidhm airmheánach.
Glacfaimid leis freisin go bhfuil an sruth sonraí isteach in ord ama. Tabharfaidh sé seo deis dúinn oibriú ach amháin leis an nóiméad deireanach. Go praiticiúil, is leor a bheith in ann oibriú leis na miontuairiscí reatha agus roimhe seo ar eagla go bhfuil roinnt nuashonruithe déanach. Ar mhaithe le simplíocht, ní mheasfaimid an cás seo.
Feidhmeanna comhiomlánaithe
Tá na feidhmeanna comhiomlánaithe riachtanacha liostaithe thíos. Ghlac mé an oiread agus ab fhéidir leo chun an t-ualach ar an tseirbhís a mhéadú:
- ard – uasphraghas – uasphraghas in aghaidh an nóiméid.
- íseal – íosphraghas – íosphraghas in aghaidh an nóiméid.
- céadphraghas - an chéad phraghas - an chéad phraghas in aghaidh an nóiméid.
- lastPrice – praghas deiridh – praghas deireanach in aghaidh an nóiméid.
- firstSize – an chéad mhéid – an chéad mhéid trádála in aghaidh an nóiméid.
- lastSize - méid deiridh - méid trádála deiridh i nóiméad.
- numTrades – comhaireamh i – líon na dtrádálacha in aghaidh an nóiméid.
- toirt – méid suime – suim méideanna trádála in aghaidh an nóiméid.
- pvolume – suimphraghas – suim na bpraghsanna in aghaidh an nóiméid, ag teastáil le haghaidh avgPrice.
- – suim láimhdeachais praghas*méid – toirt iomlán na n-idirbheart in aghaidh an nóiméid.
- avgPrice – pvolume%numTrades – meánphraghas in aghaidh an nóiméid.
- avgSize – toirt%numTrades – meánmhéid trádála in aghaidh an nóiméid.
- vwap – láimhdeachas% toirt – meánphraghas in aghaidh an nóiméid ualaithe de réir mhéid an idirbhirt.
- cumImleabhar – toirt suime – méid carntha na n-idirbheart thar an am ar fad.
Déanaimis pointe amháin nach bhfuil soiléir a phlé láithreach - conas na colúin seo a thúsú den chéad uair agus gach nóiméad ina dhiaidh sin. Ní mór roinnt colúin den chineál FirstPrice a thúsú go neamhní gach uair; Ní mór cineálacha eile toirte a shocrú go 0 i gcónaí. Tá colúin ann freisin a dteastaíonn cur chuige comhcheangailte leo - mar shampla, ní mór cumVolume a chóipeáil ón nóiméad roimhe sin, agus don chéad sraith amháin go 0. Déanaimis na paraiméadair seo go léir a shocrú ag baint úsáide as na sonraí foclóir cineál (ar aon dul le taifead):
// 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 объяснен ниже
Chuir mé sim agus am leis an bhfoclóir ar mhaithe le caoithiúlacht, anois is líne réidh é initWith ón tábla comhiomlánaithe deiridh, áit a bhfuil sé fós chun an sim agus an t-am ceart a shocrú. Is féidir leat é a úsáid chun sraitheanna nua a chur le tábla.
Beidh aggCols de dhíth orainn agus feidhm chomhiomlánaithe á cruthú. Ní mór an liosta a aisiompú mar gheall ar an ord ina ndéantar na sloinn i Q a mheas (ó dheis go clé). Is é an sprioc a chinntiú go dtéann an ríomh ó ard go cumVolume, ós rud é go mbraitheann roinnt colúin ar na cinn roimhe seo.
Colúin ar gá iad a chóipeáil go dtí nóiméad nua ón gceann roimhe seo, cuirtear an colún simp leis mar áis:
rollColumns:`sym`cumVolume;
Anois déanaimis na colúin a roinnt ina ngrúpaí de réir conas ba cheart iad a nuashonrú. Is féidir trí chineál a idirdhealú:
- Taisc (toirt, láimhdeachas,..) – ní mór dúinn an luach isteach a chur leis an gceann roimhe sin.
- Le pointe speisialta (ard, íseal, ..) - tógtar an chéad luach sa nóiméad ó na sonraí a thagann isteach, ríomhtar an chuid eile ag baint úsáide as an bhfeidhm.
- An chuid eile. Ríomh i gcónaí ag baint úsáide as feidhm.
Sainmhínímid athróga do na ranganna seo:
accumulatorCols:`numTrades`volume`pvolume`turnover;
specialCols:`high`low`firstPrice`firstSize;
Ordú ríofa
Déanfaimid an tábla comhiomlán a nuashonrú in dhá chéim. Ar mhaithe le héifeachtacht, déanaimid an tábla isteach a chrapadh ar dtús ionas nach mbeidh ach sraith amháin ann do gach carachtar agus nóiméad. Ós rud é go bhfuil ár bhfeidhmeanna uile incriminteach agus comhthiomsaitheach ráthaíochtaí nach dtiocfaidh aon athrú ar thoradh na céime breise seo. D'fhéadfá an tábla a chrapadh le roghnú:
select high:max price, low:min price … by sym,time.minute from table
Tá míbhuntáiste ag an modh seo - tá an sraith de cholúin ríofa réamhshainithe. Ar ámharaí an tsaoil, i Q, cuirtear roghnú i bhfeidhm freisin mar fheidhm inar féidir leat argóintí a cruthaíodh go dinimiciúil a chur in ionad:
?[table;whereClause;byClause;selectClause]
Ní dhéanfaidh mé cur síos go mion ar leagan amach na n-argóintí; inár gcás, ní bheidh ach na habairtí roghnaithe agus nathanna neamhfhánacha agus ba cheart go mbeidís ina bhfoclóirí de na colúin fhoirme! Mar sin, is féidir an fheidhm chrapadh a shainiú mar seo a leanas:
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];
Ar mhaithe le soiléireacht, d'úsáid mé an fheidhm pharsála, a dhéanann sreang le slonn Q ina luach is féidir a chur ar aghaidh go dtí an fheidhm eval agus atá ag teastáil san fheidhm roghnaithe. Tabhair faoi deara freisin go sainmhínítear réamhphróiseas mar theilgean (i.e., feidhm le hargóintí atá sainmhínithe go páirteach) den fheidhm roghnaithe, tá argóint amháin (an tábla) in easnamh. Má chuirimid réamhphróiseas i bhfeidhm ar tábla, gheobhaidh muid tábla comhbhrúite.
Is é an dara céim ná an tábla comhiomlán a nuashonrú. Scríobhaimis an t-algartam i pseudocode ar dtús:
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];
…
I Q, tá sé coitianta feidhmeanna léarscáile/laghdaithe a úsáid in ionad lúba. Ach ós rud é gur teanga veicteoireach é Q agus gur féidir linn gach oibríocht a chur i bhfeidhm go héasca ar na siombailí go léir ag an am céanna, ansin ar an gcéad mheastachán is féidir linn a dhéanamh gan lúb ar chor ar bith, ag déanamh oibríochtaí ar gach siombail ag an am céanna:
idx:calcIdx inputTable;
row:aggTable idx;
aggTable[idx;`high]: row[`high] | inputTable`high;
aggTable[idx;`volume]: row[`volume] + inputTable`volume;
…
Ach is féidir linn dul níos faide, tá oibreoir uathúil agus thar a bheith cumhachtach ag Q - an t-oibreoir sannadh ginearálaithe. Ligeann sé duit sraith luachanna a athrú i struchtúr sonraí casta ag baint úsáide as liosta innéacsanna, feidhmeanna agus argóintí. In ár gcás tá sé mar seo:
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;…)];
Ar an drochuair, teastaíonn liosta sraitheanna, ní colúin, chun an tábla a shannadh, agus caithfidh tú an maitrís (liosta na gcolún go dtí an liosta sraitheanna) a thrasuí ag baint úsáide as an bhfeidhm smeach. Tá sé seo costasach do thábla mór, mar sin ina ionad sin cuirimid tasc ginearálaithe i bhfeidhm ar gach colún ar leithligh, ag baint úsáide as an fheidhm léarscáile (ar cosúil le harlamh):
.[aggTable;;:;]'[(idx;)each aggCols; (row[`high] | inputTable`high;row[`volume] + inputTable`volume;…)];
Bainimid úsáid arís as teilgean feidhme. Tabhair faoi deara freisin gur feidhm é liosta a chruthú i Q freisin agus is féidir linn é a ghlaoch ag baint úsáide as an bhfeidhm gach (léarscáileanna) chun liosta liostaí a fháil.
Chun a chinntiú nach bhfuil sraith na gcolún ríofa socraithe, cruthóimid an abairt thuas go dinimiciúil. Déanaimis feidhmeanna a shainiú ar dtús chun gach colún a ríomh, ag baint úsáide as na hathróga ró agus ionchuir chun tagairt a dhéanamh do na sonraí comhiomlánaithe agus ionchuir:
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");
Tá roinnt colúin speisialta; níor cheart go n-áireofaí a gcéad luach de réir na feidhme. Is féidir linn a chinneadh gurb é an chéad cholún ón ró [`numTrades] é - má tá 0 ann, is é an luach ar dtús. Tá feidhm roghnaithe ag Q - ?[liosta Boole;list1;list2] - a roghnaíonn luach ó liosta 1 nó 2 ag brath ar an gcoinníoll sa chéad argóint:
// high -> ?[isFirst;inp`high;row[`high]|inp`high]
// @ - тоже обобщенное присваивание для случая когда индекс неглубокий
@[`aggExpression;specialCols;{[x;y]"?[isFirst;inp`",y,";",x,"]"};string specialCols];
Anseo d'iarr mé tasc ginearálaithe le m'fheidhm (sloinn i braces chatach). Faigheann sé an luach reatha (an chéad argóint) agus argóint bhreise, a pas mé sa 4ú paraiméadar.
Cuirfimid cainteoirí ceallraí ar leithligh, ós rud é go bhfuil an fheidhm mar an gcéanna dóibh:
// volume -> row[`volume]+inp`volume
aggExpression[accumulatorCols]:{"row[`",x,"]+inp`",x } each string accumulatorCols;
Is gnáth sannadh é seo de réir caighdeáin Q, ach tá liosta luachanna á sannadh agam láithreach. Ar deireadh, déanaimis an phríomhfheidhm a chruthú:
// ":",/: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),")]}";
Leis an slonn seo, cruthaím go dinimiciúil feidhm as teaghrán ina bhfuil an slonn a thug mé thuas. Breathnóidh an toradh mar seo:
{[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])]}
Tá an t-ordú meastóireachta colún inbhéartaithe toisc go bhfuil an t-ordú meastóireachta in Q ó dheas go clé.
Anois tá dhá phríomhfheidhm againn atá riachtanach le haghaidh ríomhaireachtaí, ní mór dúinn ach beagán bonneagair a chur leis agus tá an tseirbhís réidh.
Céimeanna deiridh
Tá feidhmeanna preprocess agus updateAgg againn a dhéanann an obair ar fad. Ach tá sé riachtanach fós an t-aistriú ceart trí nóiméid a áirithiú agus innéacsanna comhiomlánaithe a ríomh. Ar an gcéad dul síos, déanaimis an fheidhm init a shainiú:
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
}
Déanfaimid an fheidhm rolla a shainiú freisin, rud a athróidh an nóiméad reatha:
roll:{[tm]
if[currTime>tm; :init[]]; // если перевалили за полночь, то просто вызовем init
rollCache,::offset _ rollColumns#tradeAgg; // обновим кэш – взять roll колонки из aggTable, обрезать, вставить в rollCache
offset::count tradeAgg;
currSyms::`u#`$();
}
Beidh feidhm ag teastáil uainn chun carachtair nua a chur leis:
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)];
}
Agus ar deireadh, an fheidhm upd (an t-ainm traidisiúnta don fheidhm seo le haghaidh seirbhísí Q), a iarrann an cliant sonraí a chur leis:
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]; // обновим агрегированную таблицу. Функция ? ищет индекс элементов списка справа в списке слева.
};
Sin é an méid. Seo é an cód iomlán dár seirbhís, mar a gealladh, ach cúpla líne:
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ástáil
Déanaimis seiceáil ar fheidhmíocht na seirbhíse. Chun seo a dhéanamh, déanaimis é a rith i bpróiseas ar leith (cuir an cód sa chomhad service.q) agus cuir glaoch ar an bhfeidhm init:
q service.q –p 5566
q)init[]
I gconsól eile, cuir tús leis an dara próiseas Q agus ceangail leis an gcéad cheann:
h:hopen `:host:5566
h:hopen 5566 // если оба на одном хосте
Ar dtús, déanaimis liosta siombailí a chruthú - 10000 píosa agus cuir feidhm leis chun tábla randamach a chruthú. Sa dara consól:
syms:`IBM`AAPL`GOOG,-9997?`8
rnd:{[n;t] ([] sym:n?syms; time:t+asc n#til 25; price:n?10f; size:n?10)}
Chuir mé trí fhíorshiombail leis an liosta chun é a dhéanamh níos éasca iad a chuardach sa tábla. Cruthaíonn an fheidhm rnd tábla randamach le n sraitheanna, áit a athraíonn an t-am ó t go t+25 milleasoicind.
Anois is féidir leat triail a bhaint as sonraí a sheoladh chuig an tseirbhís (cuir na chéad deich n-uaire an chloig leis):
{h (`upd;`trade;rnd[10000;x])} each `time$00:00 + til 60*10
Is féidir leat seiceáil sa tseirbhís go bhfuil an tábla nuashonraithe:
c 25 200
select from tradeAgg where sym=`AAPL
-20#select from tradeAgg where sym=`AAPL
Toradh:
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|2919Déanaimis tástáil ualaigh anois chun a fháil amach cé mhéad sonraí is féidir leis an tseirbhís a phróiseáil in aghaidh an nóiméid. Lig dom a mheabhrú duit go bhfuil an t-eatramh nuashonraithe socraithe againn go 25 milleasoicind. Dá réir sin, ní mór don tseirbhís (ar an meán) luí isteach ar 20 milleasoicind ar a laghad in aghaidh an nuashonraithe chun am a thabhairt d'úsáideoirí sonraí a iarraidh. Cuir isteach an méid seo a leanas sa dara próiseas:
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)}
Dhá nóiméad atá i gceist le 4800. Is féidir leat triail a bhaint as rith ar dtús ar feadh 1000 sraith gach 25 milleasoicind:
start 1000
I mo chás, tá an toradh thart ar chúpla milleasoicind in aghaidh an nuashonraithe. Mar sin méadóidh mé láithreach líon na sraitheanna go 10.000:
start 10000
Toradh:
min| 00:00:00.004
avg| 9.191458
med| 9f
max| 00:00:00.030
Arís, aon rud speisialta, ach tá sé seo 24 milliún línte in aghaidh an nóiméid, 400 míle in aghaidh an tsoicind. Ar feadh níos mó ná 25 milleasoicind, níor mhoilligh an nuashonrú ach 5 huaire, is cosúil nuair a d'athraigh an nóiméad. Méadaimis go 100.000:
start 100000
Toradh:
min| 00:00:00.013
avg| 25.11083
med| 24f
max| 00:00:00.108
q)sum times
00:02:00.532
Mar a fheiceann tú, is ar éigean gur féidir leis an tseirbhís dul i ngleic, ach mar sin féin bainistíonn sé fanacht ar snámh. Tá méid sonraí den sórt sin (240 milliún sraitheanna in aghaidh an nóiméid) thar a bheith mór; i gcásanna den sórt sin, tá sé coitianta roinnt clón (nó fiú mórán clón) den tseirbhís a sheoladh, agus ní phróiseálann gach ceann acu ach cuid de na carachtair. Mar sin féin, tá an toradh iontach do theanga ateangaireachta a dhíríonn go príomha ar stóráil sonraí.
D’fhéadfadh go n-eascródh an cheist cén fáth a n-éiríonn am go neamhlíneach le méid gach nuashonraithe. Is é an chúis atá leis ná gur feidhm C é an fheidhm crapadh i ndáiríre, atá i bhfad níos éifeachtaí ná updateAgg. Ag tosú ó mhéid nuashonraithe áirithe (thart ar 10.000), sroicheann updateAgg a uasteorainn agus ansin ní bhraitheann a chuid ama forghníomhaithe ar mhéid an nuashonraithe. Is mar gheall ar an réamhchéim Q atá an tseirbhís in ann méideanna den sórt sin sonraí a dhíolama. Léiríonn sé seo cé chomh tábhachtach agus atá sé an algartam ceart a roghnú agus tú ag obair le sonraí móra. Pointe eile is ea stóráil cheart sonraí sa chuimhne. Mura ndéanfaí na sonraí a stóráil go colún nó mura n-ordaítear iad de réir ama, chuirfinn aithne ar rud mar chailleann taisce TLB - gan seoladh leathanach cuimhne i dtaisce seoltaí an phróiseálaí. Tógann cuardach seoladh thart ar 30 uair níos faide mura n-éiríonn leis, agus má scaiptear na sonraí, féadfaidh sé moill a chur ar an tseirbhís arís agus arís eile.
Conclúid
San Airteagal seo, thaispeáin mé go bhfuil an bunachar sonraí KDB+ agus Q oiriúnach ní amháin chun sonraí móra a stóráil agus rochtain éasca a fháil air trí rogha, ach freisin chun seirbhísí próiseála sonraí a chruthú atá in ann na céadta milliún sraitheanna/gigabytes de shonraí a dhíleá fiú amháin i próiseas amháin Q amháin. Ceadaíonn an teanga Q féin cur i bhfeidhm thar a bheith beacht agus éifeachtach halgartaim a bhaineann le próiseáil sonraí mar gheall ar a nádúr veicteoireach, ateangaire canúint SQL ionsuite agus sraith feidhmeanna leabharlainne an-rathúil.
Tabharfaidh mé faoi deara nach bhfuil sa mhéid thuas ach cuid den méid is féidir le Q a dhéanamh, tá gnéithe uathúla eile aige freisin. Mar shampla, prótacal IPC an-simplí a scriosann an teorainn idir próisis aonair Q agus a ligeann duit na céadta de na próisis seo a chomhcheangal i líonra amháin, ar féidir a bheith suite ar an iliomad freastalaithe in áiteanna éagsúla ar fud an domhain.
Foinse: will.com
