在金融科技领域,我们经常需要处理大量的货币汇率数据。 我们从不同的来源获得数据,每个人对于如何推断明天、后天、下个月甚至未来三年的汇率都有自己的想法。 如果有人能预测利率就好了 正确地,是时候关闭业务并愚蠢地来回换钱了。 有些来源更可靠,有些提供完全垃圾,很少包含几乎正确的值,但对于异国情调的夫妇来说。 我们的工作是每秒筛选这数以万计的值,并确定到底要向客户展示什么。 我们需要从大量的污垢和淤泥中过滤出一个正确的值,就像火烈鸟在午餐时所做的那样。
火烈鸟的一个显着特征是它们巨大的向下弯曲的喙,它们用它从水或泥土中过滤食物。
-维基
图书馆就这样诞生了 Vela
假设我们收集三种货币对的汇率。 最简单的定义 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/2
Kernel.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?/2
или compare/2
,那么就用这些函数来进行比较,不然我们就傻乎乎的用 ==/2
.
获取值
处理当前状态通常从调用开始 Vela.purge/1
,这会删除过时的值(如果 validator
拴 timestamps
)。 然后你可以打电话 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
,当需要课程的一小部分历史记录(整个系列)时,我们只需返回它(已经排序)和经过验证的值。
快乐的时间序列缓存!
来源: habr.com