aboutsummaryrefslogtreecommitdiffstats
path: root/searchlib
diff options
context:
space:
mode:
authorTor Egge <Tor.Egge@broadpark.no>2017-02-24 14:55:33 +0100
committerGitHub <noreply@github.com>2017-02-24 14:55:33 +0100
commitf03d03c6402fa7c0b96e21b8664733c6ec3feeb1 (patch)
tree99747879b8c82cacbe95885459baf7577c420714 /searchlib
parent2269a8f3dab0785fe8dab0a6f35a74a05a0c2a10 (diff)
parent08dbb5ac796492a55bc0921cfb25d06e63311c51 (diff)
Merge pull request #1861 from yahoo/havardpe/lazy-rank-expressions
Havardpe/lazy rank expressions
Diffstat (limited to 'searchlib')
-rw-r--r--searchlib/src/tests/fef/properties/properties_test.cpp8
-rw-r--r--searchlib/src/tests/fef/rank_program/rank_program_test.cpp47
-rw-r--r--searchlib/src/vespa/searchlib/features/rankingexpressionfeature.cpp46
-rw-r--r--searchlib/src/vespa/searchlib/fef/indexproperties.cpp13
-rw-r--r--searchlib/src/vespa/searchlib/fef/indexproperties.h11
5 files changed, 123 insertions, 2 deletions
diff --git a/searchlib/src/tests/fef/properties/properties_test.cpp b/searchlib/src/tests/fef/properties/properties_test.cpp
index 7ca79599d5c..7f5594ea821 100644
--- a/searchlib/src/tests/fef/properties/properties_test.cpp
+++ b/searchlib/src/tests/fef/properties/properties_test.cpp
@@ -215,6 +215,14 @@ TEST("test stuff") {
}
{ // test index properties known by the framework
+ { // vespa.eval.lazy_expressions
+ EXPECT_EQUAL(eval::LazyExpressions::NAME, vespalib::string("vespa.eval.lazy_expressions"));
+ EXPECT_EQUAL(eval::LazyExpressions::DEFAULT_VALUE, vespalib::string("false"));
+ Properties p;
+ EXPECT_TRUE(!eval::LazyExpressions::check(p));
+ p.add("vespa.eval.lazy_expressions", "true");
+ EXPECT_TRUE(eval::LazyExpressions::check(p));
+ }
{ // vespa.rank.firstphase
EXPECT_EQUAL(rank::FirstPhase::NAME, vespalib::string("vespa.rank.firstphase"));
EXPECT_EQUAL(rank::FirstPhase::DEFAULT_VALUE, vespalib::string("nativeRank"));
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 62c6ffb1559..261be51a3c7 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;
@@ -275,4 +294,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());
+ }
}
//-----------------------------------------------------------------------------
diff --git a/searchlib/src/vespa/searchlib/fef/indexproperties.cpp b/searchlib/src/vespa/searchlib/fef/indexproperties.cpp
index 23874924ddb..b75a0f33393 100644
--- a/searchlib/src/vespa/searchlib/fef/indexproperties.cpp
+++ b/searchlib/src/vespa/searchlib/fef/indexproperties.cpp
@@ -74,6 +74,19 @@ checkIfTrue(const Properties &props, const vespalib::string &name,
}
+namespace eval {
+
+const vespalib::string LazyExpressions::NAME("vespa.eval.lazy_expressions");
+const vespalib::string LazyExpressions::DEFAULT_VALUE("false");
+
+bool
+LazyExpressions::check(const Properties &props)
+{
+ return checkIfTrue(props, NAME, DEFAULT_VALUE);
+}
+
+} // namespace eval
+
namespace rank {
const vespalib::string FirstPhase::NAME("vespa.rank.firstphase");
diff --git a/searchlib/src/vespa/searchlib/fef/indexproperties.h b/searchlib/src/vespa/searchlib/fef/indexproperties.h
index 2a37f2f93fd..4a97535879b 100644
--- a/searchlib/src/vespa/searchlib/fef/indexproperties.h
+++ b/searchlib/src/vespa/searchlib/fef/indexproperties.h
@@ -21,6 +21,17 @@ class Properties;
**/
namespace indexproperties {
+namespace eval {
+
+// lazy evaluation of expressions. affects rank/summary/dump
+struct LazyExpressions {
+ static const vespalib::string NAME;
+ static const vespalib::string DEFAULT_VALUE;
+ static bool check(const Properties &props);
+};
+
+} // namespace eval
+
namespace rank {
/**