mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of https://github.com/arangodb/arangodb into devel
This commit is contained in:
commit
237ef1112e
|
@ -160,8 +160,8 @@ std::unordered_map<std::string, Function const> const Executor::FunctionNames{
|
|||
{ "MIN", Function("MIN", "AQL_MIN", "l", true, true, false, true, true, &Functions::Min) },
|
||||
{ "MAX", Function("MAX", "AQL_MAX", "l", true, true, false, true, true, &Functions::Max) },
|
||||
{ "SUM", Function("SUM", "AQL_SUM", "l", true, true, false, true, true, &Functions::Sum) },
|
||||
{ "MEDIAN", Function("MEDIAN", "AQL_MEDIAN", "l", true, true, false, true, true) },
|
||||
{ "PERCENTILE", Function("PERCENTILE", "AQL_PERCENTILE", "l,n|s", true, true, false, true, true) },
|
||||
{ "MEDIAN", Function("MEDIAN", "AQL_MEDIAN", "l", true, true, false, true, true, &Functions::Median) },
|
||||
{ "PERCENTILE", Function("PERCENTILE", "AQL_PERCENTILE", "l,n|s", true, true, false, true, true, &Functions::Percentile) },
|
||||
{ "AVERAGE", Function("AVERAGE", "AQL_AVERAGE", "l", true, true, false, true, true, &Functions::Average) },
|
||||
{ "VARIANCE_SAMPLE", Function("VARIANCE_SAMPLE", "AQL_VARIANCE_SAMPLE", "l", true, true, false, true, true, &Functions::VarianceSample) },
|
||||
{ "VARIANCE_POPULATION", Function("VARIANCE_POPULATION", "AQL_VARIANCE_POPULATION", "l", true, true, false, true, true, &Functions::VariancePopulation) },
|
||||
|
|
|
@ -448,6 +448,29 @@ static bool Variance (Json const& values, double& value, size_t& count) {
|
|||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Sorts the given list of Numbers in ASC order.
|
||||
/// Removes all null entries.
|
||||
/// Returns false if the list contains non-number values.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool SortNumberList (Json const& values, std::vector<double>& result) {
|
||||
TRI_ASSERT(values.isArray());
|
||||
TRI_ASSERT(result.empty());
|
||||
bool unused;
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
Json element = values.at(i);
|
||||
if (! element.isNull()) {
|
||||
if (! element.isNumber()) {
|
||||
return false;
|
||||
}
|
||||
result.emplace_back(ValueToNumber(element.json(), unused));
|
||||
}
|
||||
}
|
||||
std::sort(result.begin(), result.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- AQL functions public helpers
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -3895,6 +3918,129 @@ AqlValue Functions::StdDevPopulation (triagens::aql::Query* query,
|
|||
return AqlValue(new Json(sqrt(value / count)));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief function MEDIAN
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AqlValue Functions::Median (triagens::aql::Query* query,
|
||||
triagens::arango::AqlTransaction* trx,
|
||||
FunctionParameters const& parameters) {
|
||||
size_t const n = parameters.size();
|
||||
if (n != 1) {
|
||||
THROW_ARANGO_EXCEPTION_PARAMS(TRI_ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH, "MEDIAN", (int) 1, (int) 1);
|
||||
}
|
||||
|
||||
Json list = ExtractFunctionParameter(trx, parameters, 0, false);
|
||||
|
||||
if (! list.isArray()) {
|
||||
RegisterWarning(query, "MEDIAN", TRI_ERROR_QUERY_ARRAY_EXPECTED);
|
||||
return AqlValue(new Json(Json::Null));
|
||||
}
|
||||
|
||||
std::vector<double> values;
|
||||
if (! SortNumberList(list, values)) {
|
||||
RegisterWarning(query, "MEDIAN", TRI_ERROR_QUERY_INVALID_ARITHMETIC_VALUE);
|
||||
return AqlValue(new Json(Json::Null));
|
||||
}
|
||||
|
||||
if (values.empty()) {
|
||||
return AqlValue(new Json(Json::Null));
|
||||
}
|
||||
size_t const l = values.size();
|
||||
size_t midpoint = l / 2;
|
||||
|
||||
if (l % 2 == 0) {
|
||||
return AqlValue(new Json((values[midpoint - 1] + values[midpoint]) / 2));
|
||||
}
|
||||
return AqlValue(new Json(values[midpoint]));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief function PERCENTILE
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AqlValue Functions::Percentile (triagens::aql::Query* query,
|
||||
triagens::arango::AqlTransaction* trx,
|
||||
FunctionParameters const& parameters) {
|
||||
size_t const n = parameters.size();
|
||||
if (n != 2 && n != 3) {
|
||||
THROW_ARANGO_EXCEPTION_PARAMS(TRI_ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH, "PERCENTILE", (int) 2, (int) 3);
|
||||
}
|
||||
|
||||
Json list = ExtractFunctionParameter(trx, parameters, 0, false);
|
||||
|
||||
if (! list.isArray()) {
|
||||
RegisterWarning(query, "PERCENTILE", TRI_ERROR_QUERY_ARRAY_EXPECTED);
|
||||
return AqlValue(new Json(Json::Null));
|
||||
}
|
||||
|
||||
Json border = ExtractFunctionParameter(trx, parameters, 1, false);
|
||||
|
||||
if (! border.isNumber()) {
|
||||
RegisterWarning(query, "PERCENTILE", TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
|
||||
return AqlValue(new Json(Json::Null));
|
||||
}
|
||||
|
||||
bool unused = false;
|
||||
double p = ValueToNumber(border.json(), unused);
|
||||
if (p <= 0 || p > 100) {
|
||||
RegisterWarning(query, "PERCENTILE", TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
|
||||
return AqlValue(new Json(Json::Null));
|
||||
}
|
||||
|
||||
bool useInterpolation = false;
|
||||
|
||||
if (n == 3) {
|
||||
Json methodJson = ExtractFunctionParameter(trx, parameters, 2, false);
|
||||
if (! methodJson.isString()) {
|
||||
RegisterWarning(query, "PERCENTILE", TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
|
||||
return AqlValue(new Json(Json::Null));
|
||||
}
|
||||
std::string method = triagens::basics::JsonHelper::getStringValue(methodJson.json(), "");
|
||||
if (method == "interpolation") {
|
||||
useInterpolation = true;
|
||||
}
|
||||
else if (method == "rank") {
|
||||
useInterpolation = false;
|
||||
}
|
||||
else {
|
||||
RegisterWarning(query, "PERCENTILE", TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
|
||||
return AqlValue(new Json(Json::Null));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<double> values;
|
||||
if (! SortNumberList(list, values)) {
|
||||
RegisterWarning(query, "PERCENTILE", TRI_ERROR_QUERY_INVALID_ARITHMETIC_VALUE);
|
||||
return AqlValue(new Json(Json::Null));
|
||||
}
|
||||
|
||||
if (values.empty()) {
|
||||
return AqlValue(new Json(Json::Null));
|
||||
}
|
||||
size_t l = values.size();
|
||||
if (l == 1) {
|
||||
return AqlValue(new Json(values[0]));
|
||||
}
|
||||
|
||||
if (useInterpolation) {
|
||||
double idx = p * (l + 1) / 100;
|
||||
double pos = floor(idx);
|
||||
|
||||
if (pos >= l) {
|
||||
return AqlValue(new Json(values[l - 1]));
|
||||
}
|
||||
|
||||
double delta = idx - pos;
|
||||
return AqlValue(new Json(delta * (values[pos] - values[pos - 1]) + values[pos - 1]));
|
||||
}
|
||||
double idx = p * l / 100;
|
||||
double pos = ceil(idx);
|
||||
if (pos >= l) {
|
||||
return AqlValue(new Json(values[l - 1]));
|
||||
}
|
||||
return AqlValue(new Json(values[pos - 1]));
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -145,6 +145,8 @@ namespace triagens {
|
|||
static AqlValue VariancePopulation (triagens::aql::Query*, triagens::arango::AqlTransaction*, FunctionParameters const&);
|
||||
static AqlValue StdDevSample (triagens::aql::Query*, triagens::arango::AqlTransaction*, FunctionParameters const&);
|
||||
static AqlValue StdDevPopulation (triagens::aql::Query*, triagens::arango::AqlTransaction*, FunctionParameters const&);
|
||||
static AqlValue Median (triagens::aql::Query*, triagens::arango::AqlTransaction*, FunctionParameters const&);
|
||||
static AqlValue Percentile (triagens::aql::Query*, triagens::arango::AqlTransaction*, FunctionParameters const&);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -2742,6 +2742,22 @@ function ahuacatlFunctionsTestSuite () {
|
|||
else {
|
||||
assertEqual(value[0].toFixed(4), actual[0].toFixed(4));
|
||||
}
|
||||
|
||||
actual = getQueryResults("RETURN NOOPT(MEDIAN(" + JSON.stringify(value[1]) + "))");
|
||||
if (actual[0] === null) {
|
||||
assertNull(value[0]);
|
||||
}
|
||||
else {
|
||||
assertEqual(value[0].toFixed(4), actual[0].toFixed(4));
|
||||
}
|
||||
|
||||
actual = getQueryResults("RETURN NOOPT(V8(MEDIAN(" + JSON.stringify(value[1]) + ")))");
|
||||
if (actual[0] === null) {
|
||||
assertNull(value[0]);
|
||||
}
|
||||
else {
|
||||
assertEqual(value[0].toFixed(4), actual[0].toFixed(4));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -2757,6 +2773,22 @@ function ahuacatlFunctionsTestSuite () {
|
|||
assertQueryWarningAndNull(errors.ERROR_QUERY_ARRAY_EXPECTED.code, "RETURN MEDIAN(3)");
|
||||
assertQueryWarningAndNull(errors.ERROR_QUERY_ARRAY_EXPECTED.code, "RETURN MEDIAN(\"yes\")");
|
||||
assertQueryWarningAndNull(errors.ERROR_QUERY_ARRAY_EXPECTED.code, "RETURN MEDIAN({ })");
|
||||
|
||||
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(MEDIAN())");
|
||||
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(MEDIAN([ ], 2))");
|
||||
assertQueryWarningAndNull(errors.ERROR_QUERY_ARRAY_EXPECTED.code, "RETURN NOOPT(MEDIAN(null))");
|
||||
assertQueryWarningAndNull(errors.ERROR_QUERY_ARRAY_EXPECTED.code, "RETURN NOOPT(MEDIAN(false))");
|
||||
assertQueryWarningAndNull(errors.ERROR_QUERY_ARRAY_EXPECTED.code, "RETURN NOOPT(MEDIAN(3))");
|
||||
assertQueryWarningAndNull(errors.ERROR_QUERY_ARRAY_EXPECTED.code, "RETURN NOOPT(MEDIAN(\"yes\"))");
|
||||
assertQueryWarningAndNull(errors.ERROR_QUERY_ARRAY_EXPECTED.code, "RETURN NOOPT(MEDIAN({ }))");
|
||||
|
||||
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(V8(MEDIAN()))");
|
||||
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(V8(MEDIAN([ ], 2)))");
|
||||
assertQueryWarningAndNull(errors.ERROR_QUERY_ARRAY_EXPECTED.code, "RETURN NOOPT(V8(MEDIAN(null)))");
|
||||
assertQueryWarningAndNull(errors.ERROR_QUERY_ARRAY_EXPECTED.code, "RETURN NOOPT(V8(MEDIAN(false)))");
|
||||
assertQueryWarningAndNull(errors.ERROR_QUERY_ARRAY_EXPECTED.code, "RETURN NOOPT(V8(MEDIAN(3)))");
|
||||
assertQueryWarningAndNull(errors.ERROR_QUERY_ARRAY_EXPECTED.code, "RETURN NOOPT(V8(MEDIAN(\"yes\")))");
|
||||
assertQueryWarningAndNull(errors.ERROR_QUERY_ARRAY_EXPECTED.code, "RETURN NOOPT(V8(MEDIAN({ })))");
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -2798,6 +2830,22 @@ function ahuacatlFunctionsTestSuite () {
|
|||
else {
|
||||
assertEqual(value[0].toFixed(4), actual[0].toFixed(4), value);
|
||||
}
|
||||
|
||||
actual = getQueryResults("RETURN NOOPT(PERCENTILE(" + JSON.stringify(value[1]) + ", " + JSON.stringify(value[2]) + ", " + JSON.stringify(value[3]) + "))");
|
||||
if (actual[0] === null) {
|
||||
assertNull(value[0]);
|
||||
}
|
||||
else {
|
||||
assertEqual(value[0].toFixed(4), actual[0].toFixed(4), value);
|
||||
}
|
||||
|
||||
actual = getQueryResults("RETURN NOOPT(V8(PERCENTILE(" + JSON.stringify(value[1]) + ", " + JSON.stringify(value[2]) + ", " + JSON.stringify(value[3]) + ")))");
|
||||
if (actual[0] === null) {
|
||||
assertNull(value[0]);
|
||||
}
|
||||
else {
|
||||
assertEqual(value[0].toFixed(4), actual[0].toFixed(4), value);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
|
Loading…
Reference in New Issue