Skip to content

Instantly share code, notes, and snippets.

@jjttjj
Last active January 30, 2020 16:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jjttjj/e63ba5a366961c314b40118edc548aed to your computer and use it in GitHub Desktop.
Save jjttjj/e63ba5a366961c314b40118edc548aed to your computer and use it in GitHub Desktop.
A draft of a time series query language
;;The goal of this is to specify a query format which clients can use to request
;;time series data from a server. The two primary operations are `:seek`s, which
;;are database lookups, and `:calc`s which tell the server to calculate
;;something using a previous seek as an argument. The result of either a seek or
;;a calc can be either a vector of data points or a map of columns (column name
;;-> vector).
;;Queries are either maps of names to subqueries, or just a vector of
;;subqueries. In either case, the response mirrors the shape of the query, with
;;subqueries replaced with either a vector of data points, or a map of column
;;names to data points.
;;There are two types of "subqueries", which are indicated by metadata tags:
;;^:seek and ^:calc. Stored data is retrived with ^:seek and and calculations
;;can be made with ^:calc. Caculations are simliar to functions and can be
;;dependent on both retrieved data and/or other calculations.
;;A ^:seek vector has both a lookup map of arbitrary clojure data identifying a
;;series (presumably in a db somewhere), and a range map with a start/end time,
;;defining the time bounds of the data we want. ^:seek values are replaced with
;;their results (a vector of data or a map of columns).
;;A ^:calc vector as a keyword identifying a calculation, followed by any number
;;of arguemnts to that calculation. an argument can be anything serialzable by
;;transit, or a ^:ref vector, which denotes a path in the query. refs can "reach
;;into" results which are column maps to get a specific column
;;To limit results returned, :select [<paths to keep>] metadata can be placed on
;;the whole query, or ^:keep metadata can be placed on one or more
;;subqueries. Otherwise, all results are returned in a map or vector mirroring
;;the query.
(def range1 {:tick/beginning (t/- (t/zoned-date-time) #time/period "P100D")
:tick/end (t/zoned-date-time)})
(def q1
^{:select [:aapl :rel-ema]}
{:msft ^:seek [{:symbol "MSFT" :resolution "1 day"} range1]
:aapl ^:seek [{:symbol "AAPL" :resolution "1 day"} range1]
:relative ^:calc [:divide ^:ref [:msft :close] ^:ref [:aapl :close]]
:rel-ema ^:calc [:ema 20 ^:ref [:relative]]})
(def q2
[^:seek ^:keep [{:symbol "MSFT" :resolution "1 day"} range1]
^:seek [{:symbol "AAPL" :resolution "1 day"} range1]
^:calc [:divide ^:ref [0 :close] ^:ref [1 :close]]
^:calc ^:keep [:ema 20 ^:ref [2]]])
(comment
(query db q1)
;;=>
{:aapl {:open [5,,,,] :high [7,,,,] :low [4,,,,] :close [6,,,,]}
:rel-ema [4 3 2,,,]}
(query db q2)
;;=>
[{:open [5,,,,] :high [7,,,,] :low [4,,,,] :close [6,,,,]}
[4 3 2,,,]])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment