Vela → 用於時間序列等的智能緩存

在金融科技領域,我們經常需要處理大量的貨幣匯率資料。 我們從不同的來源獲得數據,每個人對於如何推論明天、後天、下個月甚至未來三年的匯率都有自己的想法。 如果有人能預測利率就好了 正確地,是時候關閉業務並愚蠢地來回換錢了。 有些來源更可靠,有些提供完全垃圾,很少包含幾乎正確的值,但對於異國情調的夫婦來說。 我們的工作是每秒鐘篩選這數以萬計的數值,並確定到底要向客戶展示什麼。 我們需要從大量的污垢和淤泥中過濾出一個正確的值,就像火烈鳥在午餐時所做的那樣。

Vela → 用於時間序列等的智能緩存

火烈鳥的一個顯著特徵是它們巨大的向下彎曲的喙,它們用它從水或泥土中過濾食物。
  -  維基

圖書館就這樣誕生了 Vela,它以指定的時間間隔儲存多個值的狀態快取。 在幕後,它可以動態過濾掉不良和過時的數據,並提供對最新數據的訪問 N 每個鍵的驗證值(在我們的例子中是貨幣對)。

假設我們收集三種貨幣對的匯率。 最簡單的定義 Vela 要儲存當前狀態,它看起來像這樣:

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

更新值

Vela.put/3 該函數將按順序執行以下操作:

  • 將造成 validator 如果定義了值(請參閱章節 驗證 以下);
  • 如果驗證成功,則將該值新增至有效值行,或新增至服務行 :__errors__ 否則;
  • 如果 sorter 為給定的鍵定義,或簡單地將值放在清單的頭部(LIFO,參見章節 排序 以下);
  • 將根據參數修剪行 :limit 傳承於創造;
  • 將返回更新後的結構 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]}

Vela 實施 Access,因此您可以使用任何標準函數來深度更新武庫中的結構來更新值 Kernel: Kernel.get_in/2, Kernel.put_in/3, Kernel.update_in/3, Kernel.pop_in/2Kernel.get_and_update_in/3.

驗證

驗證器可以定義為:

  • 帶一個參數的外部函數 (&MyMod.my_fun/1),它只會接收用於驗證的值;
  • 有兩個參數的外部函數, &MyMod.my_fun/2,她會得到一雙 serie, value 用於驗證;
  • 模組實現 Vela.Validator;
  • 配置參數 threshold,並且 - 可選 - compare_by,參見章節 競品對比 下方。

如果驗證成功,則將值新增至對應鍵下的清單中;否則,將元組新增至清單中 {serie, value}:__errors_.

對照

這些行中儲存的值可以是任何值。 去教 Vela 為了比較它們,需要轉移 compare_by 系列定義中的參數(除非該值無法與標準進行比較) Kernel.</2); 此參數必須是類型 (Vela.value() -> number())。 預設很簡單 & &1.

另外,您可以將參數傳遞給行定義 comparator 計算增量值(min/max); 例如,透過傳輸 Date.diff/2 作為比較器,您可以獲得正確的日期增量。

另一種方便的工作方式是傳遞參數 threshold,它定義了新值與 {min, max} 間隔。 由於它被指定為百分比,因此檢查不使用 comparator但仍使用 compare_by。 例如,要指定日期時間的閾值,您必須指定 compare_by: &DateTime.to_unix/1 (得到整數值)和 threshold: 1,導致只有在新值存在的情況下才允許使用新值 ±band 與目前值的間隔。

最後,您可以使用 Vela.equal?/2 比較兩個快取。 如果值定義了一個函數 equal?/2compare/2,那麼就用這些函數來進行比較,不然我們就傻乎乎的用 ==/2.

獲取值

處理當前狀態通常從呼叫開始 Vela.purge/1,這會刪除過時的值(如果 validatortimestamps)。 然後你可以打電話 Vela.slice/1這將返回 keyword 以行名稱作為鍵和第一個實際值。

您也可以使用 get_in/2/pop_in/2 用於對每行中的值進行低階存取。

應用

Vela 作為進程狀態下的時間序列快取非常有用,例如 GenServer/Agent。 我們希望永遠不要使用過時的課程值,為此,我們只需保持流程的狀態已處理 Vela,驗證器如下所示。

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

и Vela.purge/1 每次我們需要資料時,都會悄悄地刪除所有陳舊的值。 要存取實際值,我們只需調用 Vela.slice/1,當需要課程的一小部分歷史記錄(整個系列)時,我們只需返回它(已經排序)和經過驗證的值。

快樂的時間序列快取!

來源: www.habr.com

添加評論