Vela → smart cache for tidsserier og mer

I fintech må vi ofte behandle ganske massive mengder valutakursdata. Vi får data fra forskjellige kilder, og hver av dem har sin egen idé om hvordan man kan ekstrapolere valutakurser for i morgen, i overmorgen, neste måned og til og med de neste tre årene. Hvis bare noen kunne forutsi priser riktig, ville det være på tide å stenge virksomheten og bare dumt bytte penger frem og tilbake. Noen kilder er mer pålitelige, noen leverer fullstendig søppel, med sjeldne inkluderinger av nesten korrekte verdier, men for eksotiske par. Vår jobb er å sile gjennom disse titusenvis av verdier per sekund og finne ut hva som skal vises til kundene. Vi må filtrere ut den ene riktige verdien fra tonnevis med skitt og silt, akkurat som flamingoer gjør til lunsj.

Vela → smart cache for tidsserier og mer

Et spesielt kjennetegn ved flamingoer er deres massive nedoverbuede nebb, som de filtrerer mat fra vann eller gjørme med.
 - Vicki

Slik ble biblioteket født Vela, som lagrer en tilstandsbuffer for flere verdier med spesifiserte tidsintervaller. Under panseret filtrerer den bort dårlige og utdaterte data i farten, og gir også tilgang til det siste N validerte verdier for hver nøkkel (valutapar, i vårt tilfelle).

La oss si at vi samler inn kurser for tre valutapar. Enkleste definisjon Vela for å lagre gjeldende tilstand vil det se omtrent slik ut:

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

Oppdaterer verdier

Vela.put/3 Funksjonen vil gjøre følgende i rekkefølge:

  • vil forårsake validator på verdien, hvis en er definert (se kapittel Validering under);
  • vil legge til verdien enten til raden med gode verdier hvis valideringen var vellykket, eller til tjenesteraden :__errors__ ellers;
  • vil føre til sortering hvis sorter definert for en gitt nøkkel, eller vil ganske enkelt sette verdien øverst på listen (LIFO, se kapittel Сортировка under);
  • vil trimme raden i henhold til parameteren :limit gått over skapelsen;
  • vil returnere den oppdaterte strukturen 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 redskaper Access, slik at du kan bruke hvilken som helst av standardfunksjonene for dyp oppdatering av strukturer fra arsenalet til å oppdatere verdier 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 funksjon med ett argument (&MyMod.my_fun/1), vil den bare motta verdien for validering;
  • ekstern funksjon med to argumenter, &MyMod.my_fun/2, hun får et par serie, value for validering;
  • modulimplementering Vela.Validator;
  • konfigurasjonsparameter threshold, og - valgfritt - compare_by, se kapittel Sammenligning nedenfor.

Hvis valideringen er vellykket, legges verdien til listen under den tilsvarende nøkkelen, ellers tuppelen {serie, value} går til :__errors_.

sammenligning

Verdiene som er lagret i disse radene kan være hva som helst. Å lære Vela for å sammenligne dem, er det nødvendig å overføre compare_by parameter i seriedefinisjonen (med mindre verdiene ikke kan sammenlignes med standarden Kernel.</2); denne parameteren må være av typen (Vela.value() -> number()). Som standard er det enkelt & &1.

Du kan også sende en parameter til raddefinisjonen comparator å beregne delta-verdier (min/max); for eksempel ved å sende Date.diff/2 som en komparator kan du få de riktige deltaene for datoer.

En annen praktisk måte å jobbe på er å sende en parameter threshold, som definerer det maksimalt tillatte forholdet mellom den nye verdien til {min, max} intervall. Siden det er angitt som en prosentandel, bruker ikke sjekken comparatormen bruker fortsatt compare_by. For å angi en terskelverdi for dato og klokkeslett, må du for eksempel spesifisere compare_by: &DateTime.to_unix/1 (for å få en heltallsverdi) og threshold: 1, noe som gjør at nye verdier bare tillates hvis de er inne ±band intervall fra gjeldende verdier.

Til slutt kan du bruke Vela.equal?/2 å sammenligne to cacher. Hvis verdiene definerer en funksjon equal?/2 eller compare/2, så vil disse funksjonene bli brukt for sammenligning, ellers bruker vi dumt ==/2.

Å få verdier

Behandling av gjeldende tilstand starter vanligvis med å ringe Vela.purge/1, som fjerner foreldede verdier (hvis validator bundet til timestamps). Da kan du ringe Vela.slice/1som kommer tilbake keyword med radnavn som nøkler og de første, faktiske verdiene.

Du kan også bruke get_in/2/pop_in/2 for tilgang på lavt nivå til verdiene i hver rad.

App

Vela kan være ekstremt nyttig som en tidsseriebuffer i en prosesstilstand som GenServer/Agent. Vi ønsker å aldri bruke foreldede kursverdier, og for å gjøre dette holder vi rett og slett prosessen 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 alle foreldede verdier hver gang vi trenger dataene. For å få tilgang til de faktiske verdiene ringer vi bare Vela.slice/1, og når det kreves en liten historikk for kurset (hele serien), returnerer vi det ganske enkelt - allerede sortert - med validerte verdier.

God tidsserie-caching!

Kilde: www.habr.com

Legg til en kommentar