Vela → smart cache til tidsserier og mere

I fintech er vi ofte nødt til at behandle ganske massive mængder af valutakursdata. Vi får data fra forskellige kilder, og hver af dem har sin egen idé om, hvordan man ekstrapolerer valutakurser for i morgen, i overmorgen, næste måned og endda de næste tre år. Hvis bare nogen kunne forudsige priserne korrekt, ville det være tid til at lukke forretningen og bare dumt skifte penge frem og tilbage. Nogle kilder er mere pålidelige, nogle leverer komplet affald, med sjældne indeslutninger af næsten korrekte værdier, men for eksotiske par. Vores opgave er at gennemsøge disse titusindvis af værdier i sekundet og bestemme, hvad der præcist skal vises til kunderne. Vi er nødt til at filtrere den ene korrekte værdi fra tonsvis af snavs og silt, ligesom flamingoer gør til frokost.

Vela → smart cache til tidsserier og mere

Et særligt kendetegn ved flamingoer er deres massive nedadbøjede næb, som de filtrerer mad fra vand eller mudder med.
 — R'RoRєRo

Således blev biblioteket født Vela, som gemmer en tilstandscache for flere værdier med angivne tidsintervaller. Under motorhjelmen filtrerer den dårlige og forældede data fra i farten, og giver også adgang til det nyeste 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 ser det 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 en er defineret (se kapitel Validering under);
  • vil tilføje værdien enten til rækken af ​​gode værdier, hvis valideringen var vellykket, eller til servicerækken :__errors__ Ellers;
  • vil forårsage sortering hvis sorter defineret for en given nøgle, eller vil blot sætte værdien øverst på listen (LIFO, se kapitel Сортировка under);
  • vil trimme rækken i henhold til parameteren :limit overgået skabelsen;
  • 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 enhver af standardfunktionerne til dyb opdatering af strukturer fra arsenal til opdatering af værdier 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 et argument (&MyMod.my_fun/1), vil den kun modtage værdien til validering;
  • ekstern funktion med to argumenter, &MyMod.my_fun/2, hun får et par serie, value til validering;
  • modul implementering 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 tuplen {serie, value} går til :__errors_.

sammenligning

Værdierne gemt i disse rækker kan være hvad som helst. At lære Vela for at sammenligne dem, er det nødvendigt at overføre compare_by parameter i seriedefinitionen (medmindre værdierne ikke kan sammenlignes med standarden Kernel.</2); denne parameter skal være af typen (Vela.value() -> number()). Som standard er det enkelt & &1.

Du kan også sende en parameter til rækkedefinitionen comparator at beregne delta værdier (min/max); for eksempel ved at sende Date.diff/2 som en komparator kan du få de korrekte deltaer for datoer.

En anden bekvem måde at arbejde på er at videregive en parameter threshold, som definerer det maksimalt tilladte forhold mellem den nye værdi til {min, max} interval. Da det er angivet som en procentdel, bruger checken ikke comparatormen bruger stadig compare_by. For at angive en tærskelværdi for dato-tider, skal du f.eks. angive compare_by: &DateTime.to_unix/1 (for at få en heltalsværdi) og threshold: 1, hvilket bevirker, 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 caches. Hvis værdierne definerer en funktion equal?/2 eller compare/2, så vil disse funktioner blive brugt til sammenligning, ellers bruger vi dumt ==/2.

At få værdier

Behandling af den aktuelle tilstand starter normalt med opkald Vela.purge/1, som fjerner forældede værdier (hvis validator bundet til timestamps). Så kan du ringe Vela.slice/1som vil vende tilbage keyword med rækkenavne 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 tidsseriecache i en procestilstand som GenServer/Agent. Vi ønsker aldrig at bruge forældede kursusværdier, og for at gøre dette beholder vi simpelthen processen med staten behandlet 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 faktiske værdier ringer vi blot Vela.slice/1, og når der kræves en lille historik over kurset (hele serien), returnerer vi den simpelthen - allerede sorteret - med validerede værdier.

God tidsserie-caching!

Kilde: www.habr.com

Tilføj en kommentar