Vela → chytrá cache pro časové řady a nejen to

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ě.

Vela → chytrá cache pro časové řady a nejen to

Jedinečným charakteristickým znakem plameňáka je masivní zakřivený dolů zobák, kterým filtrují potravu z vody nebo bláta.
 — Wiki

Tak vznikla knihovna Vela, 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
end

Aktualizace hodnot

Vela.put/3 funkce postupně udělá následující:

  • vyvolá validator na 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 sorter definová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 :limit př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 Přístup, takže pro aktualizaci hodnot lze použít jakoukoli ze standardních funkcí pro hlubokou aktualizaci struktur z arsenálu Kernel: Kernel.get_in/2, Kernel.put_in/3, Kernel.update_in/3, Kernel.pop_in/2, a Kernel.get_and_update_in/3.

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ár serie, value k validaci;
  • modul implementující Vela.Validator;
  • 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_age

a 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

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster