= Analytics Mapping Functions
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

Mapping functions map values for each Solr Document or Reduction.

Below is a list of all mapping functions provided by the Analytics Component.
These mappings can be chained together to implement more complex functionality.

== Numeric Functions

=== Negation
Negates the result of a numeric expression.

`neg(<_Numeric_ T>)` \=> `<T>`::
    * `neg(10.53)` \=> `-10.53`
    * `neg([1, -4])` \=> `[-1, 4]`

=== Absolute Value
Returns the absolute value of the numeric expression.

`abs(< _Numeric_ T >)` \=> `< T >`::
    * `abs(-10.53)` \=> `10.53`
    * `abs([1, -4])` \=> `[1, 4]`

[[analytics-round]]
=== Round
Rounds the numeric expression to the nearest `Integer` or `Long` value.

`round(< _Float_ >)` \=> `< _Int_ >`::
`round(< _Double_ >)` \=> `< _Long_ >`::
    * `round(-1.5)` \=> `-1`
    * `round([1.75, 100.34])` \=> `[2, 100]`

=== Ceiling
Rounds the numeric expression to the nearest `Integer` or `Long` value that is greater than or equal to the original value.

`ceil(< _Float_ >)` \=> `< _Int_ >`::
`ceil(< _Double_ >)` \=> `< _Long_ >`::
    * `ceil(5.01)` \=> `5`
    * `ceil([-4.999, 6.99])` \=> `[-4, 7]`

[[analytics-floor]]
=== Floor
Rounds the numeric expression to the nearest `Integer` or `Long` value that is less than or equal to the original value.

`floor(< _Float_ >)` \=> `< _Int_ >`::
`floor(< _Double_ >)` \=> `< _Long_ >`::
    * `floor(5.75)` \=> `5`
    * `floor([-4.001, 6.01])` \=> `[-5, 6]`

=== Addition
Adds the values of the numeric expressions.

`add(< _Multi Double_ >)` \=> `< _Single Double_ >`::
    * `add([1, -4])` \=> `-3.0`
`add(< _Single Double_ >, < _Multi Double_ >)` \=> `< _Multi Double_ >`::
    * `add(3.5, [1, -4])` \=> `[4.5, -0.5]`
`add(< _Multi Double_ >, < _Single Double_ >)` \=> `< _Multi Double_ >`::
    * `add([1, -4], 3.5)` \=> `[4.5, -0.5]`
`add(< _Single Double_ >, ...)` \=> `< _Single Double_ >`::
    * `add(3.5, 100, -27.6)` \=> `75.9`

=== Subtraction
Subtracts the values of the numeric expressions.

`sub(< _Single Double_ >, < _Single Double_ >)` \=> `< _Single Double_ >`::
    * `sub(3.5, 100)` \=> `-76.5`
`sub(< _Single Double_ >, < _Multi Double_ >)` \=> `< _Multi Double_ >`::
    * `sub(3.5, [1, -4])` \=> `[2.5, 7.5]`
`sub(< _Multi Double_ >, < _Single Double_ >)` \=> `< _Multi Double_ >`::
    * `sub([1, -4], 3.5)` \=> `[-2.5, -7.5]`

=== Multiplication
Multiplies the values of the numeric expressions.

`mult(< _Multi Double_ >)` \=> `< _Single Double_ >`::
    * `mult([1, -4])` \=> `-4.0`
`mult(< _Single Double_ >, < _Multi Double_ >)` \=> `< _Multi Double_ >`::
    * `mult(3.5, [1, -4])` \=> `[3.5, -16.0]`
`mult(< _Multi Double_ >, < _Single Double_ >)` \=> `< _Multi Double_ >`::
    * `mult([1, -4], 3.5)` \=> `[3.5, 16.0]`
`mult(< _Single Double_ >, ...)` \=> `< _Single Double_ >`::
    * `mult(3.5, 100, -27.6)` \=> `-9660`

=== Division
Divides the values of the numeric expressions.

`div(< _Single Double_ >, < _Single Double_ >)` \=> `< _Single Double_ >`::
    * `div(3.5, 100)` \=> `.035`
`div(< _Single Double_ >, < _Multi Double_ >)` \=> `< _Multi Double_ >`::
    * `div(3.5, [1, -4])` \=> `[3.5, -0.875]`
`div(< _Multi Double_ >, < _Single Double_ >)` \=> `< _Multi Double_ >`::
    * `div([1, -4], 25)` \=> `[0.04, -0.16]`

=== Power
Takes one numeric expression to the power of another.

