8000 Apm 55 by alexbakharew · Pull Request #14364 · arangodb/arangodb · GitHub
[go: up one dir, main page]

Skip to content

Apm 55 #14364

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 17, 2021
Merged

Apm 55 #14364

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ build

*.deb
*.rpm
*.user

.DS_Store
*.swp
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ devel

* Slightly improve specific warning messages for better readability.

* Add 3 AQL functions: DECAY_GAUSS, DECAY_EXP and DECAY_LINEAR.

* Fix URL request parsing in case data is handed in in small chunks.
Previously the URL could be cut off if the chunk size was smaller than
the URL size.
Expand Down
3 changes: 3 additions & 0 deletions arangod/Aql/AqlFunctionFeature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,9 @@ void AqlFunctionFeature::addListFunctions() {
add({"REPLACE_NTH", ".,.,.|.", flags, &Functions::ReplaceNth});
add({"INTERLEAVE", ".,.|+", flags, &Functions::Interleave});

add({"DECAY_GAUSS", ".,.,.,.,.,", flags, &Functions::DecayGauss});
add({"DECAY_EXP", ".,.,.,.,.,", flags, &Functions::DecayExp});
add({"DECAY_LINEAR", ".,.,.,.,.,", flags, &Functions::DecayLinear});
// special flags:
// CALL and APPLY will always run on the coordinator and are not deterministic
// and not cacheable, as we don't know what function is actually gonna be
Expand Down
150 changes: 150 additions & 0 deletions arangod/Aql/Functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1313,6 +1313,14 @@ Result parseShape(ExpressionContext* exprCtx,
}
}

irs::string_ref getFunctionName(const AstNode& node) {

TRI_ASSERT(aql::NODE_TYPE_FCALL == node.type);
auto const* impl = static_cast<arangodb::aql::Function*>(node.getData());
TRI_ASSERT(impl != nullptr);
return impl->name;
}

} // namespace

