Vela → smart cache til tidsserier og mere

Inden for fintech er vi ofte nødt til at behandle ret enorme mængder af valutakursdata. Vi får data fra forskellige kilder, og hver af dem har sin egen idé om, hvordan man ekstrapolerer valutakursværdier for i morgen, i overmorgen, den næste måned og endda de næste tre år. Hvis bare nogen kunne forudsige valutakurser korrekt, ville det være på tide at lukke forretningen og bare dumt veksle penge frem og tilbage. Nogle kilder er mere pålidelige, andre leverer intet andet end skrammel, med sjældne inkluderinger af næsten korrekte værdier, men for eksotiske par. Vores opgave er at sortere disse titusindvis af værdier i sekundet og bestemme præcis, hvad der skal vises til kunderne. Vi er nødt til at filtrere den eneste korrekte betydning fra en masse snavs og silt, ligesom flamingoer gør til frokost.

Vela → smart cache til tidsserier og mere

Et karakteristisk træk ved flamingoer er deres massive, nedadbuede næb, som de bruger til at filtrere mad fra vand eller mudder.
 — R'RoRєRo

Sådan blev biblioteket født Vela, som lagrer en cache med tilstande for flere værdier med bestemte tidsintervaller. Under motorhjelmen filtrerer den dårlige og forældede data fra undervejs og giver adgang til de seneste N validerede værdier for hver nøgle (valutapar, i vores tilfælde).

Lad os sige, at vi indsamler kurser for tre valutapar. Den enkleste definition Vela For at gemme den aktuelle tilstand vil det se sådan ud:

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

Opdatering af værdier

Vela.put/3 Funktionen vil gøre følgende i rækkefølge:

  • vil forårsage validator på værdien, hvis defineret (se kapitel Validering under);
  • vil tilføje værdien enten til rækken med den gode værdi, hvis valideringen lykkes, eller til servicerækken :__errors__ ellers;
  • vil forårsage sortering, hvis sorter defineret for den givne nøgle, eller blot placere værdien øverst på listen (LIFO, se kapitel Сортировка under);
  • vil klippe rækken i henhold til parameteren :limit overført under oprettelsen;
  • vil returnere den opdaterede struktur 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]}

Også Vela redskaber Access, så du kan bruge en hvilken som helst af standardfunktionerne til dybdegående opdatering af strukturer fra arsenalet for at opdatere værdierne Kernel: Kernel.get_in/2, Kernel.put_in/3, Kernel.update_in/3, Kernel.pop_in/2og Kernel.get_and_update_in/3.

Validering

En validator kan defineres som:

  • ekstern funktion med ét argument (&MyMod.my_fun/1), vil den kun modtage en værdi til validering;
  • ekstern funktion med to argumenter, &MyMod.my_fun/2, hun får et par serie, value til validering;
  • modulimplementering Vela.Validator;
  • konfigurationsparameter threshold, og - valgfrit - compare_by, se kapitel Sammenligning nedenfor.

Hvis valideringen lykkes, tilføjes værdien til listen under den tilsvarende nøgle, ellers en tuple {serie, value} går til :__errors_.

sammenligning

Værdierne, der er gemt i disse rækker, kan være hvad som helst. At undervise Vela for at sammenligne dem, er det nødvendigt at formidle compare_by parameter i definitionen af ​​en serie (medmindre værdierne kan sammenlignes ved hjælp af standard Kernel.</2); Denne parameter skal være af typen (Vela.value() -> number()). Som standard er det simpelt & &1.

Du kan også sende en parameter til rækkedefinitionen. comparator at beregne deltaværdier (min/max); for eksempel at bestå Date.diff/2 Som sammenligningsenhed kan du få de korrekte deltaer for datoer.

En anden bekvem måde at arbejde på er at sende en parameter threshold, som definerer det maksimalt tilladte forhold mellem den nye værdi og {min, max} interval. Da det er angivet som en procentdel, bruger checken ikke comparator, men bruger stadig compare_by. For eksempel, for at angive en tærskel for dato og klokkeslæt, skal du angive compare_by: &DateTime.to_unix/1 (for at få en heltalsværdi) og threshold: 1, hvilket vil resultere i, at nye værdier kun tillades, hvis de er i ±band interval fra de aktuelle værdier.

Endelig kan du bruge Vela.equal?/2 at sammenligne to cacher. Hvis værdierne definerer en funktion equal?/2 eller compare/2, så vil disse funktioner blive brugt til sammenligning, ellers bruger vi dumt nok ==/2.

Hentning af værdier

Behandling af den aktuelle tilstand begynder normalt med et opkald Vela.purge/1, som fjerner forældede værdier (hvis validator bundet til timestamps). Så kan du ringe Vela.slice/1, som vil vende tilbage keyword med rækkenavnene som nøgler og de første, faktiske værdier.

Du kan også bruge get_in/2/pop_in/2 for adgang på lavt niveau til værdierne i hver række.

App

Vela kan være yderst nyttig som en cache af tidsserier i en process tilstand som GenServer/Agent. Vi ønsker aldrig at bruge forældede valutakursværdier, og for at gøre dette beholder vi blot en proces med en tilstand, der behandles. Vela, med validatoren vist nedenfor.

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

и Vela.purge/1 fjerner stille og roligt alle forældede værdier, hver gang vi har brug for dataene. For at få adgang til de aktuelle værdier, kalder vi blot Vela.slice/1, og når en lille historik over hastigheden er nødvendig (hele serien), returnerer vi den simpelthen - allerede sorteret - med validerede værdier.

God fornøjelse med tidsserie-caching!

Kilde: www.habr.com

Køb pålidelig hosting til websteder med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster