Хусусиятҳои забони Q ва KDB+ бо истифода аз мисоли хидмати вақти воқеӣ

Шумо метавонед дар бораи он ки пойгоҳи KDB+, забони барномасозии Q чист, ҷиҳатҳои қавӣ ва заъфи онҳо дар мақолаи қаблии ман хонед. мақола ва мухтасар дар мукаддима. Дар мақола, мо хидматеро дар Q татбиқ хоҳем кард, ки ҷараёни маълумоти воридшударо коркард мекунад ва ҳар дақиқа дар реҷаи "вақти воқеӣ" вазифаҳои гуногуни ҷамъкуниро ҳисоб мекунад (яъне он вақт дорад, ки ҳама чизро пеш аз қисми навбатии маълумот ҳисоб кунад). Хусусияти асосии Q дар он аст, ки он забони векторист, ки ба шумо имкон медиҳад, ки на бо як объект, балки бо массивҳо, массивҳои массивҳо ва дигар объектҳои мураккаб кор кунед. Забонҳо ба монанди Q ва хешовандони он K, J, APL бо кӯтоҳ будани худ машҳуранд. Аксар вақт, барномае, ки якчанд экранҳои кодро бо забони шинос ба монанди Java мегирад, метавонад дар чанд сатр навишта шавад. Ин аст он чизе ки ман мехоҳам дар ин мақола нишон диҳам.

Хусусиятҳои забони Q ва KDB+ бо истифода аз мисоли хидмати вақти воқеӣ

Муқаддима

KDB+ як махзани сутунӣ мебошад, ки ба миқдори хеле зиёди додаҳо нигаронида шудааст, ки ба таври мушаххас (пеш аз ҳама аз рӯи вақт) тартиб дода шудааст. Он асосан дар муассисаҳои молиявӣ - бонкҳо, фондҳои сармоягузорӣ, ширкатҳои суғурта истифода мешавад. Забони Q забони дохилии KDB+ мебошад, ки ба шумо имкон медиҳад, ки бо ин додаҳо самаранок кор кунед. Идеологияи Q кӯтоҳӣ ва самаранокӣ аст, дар ҳоле ки возеҳият қурбон аст. Ин бо он асоснок карда мешавад, ки забони векториро дар ҳама ҳолат фаҳмидан душвор хоҳад буд ва кӯтоҳӣ ва ғанӣ будани сабт ба шумо имкон медиҳад, ки қисми зиёди барномаро дар як экран бинед, ки дар ниҳоят фаҳмидани онро осон мекунад.

Дар ин мақола мо як барномаи мукаммалро дар Q татбиқ мекунем ва шумо шояд мехоҳед онро санҷед. Барои ин ба шумо Q воқеии лозим аст. Шумо метавонед версияи ройгони 32-битро аз вебсайти ширкати kx зеркашӣ кунед - www.kx.com. Дар он ҷо, агар шумо таваҷҷӯҳ дошта бошед, шумо маълумотро дар бораи Q, китоб хоҳед ёфт Q Барои мурдагон ва мақолаҳои гуногун дар ин мавзӯъ.

Тартиб додани масъала

Манбае мавҷуд аст, ки ҳар 25 миллисония ҷадвалро бо маълумот мефиристад. Азбаски KDB+ асосан дар соҳаи молия истифода мешавад, мо фарз мекунем, ки ин ҷадвали муомилот (тиҷорат) аст, ки дорои сутунҳои зерин аст: вақт (вақт дар миллисонияҳо), сим (таъиноти ширкат дар биржа - IBM, AAPL,…), нарх (нархе, ки бо он саҳмияҳо харида шудаанд), андоза (андозаи муомилот). Фосилаи 25 миллисония худсарона аст, на хеле хурд ва на хеле дароз. Мавҷудияти он маънои онро дорад, ки маълумот ба хидмате, ки аллакай буфер карда шудааст, меояд. Татбиқи буферӣ дар тарафи хидмат осон мебуд, аз ҷумла буферсозии динамикӣ вобаста ба сарбории ҷорӣ, аммо барои содда, мо ба фосилаи собит тамаркуз хоҳем кард.

Хидмат бояд ҳар як дақиқаро барои ҳар як рамзи воридшаванда аз сутуни сим маҷмӯи функсияҳои ҷамъоварӣ - нархи максималӣ, нархи миёна, андозаи маблағ ва ғайра ҳисоб кунад. маълумоти муфид. Барои содда, мо тахмин мезанем, ки ҳамаи функсияҳоро ба таври афзоянда ҳисоб кардан мумкин аст, яъне. барои ба даст овардани арзиши нав донистани ду адад кифоя аст - арзишҳои кӯҳна ва даромад. Масалан, функсияҳои макс, миёна, ҷамъ ин хосият доранд, аммо функсияи медианӣ надорад.

Мо инчунин тахмин мекунем, ки ҷараёни додаҳои воридотӣ вақт фармоиш дода мешавад. Ин ба мо имконият медихад, ки факат бо дакикаи охирин кор кунем. Дар амал, барои кор кардан бо дақиқаҳои ҷорӣ ва қаблӣ кифоя аст, агар баъзе навсозиҳо дер шаванд. Барои содда, мо ин парвандаро баррасӣ намекунем.

Функсияҳои ҷамъоварӣ

Функсияҳои ҷамъкунии зарурӣ дар зер оварда шудаанд. Ман то ҳадди имкон шумораи зиёди онҳоро гирифтам, то сарбории хидматро зиёд кунад:

  • баланд – нархи максимум – нархи максималӣ дар як дақиқа.
  • паст - нархи ҳадди ақал - нархи ҳадди ақал дар як дақиқа.
  • FirstPrice - нархи аввал - нархи аввал дар як дақиқа.
  • LastPrice - нархи охирин - нархи охирин дар як дақиқа.
  • firstSize - андозаи аввал - андозаи савдои аввал дар як дақиқа.
  • lastSize - андозаи охирин - андозаи охирини савдо дар як дақиқа.
  • numTrades - ҳисоб i - шумораи савдо дар як дақиқа.
  • ҳаҷм – ҳаҷми ҷамъ – маблағи ҳаҷми савдо дар як дақиқа.
  • pvolume – маблағи ҷамъ – маблағи нархҳо дар як дақиқа, ки барои avgPrice лозим аст.
  • – нархи муомилот*андоза – ҳаҷми умумии муомилот дар як дақиқа.
  • avgPrice – pvolume%numTrades – нархи миёна дар як дақиқа.
  • avgSize – ҳаҷми%numTrades – ҳаҷми миёнаи савдо дар як дақиқа.
  • vwap - гардиши% - нархи миёнаи як дақиқа аз рӯи андозаи муомилот вазн карда мешавад.
  • cumVolume – ҳаҷми ҷамъ – ҳаҷми ҷамъшудаи муомилот дар тӯли тамоми вақт.

Биёед фавран як нуктаи норавшанро муҳокима кунем - чӣ гуна ин сутунҳоро бори аввал ва барои ҳар як дақиқаи минбаъда оғоз кардан мумкин аст. Баъзе сутунҳои навъи firstPrice бояд ҳар дафъа ба сифр оғоз карда шаванд; арзиши онҳо номуайян аст. Дигар намудҳои ҳаҷм бояд ҳамеша ба 0 муқаррар карда шаванд. Инчунин сутунҳое мавҷуданд, ки муносибати якҷояро талаб мекунанд - масалан, cumVolume бояд аз дақиқаи қаблӣ нусхабардорӣ карда шавад ва барои аввалинаш 0. Биёед ҳамаи ин параметрҳоро бо истифода аз маълумоти луғат муқаррар кунем. навъи (шабеҳ ба сабт):

// 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 объяснен ниже

Ман барои роҳат ба луғат сим ва вақтро илова кардам, ҳоло initWith як хати тайёр аз ҷадвали ҷамъбастшудаи ниҳоӣ аст, ки дар он ҷо барои танзими сим ва вақт дуруст боқӣ мемонад. Шумо метавонед онро барои илова кардани сатрҳои нав ба ҷадвал истифода баред.

Ҳангоми сохтани функсияи ҷамъкунӣ ба мо aggCols лозим мешавад. Рӯйхат бояд аз рӯи тартиби баҳодиҳии ифодаҳои Q (аз рост ба чап) иваз карда шавад. Мақсад аз он иборат аст, ки ҳисобкунӣ аз баланд ба cumVolume мегузарад, зеро баъзе сутунҳо аз сутунҳои қаблӣ вобастаанд.

Сутунҳое, ки бояд аз як дақиқаи нав ба дақиқаи нав нусхабардорӣ карда шаванд, сутуни сим барои роҳат илова карда мешавад:

rollColumns:`sym`cumVolume;