namespace arangodb {
Expand Down Expand Up @@ -8848,6 +8856,148 @@ AqlValue Functions::MakeDistributeGraphInput(arangodb::aql::ExpressionContext* e
return AqlValue{input};
}

template <typename F>
AqlValue decayFuncImpl(arangodb::aql::ExpressionContext* expressionContext,
AstNode const& node,
VPackFunctionParameters const& parameters,
F&& decayFuncFactory) {

AqlValue const& argValue = extractFunctionParameterValue(parameters, 0);
AqlValue const& originValue = extractFunctionParameterValue(parameters, 1);
AqlValue const& scaleValue = extractFunctionParameterValue(parameters, 2);
AqlValue const& offsetValue = extractFunctionParameterValue(parameters, 3);
AqlValue const& decayValue = extractFunctionParameterValue(parameters, 4);

// check type of arguments
if ((!argValue.isRange() && !argValue.isArray() && !argValue.isNumber()) ||
!originValue.isNumber() || !scaleValue.isNumber() ||
!offsetValue.isNumber() || !decayValue.isNumber()) {

registerInvalidArgumentWarning(expressionContext,
getFunctionName(node).c_str());
return AqlValue(AqlValueHintNull());
}

// extracting values
bool failed;
bool error = false;
double origin = originValue.toDouble(failed);
error |= failed;
double scale = scaleValue.toDouble(failed);
error |= failed;
double offset = offsetValue.toDouble(failed);
error |= failed;
double decay = decayValue.toDouble(failed);
error |= failed;

if (error) {
registerWarning(expressionContext,
getFunctionName(node).c_str(),
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
return AqlValue(AqlValueHintNull());
}

// check that parameters are correct
if (scale <= 0 || offset < 0 || decay <= 0 || decay >= 1) {
registerWarning(expressionContext,
getFunctionName(node).c_str(),
TRI_ERROR_QUERY_NUMBER_OUT_OF_RANGE);
return AqlValue(AqlValueHintNull());
}

// get lambda for further calculation
auto decayFunc = decayFuncFactory(origin, scale, offset, decay);

// argument is number
if (argValue.isNumber()) {
double arg = argValue.slice().getNumber<double>();
double funcRes = decayFunc(arg);
return ::numberValue(funcRes, true);
} else {
// argument is array or range
auto* trx = &expressionContext->trx();
AqlValueMaterializer materializer(&trx->vpackOptions());
VPackSlice slice = materializer.slice(argValue, true);
TRI_ASSERT(slice.isArray());

VPackBuilder builder;
{
VPackArrayBuilder arrayBuilder(&builder);
for (VPackSlice currArg : VPackArrayIterator(slice)) {
if (!currArg.isNumber()) {
registerWarning(expressionContext,
getFunctionName(node).c_str(),
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
return AqlValue(AqlValueHintNull());
}
double arg = currArg.getNumber<double>();
double funcRes = decayFunc(arg);
builder.add(VPackValue(funcRes));
}
}

return AqlValue(std::move(*builder.steal()));
}
}

AqlValue Functions::DecayGauss(arangodb::aql::ExpressionContext* expressionContext,
AstNode const& node,
VPackFunctionParameters const& parameters) {

auto gaussDecayFactory = [](const double origin,
const double scale,
const double offset,
const double decay) {
const double sigmaSqr = - (scale * scale) / (2 * std::log(decay));
return [=](double arg) {
double max = std::max(0.0, std::fabs(arg - origin) - offset);
double numerator = max * max;
double val = std::exp(- numerator / (2 * sigmaSqr));
return val;
};
};

return decayFuncImpl(expressionContext, node, parameters, gaussDecayFactory);
}

AqlValue Functions::DecayExp(arangodb::aql::ExpressionContext* expressionContext,
AstNode const& node,
VPackFunctionParameters const& parameters) {

auto expDecayFactory = [](const double origin,
const double scale,
const double offset,
const double decay) {
const double lambda = std::log(decay) / scale;
return [=](double arg) {
double numerator = lambda * std::max(0.0, std::abs(arg - origin) - offset);
double val = std::exp(numerator);
return val;
};
};

return decayFuncImpl(expressionContext, node, parameters, expDecayFactory);
}

AqlValue Functions::DecayLinear(arangodb::aql::ExpressionContext* expressionContext,
AstNode const& node,
VPackFunctionParameters const& parameters) {

auto linearDecayFactory = [](const double origin,
const double scale,
const double offset,
const double decay) {
const double s = scale / (1.0 - decay);
return [=](double arg) {
double max = std::max(0.0, std::fabs(arg - origin) - offset);
double val = std::max((s - max) / s, 0.0);
return val;
};
};

return decayFuncImpl(expressionContext, node, parameters, linearDecayFactory);
}

AqlValue Functions::NotImplemented(ExpressionContext* expressionContext, AstNode const&,
VPackFunctionParameters const& params) {
registerError(expressionContext, "UNKNOWN", TRI_ERROR_NOT_IMPLEMENTED);
Expand Down
9 changes: 9 additions & 0 deletions arangod/Aql/Functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,15 @@ struct Functions {
static AqlValue MakeDistributeGraphInput(arangodb::aql::ExpressionContext*,
AstNode const&, VPackFunctionParameters const&);

static AqlValue DecayGauss(arangodb::aql::ExpressionContext*,
AstNode const&, VPackFunctionParameters const&);

static AqlValue DecayExp(arangodb::aql::ExpressionContext*,
AstNode const&, VPackFunctionParameters const&);

static AqlValue DecayLinear(arangodb::aql::ExpressionContext*,
AstNode const&, VPackFunctionParameters const&);

/// @brief dummy function that will only throw an error when called
static AqlValue NotImplemented(arangodb::aql::ExpressionContext*,
AstNode const&, VPackFunctionParameters const&);
Expand Down
Loading
0