Feartan a’ chànain Q agus KDB+ a’ cleachdadh eisimpleir seirbheis fìor-ùine

Faodaidh tu leughadh mu dè a th’ ann am bunait KDB +, cànan prògramadh Q, dè na neartan agus na laigsean a th’ aca anns na bha agam roimhe artaigil agus gu h-aithghearr anns an ro-ràdh. Anns an artaigil, cuiridh sinn an gnìomh seirbheis air Q a làimhsicheas an t-sruth dàta a tha a’ tighinn a-steach agus obrachadh a-mach diofar ghnìomhan cruinneachaidh gach mionaid ann am modh “fìor-ùine” (ie, bidh ùine aige a h-uile càil obrachadh a-mach ron ath chuibhreann de dhàta). Is e prìomh fheart Q gur e cànan vector a th’ ann a leigeas leat obrachadh chan ann le nithean singilte, ach leis na h-arrays aca, arrays de arrays agus nithean iom-fhillte eile. Tha cànanan leithid Q agus a càirdean K, J, APL ainmeil airson cho goirid ‘s a tha iad. Gu math tric, faodar prògram a ghabhas suas grunn sgrionaichean de chòd ann an cànan air a bheil thu eòlach mar Java a sgrìobhadh orra ann am beagan loidhnichean. Is e seo a tha mi airson a shealltainn san artaigil seo.

Feartan a’ chànain Q agus KDB+ a’ cleachdadh eisimpleir seirbheis fìor-ùine

Ro-ràdh

Tha KDB + na stòr-dàta colbh a tha ag amas air mòran dàta, air òrdachadh ann an dòigh shònraichte (gu sònraichte le ùine). Tha e air a chleachdadh sa mhòr-chuid ann an ionadan ionmhais - bancaichean, airgead tasgaidh, companaidhean àrachais. Is e an cànan Q an cànan a-staigh aig KDB+ a leigeas leat obrachadh gu h-èifeachdach leis an dàta seo. Is e an ideòlas Q giorrad agus èifeachdas, fhad ‘s a thathas a’ toirt seachad soilleireachd. Tha seo air fhìreanachadh leis gu bheil an cànan vectar a bhios doirbh a thuigsinn co-dhiù, agus tha cho goirid agus cho beairteach sa tha an clàradh a 'toirt cothrom dhut pàirt fada nas motha den phrògram fhaicinn air aon sgrion, a tha ga dhèanamh nas fhasa a thuigsinn aig a' cheann thall.

San artaigil seo bidh sinn a’ cur an gnìomh prògram làn-chuimseach ann an Q agus is dòcha gum biodh tu airson feuchainn air. Gus seo a dhèanamh, bidh feum agad air an fhìor Q. Faodaidh tu an tionndadh 32-bit an-asgaidh a luchdachadh sìos air làrach-lìn companaidh kx - www.kx.com. An sin, ma tha ùidh agad, gheibh thu fiosrachadh iomraidh air Q, an leabhar Q airson mortals agus diofar artaigilean air a’ chuspair seo.

Aithris dhuilgheadas

Tha stòr ann a chuireas clàr le dàta gach 25 milliseconds. Leis gu bheil KDB+ air a chleachdadh gu sònraichte ann an ionmhas, gabhaidh sinn ris gur e clàr de ghnothaichean (ciùird) a tha seo, aig a bheil na colbhan a leanas: ùine (ùine ann am milliseconds), sym (sònrachadh companaidh air an t-iomlaid stoc - IBM, AAPL,…), prìs (am prìs aig an deach na h-earrannan a cheannach), meud (meud a’ ghnothaich). Tha an eadar-ama 25 millisecond neo-riaghailteach, gun a bhith ro bheag agus gun a bhith ro fhada. Tha an làthaireachd aige a’ ciallachadh gu bheil an dàta a’ tighinn chun t-seirbheis a tha air a bufair mu thràth. Bhiodh e furasta buffering a chuir an gnìomh air taobh na seirbheis, a’ toirt a-steach buffering fiùghantach a rèir an luchd a th’ ann an-dràsta, ach airson sìmplidheachd, cuiridh sinn fòcas air eadar-ama stèidhichte.

