Vela → smart cache för tidsserier och mer

Inom fintech måste vi ofta bearbeta ganska stora volymer av valutakursdata. Vi får data från olika källor, och var och en av dem har sin egen uppfattning om hur man extrapolerar växelkurser för imorgon, i övermorgon, nästa månad och till och med de kommande tre åren. Om bara någon kunde förutsäga kurser korrekt, det skulle vara dags att stänga verksamheten och bara dumt växla pengar fram och tillbaka. Vissa källor är mer tillförlitliga, vissa tillhandahåller komplett sopor, med sällsynta inneslutningar av nästan korrekta värden, men för exotiska par. Vårt jobb är att sålla igenom dessa tiotusentals värden per sekund och bestämma exakt vad som ska visas för kunderna. Vi måste filtrera bort ett korrekt värde från massor av smuts och slam, precis som flamingos gör vid lunch.

Vela → smart cache för tidsserier och mer

En speciell utmärkande egenskap hos flamingos är deras massiva nedåtböjda näbb, med vilken de filtrerar mat från vatten eller lera.
 - Vicki

Därmed föddes biblioteket Vela, som lagrar ett tillståndscache för flera värden vid specificerade tidsintervall. Under huven filtrerar den bort dålig och föråldrad data i farten, och ger även tillgång till det senaste N validerade värden för varje nyckel (valutapar, i vårt fall).

Låt oss säga att vi samlar in kurser för tre valutapar. Enklaste definitionen Vela för att lagra det aktuella tillståndet ser det ut ungefär så här:

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

Uppdaterar värden

Vela.put/3 Funktionen kommer att göra följande i följd:

  • kommer orsaka validator på värdet, om ett sådant är definierat (se kapitel Godkännande Nedan);
  • kommer att lägga till värdet antingen till raden med bra värden om valideringen lyckades, eller till serviceraden :__errors__ annat;
  • kommer att orsaka sortering om sorter definieras för en given nyckel, eller kommer helt enkelt att sätta värdet högst upp i listan (LIFO, se kapitel Сортировка Nedan);
  • kommer att trimma raden enligt parametern :limit övergick till skapelsen;
  • kommer att returnera den uppdaterade 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]}

också Vela redskap Access, så att du kan använda vilken som helst av standardfunktionerna för djupuppdatering av strukturer från arsenalen för att uppdatera värden Kernel: Kernel.get_in/2, Kernel.put_in/3, Kernel.update_in/3, Kernel.pop_in/2och Kernel.get_and_update_in/3.

Godkännande

En validator kan definieras som:

  • extern funktion med ett argument (&MyMod.my_fun/1), kommer den bara att få värdet för validering;
  • extern funktion med två argument, &MyMod.my_fun/2, hon ska få ett par serie, value för validering;
  • modulimplementering Vela.Validator;
  • konfigurationsparameter threshold, och - valfritt - compare_by, se kapitel Jämförelse nedan.

Om valideringen lyckas läggs värdet till i listan under motsvarande nyckel, annars tupeln {serie, value} går till :__errors_.

jämförelse

Värdena som lagras i dessa rader kan vara vad som helst. Att undervisa Vela för att jämföra dem är det nödvändigt att överföra compare_by parameter i seriedefinitionen (såvida inte värdena inte kan jämföras med standarden Kernel.</2); denna parameter måste vara av typen (Vela.value() -> number()). Som standard är det enkelt & &1.

Du kan också skicka en parameter till raddefinitionen comparator för att beräkna deltavärden (min/max); till exempel genom att sända Date.diff/2 som en jämförelse kan du få rätt delta för datum.

Ett annat bekvämt sätt att arbeta är att skicka en parameter threshold, som definierar det maximalt tillåtna förhållandet för det nya värdet till {min, max} intervall. Eftersom det anges som en procentsats används inte checken comparatormen använder fortfarande compare_by. Till exempel, för att ange ett tröskelvärde för datum och tider, måste du ange compare_by: &DateTime.to_unix/1 (för att få ett heltalsvärde) och threshold: 1, vilket gör att nya värden endast tillåts om de finns i ±band intervall från de aktuella värdena.

Äntligen kan du använda Vela.equal?/2 att jämföra två cacher. Om värdena definierar en funktion equal?/2 eller compare/2, då kommer dessa funktioner att användas för jämförelse, annars använder vi dumt ==/2.

Få värden

Bearbetning av det aktuella tillståndet börjar vanligtvis med att ringa Vela.purge/1, som tar bort föråldrade värden (if validator knuten till timestamps). Då kan du ringa Vela.slice/1som kommer tillbaka keyword med radnamn som nycklar och de första, faktiska värdena.

Du kan också använda get_in/2/pop_in/2 för tillgång på låg nivå till värdena i varje rad.

ansökan

Vela kan vara extremt användbar som en tidsseriecache i ett processtillstånd som GenServer/Agent. Vi vill aldrig använda inaktuella kursvärden, och för att göra detta håller vi helt enkelt processen med staten behandlad Vela, med validatorn som visas nedan.

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

и Vela.purge/1 tar tyst bort alla inaktuella värden varje gång vi behöver data. För att komma åt de faktiska värdena ringer vi helt enkelt Vela.slice/1, och när en liten historik över kursen krävs (hela serien) returnerar vi den helt enkelt - redan sorterad - med validerade värden.

Glad tidsseriecachning!

Källa: will.com

Lägg en kommentar