*NOTE:* The square root function `sqrt(< _Double_ >)` can be used as shorthand for  `pow(< _Double_ >, .5)`

`pow(< _Single Double_ >, < _Single Double_ >)` \=> `< _Single Double_ >`::
    * `pow(2, 4)` \=> `16.0`
`pow(< _Single Double_ >, < _Multi Double_ >)` \=> `< _Multi Double_ >`::
    * `pow(16, [-1, 0])` \=> `[0.0625, 1]`
`pow(< _Multi Double_ >, < _Single Double_ >)` \=> `< _Multi Double_ >`::
    * `pow([1, 16], .25)` \=> `[1.0, 2.0]`

=== Logarithm
Takes one logarithm of numeric expressions, with an optional second numeric expression as the base.
If only one expression is given, the natural log is used.

`log(< _Double_ >)` \=> `< _Double_ >`::
    * `log(5)` \=> `1.6094...`
    * `log([1.0, 100.34])` \=> `[0.0, 4.6085...]`
`log(< _Single Double_ >, < _Single Double_ >)` \=> `< _Single Double_ >`::
    * `log(2, 4)` \=> `0.5`
`log(< _Single Double_ >, < _Multi Double_ >)` \=> `< _Multi Double_ >`::
    * `log(16, [2, 4])` \=> `[4, 2]`
`log(< _Multi Double_ >, < _Single Double_ >)` \=> `< _Multi Double_ >`::
    * `log([81, 3], 9)` \=> `[2.0, 0.5]`

== Logic

[[analytics-logic-neg]]
=== Negation
Negates the result of a boolean expression.

`neg(< _Bool_ >)` \=> `< _Bool_>`::
    *  `neg(F)` \=> `T`
    * `neg([F, T])` \=> `[T, F]`

[[analytics-and]]
=== And
ANDs the values of the boolean expressions.

`and(< _Multi Bool_ >)` \=> `< _Single Bool_ >`::
    * `and([T, F, T])` \=> `F`
`and(< _Single Bool_ >, < _Multi Bool_ >)` \=> `< _Multi Bool_ >`::
    * `and(F, [T, T])` \=> `[F, F]`
`and(< _Multi Bool_ >, < _Single Bool_ >)` \=> `< _Multi Bool_ >`::
    * `and([F, T], T)` \=> `[F, T]`
`and(< _Single Bool_ >, ...)` \=> `< _Single Bool_ >`::
    * `and(T, T, T)` \=> `T`

[[analytics-or]]
=== Or
ORs the values of the boolean expressions.

`or(< _Multi Bool_ >)` \=> `< _Single Bool_ >`::
    * `or([T, F, T])` \=> `T`
`or(< _Single Bool_ >, < _Multi Bool_ >)` \=> `< _Multi Bool_ >`::
    * `or(F, [F, T])` \=> `[F, T]`
`or(< _Multi Bool_ >, < _Single Bool_ >)` \=> `< _Multi Bool_ >`::
    * `or([F, T], T)` \=> `[T, T]`
`or(< _Single Bool_ >, ...)` \=> `< _Single Bool_ >`::
    * `or(F, F, F)` \=> `F`

==== Exists
Checks whether any value(s) exist for the expression.

`exists( T )` \=> `< _Single Bool_ >`::
    * `exists([1, 2, 3])` \=> `T`
    * `exists([])` \=> `F`
    * `exists(_empty_)` \=> `F`
    * `exists('abc')` \=> `T`

== Comparison

=== Equality
Checks whether two expressions' values are equal. The parameters must be the same type, after implicit casting.

`equal(< _Single_ T >, < _Single_ T >)` \=> `< _Single Bool_ >`::
    * `equal(F, F)` \=> `T`
`equal(< _Single_ T >, < _Multi_ T >)` \=> `< _Multi Bool_ >`::
    * `equal("a", ["a", "ab"])` \=> `[T, F]`
`equal(< _Multi_ T >, < _Single_ T >)` \=> `< _Multi Bool_ >`::
    * `equal([1.5, -3.0], -3)` \=> `[F, T]`

=== Greater Than
Checks whether a numeric or `Date` expression's values are greater than another expression's values.
The parameters must be the same type, after implicit casting.

`gt(< _Single Numeric/Date_ T >, < _Single_ T >)` \=> `< _Single Bool_ >`::
    * `gt(1800-01-02, 1799-12-20)` \=> `F`
`gt(< _Single Numeric/Date_ T >, < _Multi_ T >)` \=> `< _Multi Bool_ >`::
    * `gt(30.756, [30, 100])` \=> `[F, T]`
