Във финтех често трябва да обработваме доста огромни обеми от данни за валутните курсове. Получаваме данни от различни източници и всеки от тях има собствена идея как да екстраполира обменните курсове за утре, вдругиден, следващия месец и дори следващите три години. Само ако някой можеше да предвиди курсовете правилно, ще е време да затворите бизнеса и просто глупаво да обменяте пари напред-назад. Някои източници са по-надеждни, някои предоставят пълен боклук, с редки включвания на почти правилни стойности, но за екзотични двойки. Нашата работа е да пресеем тези десетки хиляди стойности в секунда и да определим какво точно да покажем на клиентите. Трябва да филтрираме единствената правилна стойност от тонове мръсотия и тиня, точно както фламингото правят на обяд.
Особена отличителна черта на фламингото е масивният им извит надолу клюн, с който филтрират храната от вода или кал.
- Wiki
Така се ражда библиотеката Vela, който съхранява кеш на състоянието за множество стойности на определени интервали от време. Под капака той филтрира лоши и остарели данни в движение и също така осигурява достъп до най-новите N валидирани стойности за всеки ключ (валутни двойки, в нашия случай).
Да кажем, че събираме курсове за три валутни двойки. Най-простото определение Vela за съхраняване на текущото състояние ще изглежда нещо подобно:
defmodule Pairs do
use Vela,
eurusd: [sorter: &Kernel.<=/2],
eurgbp: [limit: 3, errors: 1],
eurcad: [validator: Pairs]
@behaviour Vela.Validator
@impl Vela.Validator
def valid?(:eurcad, rate), do: rate > 0
end
Актуализиране на стойностите
Vela.put/3 Функцията ще направи следното последователно:
ще причини validator върху стойността, ако такава е дефинирана (вижте глава Валидиране По-долу);
ще добави стойността или към реда с добри стойности, ако валидирането е било успешно, или към реда на услугата :__errors__ в противен случай;
ще доведе до сортиране, ако sorter дефинирана за даден ключ, или просто ще постави стойността в началото на списъка (LIFO, Вижте Глава сортиране По-долу);
ще отреже реда според параметъра :limit предадено при създаване;
конфигурационен параметър thresholdи - по избор - compare_by, Вижте Глава сравнение по-долу.
Ако проверката е успешна, стойността се добавя към списъка под съответния ключ; в противен случай кортежът {serie, value} отива :__errors_.
Сравнение
Стойностите, съхранявани в тези редове, могат да бъдат всякакви. Да преподавам Vela за да ги сравните, е необходимо да прехвърлите compare_by параметър в дефиницията на серията (освен ако стойностите не могат да бъдат сравнени със стандарта Kernel.</2); този параметър трябва да е от тип (Vela.value() -> number()). По подразбиране е просто & &1.
Освен това можете да подадете параметър към дефиницията на реда comparator за изчисляване на делта стойности (min/max); например чрез предаване Date.diff/2 като компаратор можете да получите правилните делти за дати.
Друг удобен начин за работа е предаването на параметър threshold, което определя максимално допустимото съотношение на новата стойност към {min, max} интервал. Тъй като е посочено като процент, проверката не се използва comparatorно все още използва compare_by. Например, за да посочите прагова стойност за дати и часове, трябва да посочите compare_by: &DateTime.to_unix/1 (за да получите цяло число) и threshold: 1, което кара нови стойности да бъдат разрешени само ако са в ±band интервал от текущите стойности.
Накрая можете да използвате Vela.equal?/2 за сравняване на два кеша. Ако стойностите дефинират функция equal?/2 или compare/2, тогава тези функции ще се използват за сравнение, в противен случай ние глупаво използваме ==/2.
Получаване на стойности
Обработката на текущото състояние обикновено започва с повикване Vela.purge/1, който премахва остарелите стойности (ако validator завързан за timestamps). След това можете да се обадите Vela.slice/1което ще се върне keyword с имена на редове като ключове и първите действителни стойности.
Можете също да използвате get_in/2/pop_in/2 за достъп на ниско ниво до стойностите във всеки ред.
App
Vela може да бъде изключително полезно като кеш за времеви серии в състояние на процес като GenServer/Agent. Искаме никога да не използваме остарели стойности на курса и за да направим това, просто поддържаме процеса с обработено състояние Vela, с показания по-долу валидатор.
и Vela.purge/1 тихо премахва всички остарели стойности всеки път, когато имаме нужда от данните. За достъп до действителните стойности просто се обаждаме Vela.slice/1, а когато се изисква малка история на курса (цялата серия), ние просто я връщаме - вече сортирана - с валидирани стойности.