Акнун биёед сутунҳоро аз рӯи тарзи навсозӣ ба гурӯҳҳо тақсим кунем. Се намудро метавон ҷудо кард:

  1. Аккумуляторҳо (ҳаҷм, гардиш, ..) - мо бояд арзиши воридшударо ба арзиши қаблӣ илова кунем.
  2. Бо нуқтаи махсус (баланд, паст, ..) - арзиши аввал дар дақиқа аз маълумоти воридотӣ гирифта мешавад, боқимонда бо истифода аз функсия ҳисоб карда мешавад.
  3. Истирохат. Ҳамеша бо истифода аз функсия ҳисоб карда мешавад.

Биёед тағирёбандаҳоро барои ин синфҳо муайян кунем:

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

Тартиби ҳисобкунӣ

Мо ҷадвали ҷамъшударо дар ду марҳила навсозӣ мекунем. Барои самаранокӣ, мо аввал ҷадвали воридшударо хурд мекунем, то барои ҳар як аломат ва дақиқа танҳо як сатр мавҷуд бошад. Далели он, ки ҳамаи вазифаҳои мо афзоянда ва ассотсиатсия мебошанд, кафолат медиҳад, ки натиҷаи ин қадами иловагӣ тағир намеёбад. Шумо метавонед ҷадвалро бо истифода аз интихоб хурд кунед:

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

Ин усул як нуқсон дорад - маҷмӯи сутунҳои ҳисобшуда пешакӣ муайян карда шудааст. Хушбахтона, дар Q, интихоб инчунин ҳамчун функсия иҷро карда мешавад, ки дар он шумо аргументҳои динамикӣ сохташударо иваз карда метавонед:

?[table;whereClause;byClause;selectClause]

Ман формати аргументҳоро ба таври муфассал тавсиф намекунам, дар ҳолати мо, танҳо ифодаҳои аз рӯи ва интихобшуда ғайримуқаррарӣ хоҳанд буд ва онҳо бояд луғатҳои сутунҳои шакл бошанд! Ҳамин тариқ, функсияи коҳишро ба таври зерин муайян кардан мумкин аст:

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

Барои равшанӣ, ман функсияи таҳлилро истифода кардам, ки сатрро бо ифодаи Q ба арзише табдил медиҳад, ки метавонад ба функсияи арзёбӣ интиқол дода шавад ва он дар интихоби функсия зарур аст. Инчунин қайд кунед, ки пешравӣ ҳамчун проексия (яъне функсия бо далелҳои қисман муайяншуда) -и функсияи интихобшуда муайян карда мешавад, як аргумент (ҷадвал) мавҷуд нест. Агар мо коркарди пешакиро ба ҷадвал татбиқ кунем, мо ҷадвали фишурдашударо мегирем.

Марҳилаи дуюм навсозии ҷадвали ҷамъшуда мебошад. Биёед аввал алгоритмро бо псевдокод нависем:

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

Дар Q, ба ҷои ҳалқаҳо истифода бурдани функсияҳои харита/камкунӣ маъмул аст. Аммо азбаски Q забони векторист ва мо метавонем ҳама амалҳоро якбора ба ҳама рамзҳо ба осонӣ татбиқ кунем, пас ба наздикшавии аввал мо метавонем умуман бидуни ҳалқа иҷро кунем ва дар як вақт дар ҳама рамзҳо амалҳоро иҷро кунем:

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

Аммо мо метавонем пеш равем, Q дорои оператори беназир ва бениҳоят пурқувват - оператори таъиноти умумӣ мебошад. Он ба шумо имкон медиҳад, ки маҷмӯи арзишҳоро дар сохтори мураккаби додаҳо бо истифода аз рӯйхати индексҳо, функсияҳо ва аргументҳо тағир диҳед. Дар ҳолати мо ин чунин ба назар мерасад:

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;…)];

Мутаассифона, барои таъин кардани ҷадвал ба шумо рӯйхати сатрҳо лозим аст, на сутунҳо ва шумо бояд матритсаро (рӯйхати сутунҳо ба рӯйхати сатрҳо) бо истифода аз функсияи флип интиқол диҳед. Ин барои ҷадвали калон гарон аст, бинобар ин, мо ба ҷои он супориши умумиро ба ҳар як сутун алоҳида бо истифода аз функсияи харита татбиқ мекунем (ки ба апостроф монанд аст):

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

Мо боз проекцияи функсияро истифода мебарем. Инчунин қайд кунед, ки дар Q эҷод кардани рӯйхат низ функсия аст ва мо метавонем онро бо истифода аз функсияи every(map) барои гирифтани рӯйхати рӯйхатҳо даъват кунем.