`gt(< _Multi Numeric/Date_ T >, < _Single_ T >)` \=> `< _Multi Bool_ >`::
    * `gt([30, 75.6], 30)` \=> `[F, T]`

=== Greater Than or Equals
Checks whether a numeric or `Date` expression's values are greater than or equal to another expression's values.
The parameters must be the same type, after implicit casting.

`gte(< _Single Numeric/Date_ T >, < _Single_ T >)` \=> `< _Single Bool_ >`::
    * `gte(1800-01-02, 1799-12-20)` \=> `F`
`gte(< _Single Numeric/Date_ T >, < _Multi_ T >)` \=> `< _Multi Bool_ >`::
    * `gte(30.756, [30, 100])` \=> `[F, T]`
`gte(< _Multi Numeric/Date_ T >, < _Single_ T >)` \=> `< _Multi Bool_ >`::
    * `gte([30, 75.6], 30)` \=> `[T, T]`

=== Less Than
Checks whether a numeric or `Date` expression's values are less than another expression's values.
The parameters must be the same type, after implicit casting.

`lt(< _Single Numeric/Date_ T >, < _Single_ T >)` \=> `< _Single Bool_ >`::
    * `lt(1800-01-02, 1799-12-20)` \=> `T`
`lt(< _Single Numeric/Date_ T >, < _Multi_ T >)` \=> `< _Multi Bool_ >`::
    * `lt(30.756, [30, 100])` \=> `[T, F]`
`lt(< _Multi Numeric/Date_ T >, < _Single_ T >)` \=> `< _Multi Bool_ >`::
    * `lt([30, 75.6], 30)` \=> `[F, F]`

=== Less Than or Equals
Checks whether a numeric or `Date` expression's values are less than or equal to another expression's values.
The parameters must be the same type, after implicit casting.

`lte(< _Single Numeric/Date_ T >, < _Single_ T >)` \=> `< _Single Bool_ >`::
    * `lte(1800-01-02, 1799-12-20)` \=> `T`
`lte(< _Single Numeric/Date_ T >, < _Multi_ T >)` \=> `< _Multi Bool_ >`::
    * `lte(30.756, [30, 100])` \=> `[T, F]`
`lte(< _Multi Numeric/Date_ T >, < _Single_ T >)` \=> `< _Multi Bool_ >`::
    * `lte([30, 75.6], 30)` \=> `[T, F]`

[[analytics-top]]
=== Top
Returns the maximum of the numeric, `Date` or `String` expression(s)' values.
The parameters must be the same type, after implicit casting.
(Currently the only type not compatible is `Boolean`, which will be converted to a `String` implicitly in order to compile the expression)

`top(< _Multi_ T >)` \=> `< _Single_ T >`::
    * `top([30, 400, -10, 0])` \=> `400`
`top(< _Single_ T >, ...)` \=> `< _Single_ T >`::
    * `top("a", 1, "d")` \=> `"d"`

=== Bottom
Returns the minimum of the numeric, `Date` or `String` expression(s)' values.
The parameters must be the same type, after implicit casting.
(Currently the only type not compatible is `Boolean`, which will be converted to a `String` implicitly in order to compile the expression)

`bottom(< _Multi_ T >)` \=> `< _Single_ T >`::
    * `bottom([30, 400, -10, 0])` \=> `-10`
`bottom(< _Single_ T >, ...)` \=> `< _Single_ T >`::
    * `bottom("a", 1, "d")` \=> `"1"`

== Conditional

[[analytics-if]]
=== If
Returns the value(s) of the `THEN` or `ELSE` expressions depending on whether the boolean conditional expression's value is `true` or `false`.
The `THEN` and `ELSE` expressions must be of the same type and cardinality after implicit casting is done.

`if(< _Single Bool_>, < T >, < T >)` \=> `< T >`::
    * `if(true, "abc", [1,2])` \=> `["abc"]`
    * `if(false, "abc", 123)` \=> `"123"`

=== Replace
Replace all values from the 1^st^ expression that are equal to the value of the 2^nd^ expression with the value of the 3^rd^ expression.
All parameters must be the same type after implicit casting is done.

`replace(< T >, < _Single_ T >, < _Single_ T >)` \=> `< T >`::
    * `replace([1,3], 3, "4")` \=> `["1", "4"]`
    * `replace("abc", "abc", 18)` \=> `"18"`
    * `replace("abc", 1, "def")` \=> `"abc"`

