Vela → έξυπνη κρυφή μνήμη για χρονοσειρές και πολλά άλλα
Στο fintech, συχνά πρέπει να επεξεργαζόμαστε τεράστιους όγκους δεδομένων συναλλαγματικών ισοτιμιών. Λαμβάνουμε δεδομένα από διαφορετικές πηγές και καθεμία από αυτές έχει τη δική της ιδέα για το πώς να υπολογίσουμε τις συναλλαγματικές ισοτιμίες για αύριο, μεθαύριο, τον επόμενο μήνα και ακόμη και τα επόμενα τρία χρόνια. Αν κάποιος μπορούσε να προβλέψει τα ποσοστά σωστά, θα ήταν καιρός να κλείσουμε την επιχείρηση και να αλλάξουμε ανόητα χρήματα πέρα δώθε. Κάποιες πηγές είναι πιο αξιόπιστες, κάποιες προμηθεύουν πλήρη σκουπίδια, με σπάνιες συμπεριλήψεις σχεδόν σωστών τιμών, αλλά για εξωτικά ζευγάρια. Η δουλειά μας είναι να διερευνήσουμε αυτές τις δεκάδες χιλιάδες τιμές ανά δευτερόλεπτο και να καθορίσουμε τι ακριβώς θα δείξουμε στους πελάτες. Πρέπει να φιλτράρουμε τη μία σωστή τιμή από τόνους βρωμιάς και λάσπης, όπως ακριβώς κάνουν τα φλαμίνγκο στο μεσημεριανό γεύμα.
Ένα ιδιαίτερο χαρακτηριστικό των φλαμίνγκο είναι το ογκώδες κυρτό ράμφος τους, με το οποίο φιλτράρουν τα τρόφιμα από το νερό ή τη λάσπη.
- Wiki
Έτσι γεννήθηκε η βιβλιοθήκη 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 πέρασε κατά τη δημιουργία?
Εάν η επικύρωση είναι επιτυχής, η τιμή προστίθεται στη λίστα κάτω από το αντίστοιχο κλειδί, διαφορετικά, η πλειάδα {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 για πρόσβαση χαμηλού επιπέδου στις τιμές σε κάθε σειρά.
App
Vela μπορεί να είναι εξαιρετικά χρήσιμο ως προσωρινή μνήμη χρονοσειράς σε μια κατάσταση διεργασίας όπως GenServer/Agent. Θέλουμε να μην χρησιμοποιούμε ποτέ μπαγιάτικες τιμές μαθημάτων και για να το κάνουμε αυτό απλώς κρατάμε τη διαδικασία με την κατάσταση επεξεργασμένη Vela, με τον επικυρωτή που φαίνεται παρακάτω.
и Vela.purge/1 αφαιρεί αθόρυβα όλες τις παλιές τιμές κάθε φορά που χρειαζόμαστε τα δεδομένα. Για να αποκτήσουμε πρόσβαση στις πραγματικές τιμές, απλώς καλούμε Vela.slice/1, και όταν απαιτείται ένα μικρό ιστορικό του μαθήματος (όλη η σειρά), απλά το επιστρέφουμε - ήδη ταξινομημένο - με επικυρωμένες τιμές.