Feumaidh an t-seirbheis cunntadh gach mionaid airson gach samhla a thig a-steach bhon cholbh sym, seata de ghnìomhan cruinneachaidh - a’ phrìs as àirde, a’ phrìs cuibheasach, meud an t-suim, msaa. fiosrachadh feumail. Airson sìmplidheachd, gabhaidh sinn ris gum faodar a h-uile gnìomh obrachadh a-mach mean air mhean, i.e. Gus luach ùr fhaighinn, tha e gu leòr fios a bhith agad air dà àireamh - an t-seann agus na luachan a tha a 'tighinn a-steach. Mar eisimpleir, tha an togalach seo aig na gnìomhan as àirde, cuibheasach, suim, ach chan eil an gnìomh meadhanach.

Gabhaidh sinn ris cuideachd gu bheil an sruth dàta a tha a’ tighinn a-steach air òrdachadh le ùine. Bheir seo dhuinn an cothrom a bhith ag obair a-mhàin leis a 'mhionaid mu dheireadh. Ann an cleachdadh, tha e gu leòr a bhith comasach air obrachadh leis na geàrr-chunntasan gnàthach agus roimhe gun fhios nach bi cuid de dh’ ùrachaidhean fadalach. Airson sìmplidh, cha bheachdaich sinn air a’ chùis seo.

Feartan co-chruinneachaidh

Tha na gnìomhan cruinneachaidh riatanach air an liostadh gu h-ìosal. Thug mi nas urrainn dhaibh gus an luchd air an t-seirbheis àrdachadh:

  • àrd - prìs as àirde - prìs as àirde gach mionaid.
  • ìosal - prìs as ìsle - prìs as ìsle gach mionaid.
  • a’ chiad phrìs – a’ chiad phrìs – a’ chiad phrìs gach mionaid.
  • LastPrice - prìs mu dheireadh - prìs mu dheireadh gach mionaid.
  • firstSize - a 'chiad mheud - a' chiad mheud malairt gach mionaid.
  • lastSize - meud mu dheireadh - meud malairt mu dheireadh ann am mionaid.
  • numTrades - cunnt i - an àireamh de chiùird gach mionaid.
  • tomhas-lìonaidh - meud suim - suim meudan malairt gach mionaid.
  • pvolume - prìs sùim - suim phrìsean gach mionaid, riatanach airson avgPrice.
  • - suim tionndaidh prìs * meud - àireamh iomlan de ghnothaichean gach mionaid.
  • avgPrice - pvolume%numTrades - prìs chuibheasach gach mionaid.
  • avgSize - volume%numTrades - meud malairt cuibheasach gach mionaid.
  • vwap - tionndadh% tomhas-lìonaidh - prìs chuibheasach gach mionaid air a chuideamachadh a rèir meud malairt.
  • cumVolume - tomhas-lìonaidh - meud cruinnichte de ghnothaichean thar na h-ùine gu lèir.

Bruidhnidh sinn sa bhad air aon phuing nach eil follaiseach - mar a thòisicheas tu na colbhan sin airson a’ chiad uair agus airson gach mionaid às deidh sin. Feumar cuid de cholbhan den t-seòrsa ciad phrìs a thòiseachadh gu null gach turas; tha an luach neo-mhìnichte. Feumaidh seòrsachan lìonaidh eile a bhith air an suidheachadh gu 0 an-còmhnaidh. Tha colbhan ann cuideachd a dh’ fheumas dòigh-obrach aonaichte - mar eisimpleir, feumaidh cumVolume a bhith air a chopaigeadh bhon mhionaid roimhe, agus airson a’ chiad sheata gu 0. Leig leinn na paramadairean sin uile a shuidheachadh a’ cleachdadh dàta an fhaclair seòrsa (co-ionann ri clàr):

// 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 mi sym agus ùine ris an fhaclair airson goireasachd, a-nis tha initWith na loidhne deiseil bhon chlàr iomlan mu dheireadh, far a bheil e fhathast gus an sim agus an ùine cheart a shuidheachadh. Faodaidh tu a chleachdadh gus sreathan ùra a chur ri clàr.

Bidh feum againn air aggCols nuair a bhios sinn a’ cruthachadh gnìomh cruinneachaidh. Feumaidh an liosta a bhith air a thionndadh air sgàth an òrdugh anns a bheil abairtean ann an Q air am measadh (bho dheas gu clì). Is e an t-amas dèanamh cinnteach gu bheil an àireamhachadh a’ dol bho àrd gu cumVolume, leis gu bheil cuid de cholbhan an urra ris an fheadhainn a bh’ ann roimhe.

Colbhan a dh’ fheumar a chopaigeadh gu mionaid ùr bhon fhear roimhe, tha an colbh sim air a chur ris airson goireasachd:

rollColumns:`sym`cumVolume;