=== Fill Missing
If the 1^st^ expression does not have values, fill it with the values for the 2^nd^ expression.
Both expressions must be of the same type and cardinality after implicit casting is done.

`fill_missing(< T >, < T >)` \=> `< T >`::
    * `fill_missing([], 3)` \=> `[3]`
    * `fill_missing(_empty_, "abc")` \=> `"abc"`
    * `fill_missing("abc", [1])` \=> `["abc"]`

=== Remove
Remove all occurrences of the 2^nd^ expression's value from the values of the 1^st^ expression.
Both expressions must be of the same type after implicit casting is done.

`remove(< T >, < _Single_ T >)` \=> `< T >`::
    * `remove([1,2,3,2], 2)` \=> `[1, 3]`
    * `remove("1", 1)` \=> `_empty_`
    * `remove(1, "abc")` \=> `"1"`

=== Filter
Return the values of the 1^st^ expression if the value of the 2^nd^ expression is `true`, otherwise return no values.

`filter(< T >, < _Single Boolean_ >)` \=> `< T >`::
    * `filter([1,2,3], true)` \=> `[1,2,3]`
    * `filter([1,2,3], false)` \=> `[]`
    * `filter("abc", false)` \=> `_empty_`
    * `filter("abc", true)` \=> `1`

== Date

=== Date Parse
Explicitly converts the values of a `String` or `Long` expression into `Dates`.

`date(< _String_ >)` \=> `< _Date_ >`::
    * `date('1800-01-02')` \=> `1800-01-02T&#8203;00:00:00Z`
    * `date(['1800-01-02', '2016-05-23'])` \=> `[1800-01-02T..., 2016-05-23T...]`
`date(< _Long_ >)` \=> `< _Date_ >`::
    * `date(1232343246648)` \=> `2009-01-19T&#8203;05:34:06Z`
    * `date([1232343246648, 223234324664])` \=> `[2009-01-19T..., 1977-01-27T...]`

[[analytics-date-math]]
=== Date Math
Compute the given date math strings for the values of a `Date` expression. The date math strings *must* be <<analytics-expression-sources.adoc#strings, constant>>.

`date_math(< _Date_ >, < _Constant String_ >...)` \=> `< _Date_ >`::
    * `date_math(1800-04-15, '+1DAY', '-1MONTH')` \=> `1800-03-16`
    * `date_math([1800-04-15,2016-05-24], '+1DAY', '-1MONTH')` \=> `[1800-03-16, 2016-04-25]`

== String

=== Explicit Casting
Explicitly casts the expression to a `String` expression.

`string(< _String_ >)` \=> `< _String_ >`::
    * `string(1)` \=> `'1'`
    * `string([1.5, -2.0])` \=> `['1.5', '-2.0']`

=== Concatenation
Concatenations the values of the `String` expression(s) together.

`concat(< _Multi String_ >)` \=> `< _Single String_ >`::
    * `concat(['a','b','c'])` \=> `'abc'`
`concat(< _Single String_ >, < _Multi String_ >)` \=> `< _Multi String_ >`::
    * `concat(1, ['a','b','c'])` \=> `['1a','1b','1c']`
`concat(< _Multi String_ >, < _Single String_ >)` \=> `< _Multi String_ >`::
    * `concat(['a','b','c'], 1)` \=> `['a1','b1','c1']`
`concat(< _Single String_ >...)` \=> `< _Single String_ >`::
    * `concat('a','b','c')` \=> `'abc'`
    * `concat('a',_empty_,'c')` \=> `'ac'` +
    _Empty values are ignored_

=== Separated Concatenation
Concatenations the values of the `String` expression(s) together using the given <<analytics-expression-sources.adoc#strings, constant string>> value as a separator.

`concat_sep(< _Constant String_ >, < _Multi String_ >)` \=> `< _Single String_ >`::
    * `concat_sep('-', ['a','b'])` \=> `'a-b'`
`concat_sep(< _Constant String_ >, < _Single String_ >, < _Multi String_ >)` \=> `< _Multi String_ >`::
    * `concat_sep(2,1,['a','b'])` \=> `['12a','12b']`
`concat_sep(< _Constant String_ >, < _Multi String_ >, < _Single String_ >)` \=> `< _Multi String_ >`::
    * `concat_sep(2,['a','b'],1)` \=> `['a21','b21']`
    * `concat_sep('-','a',2,3)` \=> `'a-2-3'`
    * `concat_sep(';','a',_empty_,'c')` \=> `'a;c'` +
_Empty values are ignored_
