summaryrefslogtreecommitdiffstats
path: root/searchlib
diff options
context:
space:
mode:
authorHaavard <havardpe@yahoo-inc.com>2017-02-24 13:44:53 +0000
committerHaavard <havardpe@yahoo-inc.com>2017-02-24 13:44:53 +0000
commit08dbb5ac796492a55bc0921cfb25d06e63311c51 (patch)
tree7b5b2ceabf01bcc398f85452453691276222d191 /searchlib
parent93110996e8384cb4e191084583c7c068fd91a566 (diff)
add and test lazy ranking expression executor
Diffstat (limited to 'searchlib')
-rw-r--r--searchlib/src/tests/fef/rank_program/rank_program_test.cpp47
-rw-r--r--searchlib/src/vespa/searchlib/features/rankingexpressionfeature.cpp46
2 files changed, 91 insertions, 2 deletions
diff --git a/searchlib/src/tests/fef/rank_program/rank_program_test.cpp b/searchlib/src/tests/fef/rank_program/rank_program_test.cpp
index 07f82db390e..a92a3572a36 100644
--- a/searchlib/src/tests/fef/rank_program/rank_program_test.cpp
+++ b/searchlib/src/tests/fef/rank_program/rank_program_test.cpp
@@ -3,7 +3,9 @@
#include <vespa/vespalib/stllike/string.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/searchlib/features/valuefeature.h>
+#include <vespa/searchlib/features/rankingexpressionfeature.h>
#include <vespa/searchlib/fef/blueprintfactory.h>
+#include <vespa/searchlib/fef/indexproperties.h>
#include <vespa/searchlib/fef/test/indexenvironment.h>
#include <vespa/searchlib/fef/test/queryenvironment.h>
#include <vespa/searchlib/fef/test/plugin/sum.h>
@@ -58,6 +60,10 @@ size_t count_const_features(const RankProgram &program) {
return count(program, [](const LazyValue &value){ return value.is_const(); });
}
+vespalib::string expr_feature(const vespalib::string &name) {
+ return vespalib::make_string("rankingExpression(%s)", name.c_str());
+}
+
struct Fixture {
BlueprintFactory factory;
IndexEnvironment indexEnv;
@@ -72,10 +78,23 @@ struct Fixture {
factory.addPrototype(Blueprint::SP(new DocidBlueprint()));
factory.addPrototype(Blueprint::SP(new DoubleBlueprint()));
factory.addPrototype(Blueprint::SP(new ImpureValueBlueprint()));
+ factory.addPrototype(Blueprint::SP(new RankingExpressionBlueprint()));
factory.addPrototype(Blueprint::SP(new SumBlueprint()));
factory.addPrototype(Blueprint::SP(new TrackingBlueprint(track_cnt)));
factory.addPrototype(Blueprint::SP(new ValueBlueprint()));
}
+ Fixture &lazy_expressions(bool value) {
+ indexEnv.getProperties().add(indexproperties::eval::LazyExpressions::NAME,
+ value ? "true" : "false");
+ return *this;
+ }
+ Fixture &add_expr(const vespalib::string &name, const vespalib::string &expr) {
+ vespalib::string feature_name = expr_feature(name);
+ vespalib::string expr_name = feature_name + ".rankingScript";
+ indexEnv.getProperties().add(expr_name, expr);
+ add(feature_name);
+ return *this;
+ }
Fixture &add(const vespalib::string &feature) {
resolver->addSeed(feature);
return *this;
@@ -262,4 +281,32 @@ TEST_F("require that auto-unboxing of non-const object values work", Fixture())
EXPECT_EQUAL(0u, count_const_features(f1.program));
}
+TEST_F("require that non-lazy ranking expression always calculates all inputs", Fixture()) {
+ f1.lazy_expressions(false);
+ f1.add_expr("rank", "if(docid<10,track(ivalue(1)),track(ivalue(2)))");
+ f1.compile();
+ EXPECT_EQUAL(6u, f1.program.num_executors());
+ EXPECT_EQUAL(6u, count_features(f1.program));
+ EXPECT_EQUAL(0u, count_const_features(f1.program));
+ EXPECT_EQUAL(f1.track_cnt, 0u);
+ EXPECT_EQUAL(f1.get(expr_feature("rank"), 5), 1.0);
+ EXPECT_EQUAL(f1.track_cnt, 2u);
+ EXPECT_EQUAL(f1.get(expr_feature("rank"), 15), 2.0);
+ EXPECT_EQUAL(f1.track_cnt, 4u);
+}
+
+TEST_F("require that lazy ranking expression only calculates needed inputs", Fixture()) {
+ f1.lazy_expressions(true);
+ f1.add_expr("rank", "if(docid<10,track(ivalue(1)),track(ivalue(2)))");
+ f1.compile();
+ EXPECT_EQUAL(6u, f1.program.num_executors());
+ EXPECT_EQUAL(6u, count_features(f1.program));
+ EXPECT_EQUAL(0u, count_const_features(f1.program));
+ EXPECT_EQUAL(f1.track_cnt, 0u);
+ EXPECT_EQUAL(f1.get(expr_feature("rank"), 5), 1.0);
+ EXPECT_EQUAL(f1.track_cnt, 1u);
+ EXPECT_EQUAL(f1.get(expr_feature("rank"), 15), 2.0);
+ EXPECT_EQUAL(f1.track_cnt, 2u);
+}
+
TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/searchlib/src/vespa/searchlib/features/rankingexpressionfeature.cpp b/searchlib/src/vespa/searchlib/features/rankingexpressionfeature.cpp
index 8c966b2456a..6839ee83ad7 100644
--- a/searchlib/src/vespa/searchlib/features/rankingexpressionfeature.cpp
+++ b/searchlib/src/vespa/searchlib/features/rankingexpressionfeature.cpp
@@ -57,6 +57,22 @@ public:
//-----------------------------------------------------------------------------
/**
+ * Implements the executor for lazy compiled ranking expressions
+ **/
+class LazyCompiledRankingExpressionExecutor : public fef::FeatureExecutor
+{
+private:
+ using function_type = CompiledFunction::lazy_function;
+ function_type _ranking_function;
+
+public:
+ LazyCompiledRankingExpressionExecutor(const CompiledFunction &compiled_function);
+ void execute(uint32_t docId) override;
+};
+
+//-----------------------------------------------------------------------------
+
+/**
* Implements the executor for interpreted ranking expressions (with tensor support)
**/
class InterpretedRankingExpressionExecutor : public fef::FeatureExecutor
@@ -98,6 +114,23 @@ CompiledRankingExpressionExecutor::execute(uint32_t)
//-----------------------------------------------------------------------------
+using Context = fef::FeatureExecutor::Inputs;
+double resolve_input(void *ctx, size_t idx) { return ((const Context *)(ctx))->get_number(idx); }
+Context *make_ctx(const Context &inputs) { return const_cast<Context *>(&inputs); }
+
+LazyCompiledRankingExpressionExecutor::LazyCompiledRankingExpressionExecutor(const CompiledFunction &compiled_function)
+ : _ranking_function(compiled_function.get_lazy_function())
+{
+}
+
+void
+LazyCompiledRankingExpressionExecutor::execute(uint32_t)
+{
+ outputs().set_number(0, _ranking_function(resolve_input, make_ctx(inputs())));
+}
+
+//-----------------------------------------------------------------------------
+
InterpretedRankingExpressionExecutor::InterpretedRankingExpressionExecutor(const InterpretedFunction &function,
ConstArrayRef<char> input_is_object)
: _function(function),
@@ -199,7 +232,11 @@ RankingExpressionBlueprint::setup(const fef::IIndexEnvironment &env,
// avoid costly compilation when only verifying setup
if (env.getFeatureMotivation() != env.FeatureMotivation::VERIFY_SETUP) {
if (do_compile) {
- _compile_token = CompileCache::compile(rank_function, PassParams::ARRAY);
+ if (fef::indexproperties::eval::LazyExpressions::check(env.getProperties())) {
+ _compile_token = CompileCache::compile(rank_function, PassParams::LAZY);
+ } else {
+ _compile_token = CompileCache::compile(rank_function, PassParams::ARRAY);
+ }
} else {
_interpreted_function.reset(new InterpretedFunction(DefaultTensorEngine::ref(), rank_function, node_types));
}
@@ -225,7 +262,12 @@ RankingExpressionBlueprint::createExecutor(const fef::IQueryEnvironment &, vespa
return stash.create<InterpretedRankingExpressionExecutor>(*_interpreted_function, input_is_object);
}
assert(_compile_token.get() != nullptr); // will be nullptr for VERIFY_SETUP feature motivation
- return stash.create<CompiledRankingExpressionExecutor>(_compile_token->get());
+ if (_compile_token->get().pass_params() == PassParams::ARRAY) {
+ return stash.create<CompiledRankingExpressionExecutor>(_compile_token->get());
+ } else {
+ assert(_compile_token->get().pass_params() == PassParams::LAZY);
+ return stash.create<LazyCompiledRankingExpressionExecutor>(_compile_token->get());
+ }
}
//-----------------------------------------------------------------------------