Vela → chytrá mezipaměť pro časové řady a další

Ve fintech musíme často zpracovávat poměrně masivní objemy dat o směnných kurzech měn. Získáváme data z různých zdrojů a každý z nich má svou vlastní představu o tom, jak extrapolovat směnné kurzy na zítřek, pozítří, příští měsíc a dokonce i další tři roky. Kdyby tak někdo dokázal odhadnout sazby správně, bylo by načase zavřít živnost a jen hloupě měnit peníze tam a zpět. Některé zdroje jsou spolehlivější, některé dodávají úplný odpad, se vzácnými inkluzemi téměř správných hodnot, ale pro exotické páry. Naším úkolem je prosít tyto desítky tisíc hodnot za sekundu a určit, co přesně ukázat zákazníkům. Musíme odfiltrovat jednu správnou hodnotu z tuny špíny a bahna, stejně jako to dělají plameňáci při obědě.

Vela → chytrá mezipaměť pro časové řady a další

Zvláštním poznávacím znakem plameňáků je jejich mohutný dolů zahnutý zobák, kterým filtrují potravu z vody nebo bahna.
 - Wiki

Tak vznikla knihovna Vela, která ukládá stavovou mezipaměť pro více hodnot v určených časových intervalech. Pod kapotou za chodu filtruje špatná a zastaralá data a také poskytuje přístup k nejnovějším N ověřené hodnoty pro každý klíč (v našem případě páry měn).

Řekněme, že shromažďujeme kurzy pro tři měnové páry. Nejjednodušší definice Vela pro uložení aktuálního stavu to bude vypadat nějak takto:

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

Aktualizace hodnot

Vela.put/3 Funkce provede následující v pořadí:

  • způsobí validator na hodnotě, pokud je definována (viz kapitola Validace níže);
  • přidá hodnotu buď do řádku dobrých hodnot, pokud bylo ověření úspěšné, nebo do řádku služby :__errors__ v opačném případě;
  • způsobí třídění, pokud sorter definovaný pro daný klíč, nebo jednoduše umístí hodnotu na začátek seznamu (LIFO, viz kapitola Třídit níže);
  • ořízne řádek podle parametru :limit předán stvoření;
  • vrátí aktualizovanou strukturu Vela.

iex|1 > pairs = %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 nářadí Access, takže k aktualizaci hodnot můžete použít kteroukoli ze standardních funkcí pro hlubokou aktualizaci struktur z arzená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 lze definovat jako:

  • externí funkce s jedním argumentem (&MyMod.my_fun/1), obdrží hodnotu pouze pro ověření;
  • externí funkce se dvěma argumenty, &MyMod.my_fun/2, dostane pár serie, value pro validaci;
  • implementace modulu Vela.Validator;
  • konfigurační parametr thresholda - volitelně - compare_by, viz kapitola Porovnání níže.

Pokud je ověření úspěšné, hodnota je přidána do seznamu pod odpovídající klíč, v opačném případě n-tice {serie, value} poslal v :__errors_.

Porovnání

Hodnoty uložené v těchto řádcích mohou být jakékoli. Učit Vela pro jejich porovnání je nutné přenést compare_by parametr v definici série (pokud hodnoty nelze porovnat se standardem Kernel.</2); tento parametr musí být typu (Vela.value() -> number()). Ve výchozím nastavení je to jednoduché & &1.

Také můžete předat parametr definici řádku comparator vypočítat hodnoty delta (min/max); například vysíláním Date.diff/2 jako komparátor můžete získat správné delty pro data.

Dalším pohodlným způsobem práce je předání parametru threshold, který definuje maximální přípustný poměr nové hodnoty k {min, max} interval. Protože je zadána v procentech, kontrola se nepoužívá comparatorale stále používá compare_by. Chcete-li například zadat prahovou hodnotu pro datum a čas, musíte zadat compare_by: &DateTime.to_unix/1 (pro získání celočíselné hodnoty) a threshold: 1, což způsobí, že nové hodnoty budou povoleny pouze v případě, že jsou v ±band interval od aktuálních hodnot.

Nakonec můžete použít Vela.equal?/2 pro porovnání dvou keší. Pokud hodnoty definují funkci equal?/2 nebo compare/2, pak budou tyto funkce použity pro srovnání, jinak hloupě používáme ==/2.

Získávání hodnot

Zpracování aktuálního stavu obvykle začíná voláním Vela.purge/1, který odstraňuje zastaralé hodnoty (pokud validator vázáno na timestamps). Pak můžete zavolat Vela.slice/1která se vrátí keyword s názvy řádků jako klíči a prvními skutečnými hodnotami.

Můžete také 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 velmi užitečná jako mezipaměť časových řad ve stavu procesu, jako je GenServer/Agent. Chceme nikdy nepoužívat zastaralé hodnoty kurzu, a proto jednoduše udržujeme proces se stavem zpracovaný Vela, s validátorem zobrazeným níže.

@impl Vela.Validator
def valid?(_key, %Rate{} = rate),
  do: Rate.age(rate) < @death_age

и Vela.purge/1 tiše odstraní všechny zastaralé hodnoty pokaždé, když data potřebujeme. Pro přístup ke skutečným hodnotám jednoduše zavoláme Vela.slice/1, a když je vyžadována malá historie kurzu (celá řada), jednoduše ji vrátíme - již seřazenou - s ověřenými hodnotami.

Šťastné ukládání časových řad do mezipaměti!

Zdroj: www.habr.com

Přidat komentář