Ve fintechu často musíme zpracovávat poměrně velké objemy údajů o směnných kurzech měn. Získáváme data z různých zdrojů a každý z nich má vlastní představu o tom, jak extrapolovat hodnoty kurzů na zítřek, pozítří, příští měsíc a dokonce i na příští tři roky. Kdyby někdo uměl předpovědět kurzy správně, bylo by na čase zavřít podnik a prostě jednotvárně měnit peníze tam a zpět. Některé zdroje si získávají více důvěry, jiné dodávají samý odpad s občasnými vkládáním téměř správných hodnot, ale zato pro exotické páry. Naší prací je prosít tyto desítky tisíc hodnot za sekundu a určit, co vlastně ukázat zákazníkům. Musíme filtrovat jediné správné hodnoty z tuny špíny a bláta, jak to dělají plameňáci při obědě.

Jedinečným charakteristickým znakem plameňáka je masivní zakřivený dolů zobák, kterým filtrují potravu z vody nebo bláta.
—
Tak vznikla knihovna , která uchovává cache stavu pro několik hodnot v určených časových intervalech. Pod kapotou na místě odfiltrovává špatné a zastaralé údaje a také poskytuje přístup k posledním N validovaným hodnotám pro každý klíč (v našem případě měnové páry).
Představme si, že sbíráme kurzy pro tři měnové páry. Nejjednodušší definice Vela pro uložení aktuálního stavu by vypadala nějak takto:
defmodule Pairs do
use Vela,
eurusd: [sorter: &Kernel. 0
endAktualizace hodnot
funkce postupně udělá následující:
- vyvolá
validatorna hodnotě, pokud je takový definován (viz část Validace níže); - přidá hodnotu buď do řady dobrých hodnot, pokud byla validace úspěšná, nebo do pomocné řady
:__errors__v opačném případě; - vyvolá třídění, pokud je
sorterdefinován pro daný klíč, nebo jednoduše uloží hodnotu na začátek seznamu (LIFO, viz část Třídění níže); - zkrátí řadu podle parametru
:limitpředaného při vytvoření; - vrátí aktualizovanou strukturu
Vela.
iex|1 > páry = %Pairs{}
iex|2 > Vela.put(pairs, :eurcad, 1.0)
#⇒ %Pairs{..., eurcad: [1.0], ...}
iex|3 > Vela.put(pairs, :eurcad, -1.0)
#⇒ %Pairs{__errors__: [eurcad: -1.0], ...}
iex|4 > pairs |> Vela.put(:eurusd, 2.0) |> Vela.put(:eurusd, 1.0)
#⇒ %Pairs{... eurusd: [1.0, 2.0]}Také Vela implementuje , takže pro aktualizaci hodnot lze použít jakoukoli ze standardních funkcí pro hlubokou aktualizaci struktur z arsenálu : , , , , a .
Validace
Validátor může být definován jako:
- externí funkce s jedním argumentem (
&MyMod.my_fun/1), obdrží pouze hodnotu k validaci; - externí funkce se dvěma argumenty,
&MyMod.my_fun/2, obdrží párserie, valuek validaci; - modul implementující ;
- konfigurační parametr
threshold, a — volitelně —compare_by, viz část Porovnání níže.
Pokud validace proběhla úspěšně, hodnota je přidána do seznamu pod odpovídajícím klíčem, jinak se tuple {serie, value} odesílá do :__errors_.
Porovnání
Hodnoty ukládané v těchto řadách mohou být libovolné. Abychom je naučili porovnávat, je nutné předat Vela parametr do definice řady (pokud hodnoty nemohou být porovnány standardním compare_by Kernel.<\/2 ); tento parametr by měl mít typ(Vela.value() -> number()) . Ve výchozím nastavení je to prostě& &1 Také, do definice řady lze předat parametr.
comparator pro výpočet hodnot rozdílů ( minmax/); například, předánímDate.diff/2 jako komparátoru, lze získat správné rozdíly pro data. Dalším pohodlným způsobem práce je předání parametru
, který určuje maximální povolené poměr nového hodnoty k threshold{min, max} intervalů. Protože je zadán v procentech, kontrola nepoužívá , ale stále používá pro výpočet hodnot rozdílů (. Například, aby bylo nastaveno prahové hodnoty pro časová data, je nutné uvést compare_bycompare_by: &DateTime.to_unix/1 (pro získání celočíselné hodnoty) a threshold: 1 , čímž budou nové hodnoty povoleny, pouze pokud jsou v±band intervalu od aktuálních hodnot. Nakonec lze použít
Vela.equal?/2 porovnat/2 , pokud hodnoty definují funkci equal?/2 nebo compare/2, poté budou tyto funkce použity pro porovnání, jinak jednoduše použijeme ==/2.
Získání hodnot
Zpracování aktuálního stavu obvykle začíná voláním Vela.purge/1, které odstraňuje zastaralé hodnoty (pokud validator je vázán na timestamps). Poté můžete zavolat Vela.slice/1, který vrátí keyword se jmény řádků jako klíči a prvním relevantním hodnotám.
Také můžete použít get_in/2/pop_in/2 pro nízkoúrovňový přístup k hodnotám v každém řádku.
Aplikace
Vela může být mimořádně užitečné jako cache časových řad ve stavu procesu typu GenServer/Agent. Chceme nikdy nepoužívat zastaralé hodnoty kurzů, a proto prostě udržujeme proces se stavem, který zpracováváme Vela, s validátorem uvedeným níže.
@impl Vela.Validator
def valid?(_key, %Rate{} = rate),
do: Rate.age(rate) < @death_agea Vela.purge/1 uchovává všechny zastaralé hodnoty pokaždé, když potřebujeme data. Pro přístup k aktuálním hodnotám jednoduše voláme Vela.slice/1, a když potřebujeme malou historii kurzu (celý řádek jako celek), jednoduše ho vrátíme — již se seřazenými — s validovanými hodnotami.
Úspěšné cachování časových řad!
Zdroj: habr.com