A-nis roinnidh sinn na colbhan ann am buidhnean a rèir mar a bu chòir an ùrachadh. Faodar trì seòrsaichean a chomharrachadh:

  1. Luchd-cruinneachaidh (tomhas-lìonaidh, tionndadh, ..) - feumaidh sinn an luach a thig a-steach a chur ris an fhear roimhe.
  2. Le puing sònraichte (àrd, ìosal, ..) - tha a 'chiad luach sa gheàrr-chunntas air a thoirt bhon dàta a tha a' tighinn a-steach, tha an còrr air a thomhas a 'cleachdadh a' ghnìomh.
  3. An còrr. An-còmhnaidh air a thomhas a’ cleachdadh gnìomh.

Mìnichidh sinn caochladairean airson na clasaichean seo:

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

Òrdugh àireamhachaidh

Ùraichidh sinn an clàr cruinn ann an dà ìre. Airson èifeachdas, bidh sinn an toiseach a’ crìonadh a’ bhùird a tha a’ tighinn a-steach gus nach bi ach aon sreath ann airson gach caractar agus mionaid. Tha an fhìrinn gu bheil na gnìomhan againn uile mean air mhean agus ceangaltach a’ gealltainn nach atharraich toradh a’ cheum a bharrachd seo. Faodaidh tu an clàr a lughdachadh le bhith a’ cleachdadh tagh:

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

Tha ana-cothrom aig an dòigh seo - tha an seata de cholbhan àireamhaichte ro-mhìnichte. Gu fortanach, ann an Q, tha tagh cuideachd air a chuir an gnìomh mar ghnìomh far an urrainn dhut argamaidean a chaidh a chruthachadh gu dinamach a chuir an àite:

?[table;whereClause;byClause;selectClause]

Cha toir mi cunntas mionaideach air cruth nan argamaidean; anns a’ chùis againn, cha bhi ach abairtean agus abairtean taghte neo-shònraichte agus bu chòir dhaibh a bhith nam faclairean de na colbhan foirm! Mar sin, faodar an gnìomh crìonadh a mhìneachadh mar 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];

Airson soilleireachd, chleachd mi an gnìomh parse, a thionndaidheas sreang le abairt Q gu luach a dh’ fhaodar a thoirt don ghnìomh eval agus a tha riatanach anns a’ ghnìomh tagh. Thoir an aire cuideachd gu bheil ro-phròiseas air a mhìneachadh mar ro-mheasadh (ie, gnìomh le argamaidean air a mhìneachadh gu ìre) den ghnìomh taghte, tha aon argamaid (am clàr) a dhìth. Ma chuireas sinn preprocess gu clàr, gheibh sinn clàr teannachaidh.

Is e an dàrna ìre an clàr iomlan ùrachadh. An toiseach sgrìobh sinn an algairim ann am 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];
  …

Ann an Q, tha e cumanta gnìomhan mapa / lughdachadh a chleachdadh an àite lùban. Ach leis gur e cànan vector a th’ ann an Q agus is urrainn dhuinn a h-uile gnìomh a chuir an sàs gu furasta anns a h-uile samhla aig an aon àm, an uairsin gu ciad tuairmseachadh as urrainn dhuinn a dhèanamh às aonais lùb idir, a’ coileanadh gnìomhachd air a h-uile samhla aig an aon àm:

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

Ach is urrainn dhuinn a dhol nas fhaide, tha gnìomhaiche sònraichte agus air leth cumhachdach aig Q - an gnìomhaiche sònrachaidh coitcheann. Leigidh e leat seata luachan atharrachadh ann an structar dàta iom-fhillte a’ cleachdadh liosta de chlàran-amais, gnìomhan agus argamaidean. Anns a 'chùis againn, tha e a' coimhead 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;…)];

Gu mì-fhortanach, airson a shònrachadh gu clàr feumaidh tu liosta de shreathan, chan e colbhan, agus feumaidh tu am matrix (liosta nan colbhan gu liosta nan sreathan) a thionndadh a’ cleachdadh a’ ghnìomh flip. Tha seo daor airson bòrd mòr, agus mar sin an àite sin bidh sinn a’ cleachdadh sònrachadh coitcheann air gach colbh fa leth, a’ cleachdadh gnìomh a’ mhapa (a tha coltach ri giorrachadh):

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

Bidh sinn a-rithist a’ cleachdadh ro-mheasadh gnìomh. Thoir an aire cuideachd, ann an Q, gu bheil cruthachadh liosta cuideachd na ghnìomh agus is urrainn dhuinn a ghairm a’ cleachdadh an gnìomh each (mapa) gus liosta liostaichean fhaighinn.