Барои он ки маҷмӯи сутунҳои ҳисобшуда собит набошад, мо ифодаи болоро динамикӣ эҷод мекунем. Биёед аввал функсияҳоро барои ҳисоб кардани ҳар як сутун бо истифода аз тағирёбандаҳои сатр ва inp барои истинод ба маълумоти ҷамъшуда ва воридшуда муайян кунем:

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

Баъзе сутунҳо махсусанд; арзиши аввалини онҳо набояд аз рӯи функсия ҳисоб карда шавад. Мо метавонем муайян кунем, ки он аз рӯи сутуни сатри [`numTrades] якум аст - агар он 0 дошта бошад, пас арзиш аввал аст. Q дорои функсияи интихобӣ - ?[Рӯйхати мантиқӣ; рӯйхат1; рӯйхат2] - ки вобаста ба шарти аргументи аввал арзишро аз рӯйхати 1 ё 2 интихоб мекунад:

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

Дар ин ҷо ман супориши умумиро бо функсияи худ даъват кардам (ифода дар қавсҳои ҷингила). Он арзиши ҷорӣ (далели аввал) ва як далели иловагӣ, ки ман дар параметри 4 мегузаранд, қабул мекунад.

Биёед баландгӯякҳои батареяро алоҳида илова кунем, зеро функсия барои онҳо якхела аст:

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

Ин як супориши муқаррарӣ аз рӯи стандартҳои Q аст, аммо ман якбора рӯйхати арзишҳоро таъин мекунам. Дар охир, биёед функсияи асосиро эҷод кунем:

// ":",/: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),")]}";

Бо ин ифода, ман динамикӣ аз сатр функсияеро эҷод мекунам, ки ифодаи дар боло додашударо дар бар мегирад. Натиҷа чунин хоҳад буд:

{[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])]}

Тартиби баҳодиҳии сутун баргардонида мешавад, зеро дар Q тартиби арзёбӣ аз рост ба чап аст.

Ҳоло мо ду функсияи асосие дорем, ки барои ҳисобҳо заруранд, ба мо лозим аст, ки каме инфрасохтор илова кунем ва хидмат омода аст.

Қадамҳои ниҳоӣ

Мо функсияҳои preprocess ва updateAgg дорем, ки ҳама корро иҷро мекунанд. Аммо ба ҳар ҳол зарур аст, ки гузариши дурусти дақиқаҳо ва ҳисоб кардани индексҳо барои ҷамъоварӣ. Пеш аз ҳама, биёед функсияи 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
 }

Мо инчунин функсияи ролро муайян мекунем, ки дақиқаи ҷорӣро тағир медиҳад:

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

Барои илова кардани аломатҳои нав ба мо функсия лозим мешавад:

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

Ва ниҳоят, функсияи upd (номи анъанавии ин функсия барои хидматҳои Q), ки аз ҷониби муштарӣ барои илова кардани маълумот даъват карда мешавад:

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]; // обновим агрегированную таблицу. Функция ? ищет индекс элементов списка справа в списке слева.
 };

Ҳамааш ҳамин. Ин аст рамзи пурраи хидмати мо, тавре ваъда дода шудааст, ҳамагӣ чанд сатр:

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

санҷиши

Биёед кори хидматро тафтиш кунем. Барои ин, биёед онро дар як раванди алоҳида иҷро кунем (рамзро дар файли service.q ҷойгир кунед) ва функсияи init -ро даъват кунед:

q service.q –p 5566

q)init[]

Дар консоли дигар, раванди дуюми Q-ро оғоз кунед ва ба аввал пайваст шавед:

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

Аввалан, биёед рӯйхати рамзҳоро эҷод кунем - 10000 дона ва функсияро барои сохтани ҷадвали тасодуфӣ илова кунем. Дар консоли дуюм:

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

Ман се рамзи воқеиро ба рӯйхат илова кардам, то ҷустуҷӯи онҳоро дар ҷадвал осонтар кунад. Функсияи rnd ҷадвали тасодуфиро бо n сатр месозад, ки дар он вақт аз t то t+25 миллисония фарқ мекунад.

Акнун шумо метавонед кӯшиш кунед, ки маълумотро ба хидмат фиристед (даҳ соати аввалро илова кунед):

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

Шумо метавонед дар хидмат санҷед, ки ҷадвал нав карда шудааст:

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

Натиҷа:

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

Биёед ҳоло озмоиши сарборӣ гузаронем, то бифаҳмем, ки хидмат дар як дақиқа чӣ қадар маълумотро коркард карда метавонад. Хотиррасон мекунам, ки мо фосилаи навсозиро то 25 миллисония муқаррар кардем. Мувофиқи он, хадамот бояд (ба ҳисоби миёна) ба ҳадди ақал 20 миллисония дар як навсозӣ мувофиқат кунад, то ба корбарон вақти дархости маълумот диҳад. Дар раванди дуюм инҳоро ворид кунед:

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 ду дақиқа аст. Шумо метавонед кӯшиш кунед, ки аввал барои 1000 сатр ҳар 25 миллисония иҷро кунед:

start 1000

Дар ҳолати ман, натиҷа тақрибан як чанд миллисония дар як навсозӣ аст. Ҳамин тавр, ман фавран шумораи сатрҳоро ба 10.000 зиёд мекунам:

start 10000

Натиҷа:

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

Боз, чизи махсус нест, аммо ин 24 миллион сатр дар як дақиқа, 400 ҳазор дар як сония аст. Дар тӯли зиёда аз 25 миллисония, навсозӣ танҳо 5 маротиба суст шуд, зоҳиран вақте ки дақиқа тағир ёфт. Биёед ба 100.000 афзоиш диҳем:

start 100000

Натиҷа:

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

Тавре ки шумо мебинед, хидмат метавонад базӯр мубориза барад, аммо бо вуҷуди ин, он метавонад дар ҳолати худ бимонад. Чунин хачми маълумот (240 миллион сатр дар як дакика) нихоят калон аст; дар чунин мавридхо ба кор андохтани якчанд клонхо (хатто даххо клонхо) хадамот маъмул аст, ки хар кадоми онхо танхо як кисми аломатхоро коркард мекунанд. Бо вуҷуди ин, натиҷа барои забони тафсиршуда, ки асосан ба нигоҳдории маълумот нигаронида шудааст, таъсирбахш аст.

Саволе ба миён меояд, ки чаро вақт бо андозаи ҳар як навсозӣ ба таври ғайрихаттӣ меафзояд. Сабаб дар он аст, ки функсияи коҳиш дар асл як функсияи C мебошад, ки нисбат ба updateAgg хеле самараноктар аст. Аз андозаи муайяни навсозӣ (тақрибан 10.000) оғоз карда, updateAgg ба ҳадди ниҳоии худ мерасад ва сипас вақти иҷрои он аз андозаи навсозӣ вобаста нест. Маҳз ба туфайли қадами пешакӣ Q, ки хидмат қодир аст, ки чунин ҳаҷми маълумотро ҳазм кунад. Ин нишон медиҳад, ки то чӣ андоза муҳим будани интихоби алгоритми дуруст ҳангоми кор бо додаҳои калон. Нуктаи дигар ин дуруст нигоҳ доштани маълумот дар хотира мебошад. Агар маълумот ба таври сутунӣ нигоҳ дошта намешуд ё бо мурури замон фармоиш намедиҳад, он гоҳ мо бо чунин чизе ба монанди гум кардани кэши TLB - набудани суроғаи саҳифаи хотира дар кэши суроғаи протсессор шинос мешудем. Ҷустуҷӯи суроға дар сурати бемуваффақият тақрибан 30 маротиба зиёдтар вақт мегирад ва агар маълумот пароканда бошад, он метавонад хидматро якчанд маротиба суст кунад.

хулоса

Дар ин мақола ман нишон додам, ки пойгоҳи додаҳои KDB+ ва Q на танҳо барои нигоҳ доштани маълумоти калон ва дастрасии осон ба он тавассути интихоб мувофиқанд, балки барои эҷоди хидматҳои коркарди додаҳо, ки қодиранд садҳо миллион сатр/гигабайтҳои маълумотро ҳатто дар як раванди Q. Худи забони Q имкон медиҳад, ки алгоритмҳои марбут ба коркарди додаҳо бо табиати векторӣ, тарҷумони дарунсохташудаи SQL ва маҷмӯи хеле муваффақи функсияҳои китобхона амалӣ карда шаванд.

Ман қайд мекунам, ки дар боло танҳо як қисми он корҳое, ки Q метавонад иҷро кунад, он дорои дигар хусусиятҳои беназир аст. Масалан, як протоколи хеле соддаи IPC, ки сарҳади байни равандҳои инфиродии Q-ро нест мекунад ва ба шумо имкон медиҳад, ки садҳо ин равандҳоро дар як шабакаи ягона муттаҳид кунед, ки метавонанд дар даҳҳо серверҳо дар қисматҳои гуногуни ҷаҳон ҷойгир шаванд.

Манбаъ: will.com

Илова Эзоҳ