Vela → cache inteligentă pentru serii cronologice și multe altele

În fintech, trebuie adesea să procesăm volume destul de masive de date privind cursul de schimb valutar. Obținem date din diferite surse și fiecare dintre ele are propria idee despre cum să extrapolăm cursurile de schimb pentru mâine, poimâine, luna viitoare și chiar următorii trei ani. Dacă cineva ar putea prezice ratele corect, ar fi timpul să închidem afacerea și să schimbăm prostesc banii înainte și înapoi. Unele surse sunt mai de încredere, unele furnizează gunoi complet, cu includeri rare de valori aproape corecte, dar pentru cuplurile exotice. Sarcina noastră este să cercetăm aceste zeci de mii de valori pe secundă și să stabilim ce anume să arătăm clienților. Trebuie să filtram singura valoare corectă din tone de murdărie și nămol, la fel cum fac flamingii la prânz.

Vela → cache inteligentă pentru serii cronologice și multe altele

O trăsătură distinctivă specială a flamingo este ciocul lor masiv curbat în jos, cu care filtrează alimentele din apă sau noroi.
 - Vicki

Astfel s-a născut biblioteca Vela, care stochează un cache de stare pentru mai multe valori la intervale de timp specificate. Sub capotă, filtrează din mers datele proaste și învechite și oferă, de asemenea, acces la cele mai recente N valori validate pentru fiecare cheie (perechi valutare, în cazul nostru).

Să presupunem că colectăm rate pentru trei perechi valutare. Cea mai simplă definiție Vela pentru a stoca starea curentă va arăta cam așa:

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

Actualizarea valorilor

Vela.put/3 Funcția va face următoarele în secvență:

  • va cauza validator asupra valorii, dacă este definită una (vezi capitolul Validare de mai jos);
  • va adăuga valoarea fie la rândul de valori bune dacă validarea a avut succes, fie la rândul de servicii :__errors__ in caz contrar;
  • va provoca sortarea dacă sorter definit pentru o anumită cheie sau pur și simplu va pune valoarea în capul listei (LIFO, vezi capitolul triere de mai jos);
  • va tăia rândul conform parametrului :limit transmis la creație;
  • va returna structura actualizată 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]}

De asemenea Vela unelte Access, astfel încât să puteți utiliza oricare dintre funcțiile standard pentru actualizarea profundă a structurilor din arsenal pentru a actualiza valori Kernel: Kernel.get_in/2, Kernel.put_in/3, Kernel.update_in/3, Kernel.pop_in/2, și Kernel.get_and_update_in/3.

Validare

Un validator poate fi definit ca:

  • funcție externă cu un singur argument (&MyMod.my_fun/1), va primi doar valoarea pentru validare;
  • funcție externă cu două argumente, &MyMod.my_fun/2, va primi o pereche serie, value pentru validare;
  • implementarea modulelor Vela.Validator;
  • parametrul de configurare thresholdși - opțional - compare_by, vezi capitolul Comparaţie de mai jos.

Dacă validarea are succes, valoarea este adăugată la listă sub cheia corespunzătoare, în caz contrar, tuplu {serie, value} se duce la :__errors_.

comparație

Valorile stocate în aceste rânduri pot fi orice. A invata Vela pentru a le compara, este necesar să se transfere compare_by parametrul în definiția seriei (cu excepția cazului în care valorile nu pot fi comparate cu standardul Kernel.</2); acest parametru trebuie să fie de tip (Vela.value() -> number()). Implicit este simplu & &1.

De asemenea, puteți trece un parametru definiției rândului comparator pentru a calcula valorile delta (min/max); de exemplu prin transmitere Date.diff/2 ca comparator, puteți obține deltele corecte pentru date.

Un alt mod convenabil de a lucra este să treci un parametru threshold, care definește raportul maxim permis al noii valori la {min, max} interval. Deoarece este specificat ca procent, cecul nu folosește comparatordar încă folosește compare_by. De exemplu, pentru a specifica o valoare de prag pentru data orelor, trebuie să specificați compare_by: &DateTime.to_unix/1 (pentru a obține o valoare întreagă) și threshold: 1, ceea ce face ca noile valori să fie permise numai dacă sunt în ±band interval de la valorile curente.

În sfârșit, puteți folosi Vela.equal?/2 pentru a compara două cache-uri. Dacă valorile definesc o funcție equal?/2 sau compare/2, atunci aceste funcții vor fi folosite pentru comparație, altfel folosim prostește ==/2.

Obținerea de valori

Procesarea stării curente începe de obicei cu un apel Vela.purge/1, care elimină valorile învechite (dacă validator legat de timestamps). Apoi puteți suna Vela.slice/1care se va întoarce keyword cu nume de rând ca chei și primele valori reale.

Puteți utiliza, de asemenea get_in/2/pop_in/2 pentru acces la nivel scăzut la valorile din fiecare rând.

App

Vela poate fi extrem de util ca cache de serie de timp într-o stare de proces cum ar fi GenServer/Agent. Vrem să nu folosim niciodată valori de curs învechite și pentru a face acest lucru pur și simplu păstrăm procesul cu starea procesată Vela, cu validatorul prezentat mai jos.

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

и Vela.purge/1 elimină în liniște toate valorile învechite de fiecare dată când avem nevoie de date. Pentru a accesa valorile reale, sunăm pur și simplu Vela.slice/1, iar când este necesar un mic istoric al cursului (întreaga serie), pur și simplu îl returnăm - deja sortat - cu valori validate.

Memorare fericită în serii cronologice!

Sursa: www.habr.com

Adauga un comentariu