Gus dèanamh cinnteach nach eil an seata de cholbhan àireamhaichte stèidhichte, cruthaichidh sinn an abairt gu h-àrd gu dinamach. An toiseach mìnichidh sinn gnìomhan airson gach colbh obrachadh a-mach, a’ cleachdadh na caochladairean sreath agus inp gus iomradh a thoirt air an dàta cruinnichte agus cuir a-steach:

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");

Tha cuid de cholbhan sònraichte; cha bu chòir a’ chiad luach aca obrachadh a-mach leis a’ ghnìomh. Is urrainn dhuinn dearbhadh gur e seo a’ chiad fhear leis a’ cholbh sreath [`numTrades] - ma tha 0 ann, is e an luach an toiseach. Tha gnìomh taghte aig Q - ?[liosta Boolean; liosta1;list2] - a thaghas luach bho liosta 1 no 2 a rèir an t-suidheachaidh sa chiad argamaid:

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

An seo dh ’ainmich mi sònrachadh coitcheann leis a’ ghnìomh agam (abairt ann am braces lùbach). Bidh e a 'faighinn an luach làithreach (a' chiad argamaid) agus argamaid a bharrachd, a bheir mi seachad anns a '4mh paramadair.

Nach cuir sinn luchd-labhairt bataraidh air leth, leis gu bheil an gnìomh an aon rud dhaibh:

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

Is e sònrachadh àbhaisteach a tha seo a rèir inbhean Q, ach tha mi a’ sònrachadh liosta luachan aig an aon àm. Mu dheireadh, cruthaichidh sinn am prìomh dhleastanas:

// ":",/: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 abairt seo, bidh mi gu dinamach a’ cruthachadh gnìomh bho shreang anns a bheil an abairt a thug mi gu h-àrd. Bidh an toradh a 'coimhead 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])]}

Tha òrdugh measaidh a’ cholbh air a thionndadh air ais oir ann an Q tha an òrdugh measaidh bho dheas gu clì.

A-nis tha dà phrìomh dhleastanas againn a tha riatanach airson àireamhachadh, feumaidh sinn dìreach beagan bun-structair a chuir ris agus tha an t-seirbheis deiseil.

Ceumannan deireannach

Tha gnìomhan preprocess agus updateAgg againn a nì an obair gu lèir. Ach tha e fhathast riatanach dèanamh cinnteach gu bheil an gluasad ceart tro mhionaidean agus obrachadh a-mach clàran-amais airson cruinneachadh. An toiseach, mìnichidh sinn an gnìomh 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
 }

Mìnichidh sinn cuideachd gnìomh an rolla, a dh’ atharraicheas a’ mhionaid làithreach:

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

Bidh feum againn air gnìomh gus caractaran ùra a chur ris:

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 mu dheireadh, an gnìomh ùrachadh (an t-ainm traidiseanta airson a’ ghnìomh seo airson seirbheisean Q), ris an can an neach-dèiligidh dàta a chur ris:

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 e. Seo an còd iomlan den t-seirbheis againn, mar a chaidh a ghealltainn, dìreach beagan loidhnichean:

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];
 };

Deuchainn

Feuch an dèan sinn sgrùdadh air coileanadh na seirbheis. Gus seo a dhèanamh, ruithidh sinn e ann am pròiseas air leth (cuir an còd san fhaidhle service.q) agus cuir fios gu gnìomh init:

q service.q –p 5566

q)init[]

Ann an consol eile, tòisich air an dàrna pròiseas Q agus ceangail ris a’ chiad fhear:

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

An toiseach, cruthaichidh sinn liosta de shamhlaidhean - 10000 pìosan agus cuir sinn gnìomh gus clàr air thuaiream a chruthachadh. Anns an dàrna consol:

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 mi trì fìor shamhlaidhean ris an liosta gus a dhèanamh nas fhasa coimhead air an son sa chlàr. Bidh an gnìomh rnd a’ cruthachadh clàr air thuaiream le n sreathan, far a bheil an ùine ag atharrachadh bho t gu t + 25 milliseconds.

A-nis faodaidh tu feuchainn ri dàta a chuir chun t-seirbheis (cuir ris a’ chiad deich uairean):

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

Faodaidh tu dearbhadh san t-seirbheis gu bheil an clàr air ùrachadh:

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|2919

Feuch an dèan sinn a-nis deuchainn luchdan gus faighinn a-mach dè an dàta as urrainn don t-seirbheis a phròiseasadh gach mionaid. Leig leam do chuimhneachadh gun do shuidhich sinn an ùine ùrachaidh gu 25 milliseconds. Mar sin, feumaidh an t-seirbheis (gu cuibheasach) a dhol a-steach do co-dhiù 20 milliseconds gach ùrachadh gus ùine a thoirt do luchd-cleachdaidh dàta iarraidh. Cuir a-steach na leanas san dàrna 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)}

Tha 4800 dà mhionaid. Faodaidh tu feuchainn ri ruith an toiseach airson 1000 sreath gach 25 milliseconds:

start 1000

Anns a ’chùis agam, tha an toradh timcheall air millisecond no dhà airson gach ùrachadh. Mar sin àrdaichidh mi sa bhad an àireamh de shreathan gu 10.000:

start 10000

Toradh:

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

A-rithist, chan eil dad sònraichte, ach is e seo 24 millean loidhne gach mionaid, 400 mìle gach diog. Airson còrr air 25 milliseconds, cha do chuir an t-ùrachadh sìos ach 5 tursan, a rèir coltais nuair a dh’ atharraich a’ mhionaid. Àrdaichidh sinn gu 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 chì thu, is gann gun urrainn don t-seirbheis dèiligeadh, ach a dh’ aindeoin sin tha e comasach dha fuireach air falbh. Tha an leithid de dhàta (240 millean sreath gach mionaid) gu math mòr; ann an leithid de chùisean, tha e cumanta grunn chlones (no eadhon dusanan de chlones) den t-seirbheis a chuir air bhog, agus gach fear dhiubh a ’giullachd dìreach pàirt de na caractaran. Ach, tha an toradh drùidhteach airson cànan eadar-mhìneachaidh a tha ag amas gu sònraichte air stòradh dàta.

Dh’ fhaodadh a’ cheist èirigh carson a tha ùine a’ fàs gu neo-loidhneach le meud gach ùrachaidh. Is e an adhbhar gur e gnìomh C a th’ anns a ’ghnìomh crìonadh, a tha tòrr nas èifeachdaiche na updateAgg. A’ tòiseachadh bho mheud ùrachaidh sònraichte (timcheall air 10.000), bidh updateAgg a’ ruighinn a mhullach agus an uairsin chan eil an ùine cur gu bàs an urra ri meud an ùrachaidh. Is ann mar thoradh air a’ cheum tòiseachaidh Q a tha an t-seirbheis comasach air a leithid de dhàta a chnàmh. Tha seo a’ soilleireachadh cho cudromach sa tha e an algairim cheart a thaghadh nuair a bhios tu ag obair le dàta mòr. Is e puing eile stòradh dàta ceart mar chuimhne. Mura biodh an dàta air a stòradh gu colbh no mura biodh e air òrdachadh le ùine, dh’ fhàsamaid eòlach air a leithid de rud ri ionndrainn tasgadan TLB - às aonais seòladh duilleag cuimhne ann an tasgadan seòladh pròiseasar. Bheir rannsachadh airson seòladh timcheall air 30 tursan nas fhaide mura soirbhich leis, agus ma tha an dàta sgapte, faodaidh e an t-seirbheis a dhèanamh nas slaodaiche grunn thursan.

co-dhùnadh

San artaigil seo, sheall mi gu bheil an stòr-dàta KDB + agus Q freagarrach chan ann a-mhàin airson dàta mòr a stòradh agus faighinn thuige gu furasta tro thaghadh, ach cuideachd airson seirbheisean giullachd dàta a chruthachadh a tha comasach air ceudan de mhilleanan de shreathan / gigabytes de dhàta a chnàmh eadhon ann an aon phròiseas Q singilte. Tha an cànan Q fhèin a’ ceadachadh algorithms co-cheangailte ri giullachd dàta a chuir an gnìomh air leth pongail agus èifeachdach air sgàth a nàdar vector, eadar-theangair dualchainnt SQL stèidhichte agus seata fìor shoirbheachail de ghnìomhan leabharlainn.

Bheir mi fa-near gu bheil na tha gu h-àrd dìreach mar phàirt de na as urrainn dha Q a dhèanamh, tha feartan sònraichte eile aige cuideachd. Mar eisimpleir, protocol IPC air leth sìmplidh a sguabas às a’ chrìoch eadar pròiseasan Q fa leth agus a leigeas leat na ceudan de na pròiseasan sin a chur còmhla ann an aon lìonra, a dh’ fhaodar a shuidheachadh air dusanan de luchd-frithealaidh ann an diofar phàirtean den t-saoghal.

Source: www.habr.com

Cuir beachd ann