aboutsummaryrefslogtreecommitdiffstats
path: root/searchlib/src/tests/fef
diff options
context:
space:
mode:
authorHaavard <havardpe@yahoo-inc.com>2017-02-23 15:13:44 +0000
committerHaavard <havardpe@yahoo-inc.com>2017-02-23 17:10:37 +0000
commit9cb7505ccdc58dcfaa341a9c54eee60d2d16531e (patch)
tree67baab933561ad0c3dbc55a597672a0a4842cade /searchlib/src/tests/fef
parentbeea9069a65cd3625ebbbd20fb386baeed091d24 (diff)
lazy evaluate ranking expressions
Diffstat (limited to 'searchlib/src/tests/fef')
-rw-r--r--searchlib/src/tests/fef/featureoverride/featureoverride.cpp11
-rw-r--r--searchlib/src/tests/fef/object_passing/object_passing_test.cpp3
-rw-r--r--searchlib/src/tests/fef/rank_program/rank_program_test.cpp117
3 files changed, 91 insertions, 40 deletions
diff --git a/searchlib/src/tests/fef/featureoverride/featureoverride.cpp b/searchlib/src/tests/fef/featureoverride/featureoverride.cpp
index 80389064a8f..e77e50a99c8 100644
--- a/searchlib/src/tests/fef/featureoverride/featureoverride.cpp
+++ b/searchlib/src/tests/fef/featureoverride/featureoverride.cpp
@@ -97,10 +97,10 @@ TEST_F("test decorator - transitive override", Fixture)
FeatureExecutor *fe2 = &stash.create<DoubleExecutor>(3);
fe2 = &stash.create<FeatureOverrider>(*fe2, 2, 10.0);
- auto inputs = stash.create_array<const NumberOrObject *>(3);
- inputs[0] = fe->outputs().get_raw(0);
- inputs[1] = fe->outputs().get_raw(1);
- inputs[2] = fe->outputs().get_raw(2);
+ auto inputs = stash.create_array<LazyValue>(3, nullptr);
+ inputs[0] = LazyValue(fe->outputs().get_raw(0), fe);
+ inputs[1] = LazyValue(fe->outputs().get_raw(1), fe);
+ inputs[2] = LazyValue(fe->outputs().get_raw(2), fe);
fe2->bind_inputs(inputs);
f.add(fe2, 3).run();
EXPECT_EQUAL(fe2->outputs().size(), 3u);
@@ -143,9 +143,8 @@ TEST("test overrides")
overrides.add("bogus(feature)", "10.0");
rankProgram->setup(mdl, queryEnv, overrides);
- rankProgram->run(2);
- std::map<vespalib::string, feature_t> res = Utils::getAllFeatures(*rankProgram);
+ std::map<vespalib::string, feature_t> res = Utils::getAllFeatures(*rankProgram, 2);
EXPECT_EQUAL(res.size(), 20u);
EXPECT_APPROX(res["value(1)"], 1.0, 1e-6);
diff --git a/searchlib/src/tests/fef/object_passing/object_passing_test.cpp b/searchlib/src/tests/fef/object_passing/object_passing_test.cpp
index 53f9b028e9d..d62be9b42fb 100644
--- a/searchlib/src/tests/fef/object_passing/object_passing_test.cpp
+++ b/searchlib/src/tests/fef/object_passing/object_passing_test.cpp
@@ -91,11 +91,10 @@ struct Fixture {
Properties overrides;
RankProgram program(resolver);
program.setup(mdl, queryEnv, overrides);
- program.run(1);
auto result = program.get_seeds();
EXPECT_EQUAL(1u, result.num_features());
EXPECT_TRUE(!result.is_object(0)); // verifies auto-unboxing
- return *result.resolve_number(0);
+ return result.resolve(0).as_number(1);
}
bool verify(const vespalib::string &feature) {
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 b70b78d8d28..91c266f2745 100644
--- a/searchlib/src/tests/fef/rank_program/rank_program_test.cpp
+++ b/searchlib/src/tests/fef/rank_program/rank_program_test.cpp
@@ -13,19 +13,47 @@ using namespace search::fef;
using namespace search::fef::test;
using namespace search::features;
-size_t count_unique_features(const RankProgram &program) {
- std::set<const NumberOrObject *> seen;
+uint32_t default_docid = 1;
+
+void maybe_insert(const LazyValue &value, std::vector<LazyValue> &seen) {
+ for (const auto &entry: seen) {
+ if (value.is_same(entry)) {
+ return;
+ }
+ }
+ seen.push_back(value);
+}
+
+std::vector<LazyValue> get_features(const RankProgram &program) {
+ std::vector<LazyValue> seen;
auto unboxed = program.get_all_features(true);
for (size_t i = 0; i < unboxed.num_features(); ++i) {
- // fprintf(stderr, "seen feature (unboxed): %s\n", unboxed.name_of(i).c_str());
- seen.insert(unboxed.resolve_raw(i));
+ maybe_insert(unboxed.resolve(i), seen);
}
auto maybe_boxed = program.get_all_features(false);
for (size_t i = 0; i < maybe_boxed.num_features(); ++i) {
- // fprintf(stderr, "seen feature (maybe boxed): %s\n", maybe_boxed.name_of(i).c_str());
- seen.insert(maybe_boxed.resolve_raw(i));
+ maybe_insert(maybe_boxed.resolve(i), seen);
}
- return seen.size();
+ return seen;
+}
+
+template <typename Predicate>
+size_t count(const RankProgram &program, Predicate pred) {
+ size_t cnt = 0;
+ for (const auto &value: get_features(program)) {
+ if (pred(value)) {
+ ++cnt;
+ }
+ }
+ return cnt;
+}
+
+size_t count_features(const RankProgram &program) {
+ return count(program, [](const LazyValue &){ return true; });
+}
+
+size_t count_const_features(const RankProgram &program) {
+ return count(program, [](const LazyValue &value){ return value.is_const(); });
}
struct ImpureValueExecutor : FeatureExecutor {
@@ -51,6 +79,23 @@ struct ImpureValueBlueprint : Blueprint {
}
};
+struct DocidExecutor : FeatureExecutor {
+ void execute(uint32_t docid) override { outputs().set_number(0, docid); }
+};
+
+struct DocidBlueprint : Blueprint {
+ DocidBlueprint() : Blueprint("docid") {}
+ void visitDumpFeatures(const IIndexEnvironment &, IDumpFeatureVisitor &) const override {}
+ Blueprint::UP createInstance() const override { return Blueprint::UP(new DocidBlueprint()); }
+ bool setup(const IIndexEnvironment &, const std::vector<vespalib::string> &) override {
+ describeOutput("out", "the local document id");
+ return true;
+ }
+ FeatureExecutor &createExecutor(const IQueryEnvironment &, vespalib::Stash &stash) const override {
+ return stash.create<DocidExecutor>();
+ }
+};
+
struct MySetup {
BlueprintFactory factory;
IndexEnvironment indexEnv;
@@ -63,6 +108,7 @@ struct MySetup {
factory.addPrototype(Blueprint::SP(new ValueBlueprint()));
factory.addPrototype(Blueprint::SP(new ImpureValueBlueprint()));
factory.addPrototype(Blueprint::SP(new SumBlueprint()));
+ factory.addPrototype(Blueprint::SP(new DocidBlueprint()));
}
MySetup &add(const vespalib::string &feature) {
resolver->addSeed(feature);
@@ -79,20 +125,16 @@ struct MySetup {
program.setup(mdl, queryEnv, overrides);
return *this;
}
- MySetup &run() {
- program.run(1);
- return *this;
- }
- double get() {
+ double get(uint32_t docid = default_docid) {
auto result = program.get_seeds();
EXPECT_EQUAL(1u, result.num_features());
- return *result.resolve_number(0);
+ return result.resolve(0).as_number(docid);
}
double get(const vespalib::string &feature) {
auto result = program.get_seeds();
for (size_t i = 0; i < result.num_features(); ++i) {
if (result.name_of(i) == feature) {
- return *result.resolve_number(i);
+ return result.resolve(i).as_number(default_docid);
}
}
return 31212.0;
@@ -101,41 +143,42 @@ struct MySetup {
auto result = program.get_seeds();
std::map<vespalib::string, double> result_map;
for (size_t i = 0; i < result.num_features(); ++i) {
- result_map[result.name_of(i)] = *result.resolve_number(i);
+ result_map[result.name_of(i)] = result.resolve(i).as_number(default_docid);
}
return result_map;
}
};
TEST_F("require that simple program works", MySetup()) {
- EXPECT_EQUAL(15.0, f1.add("mysum(value(10),ivalue(5))").compile().run().get());
+ EXPECT_EQUAL(15.0, f1.add("mysum(value(10),ivalue(5))").compile().get());
EXPECT_EQUAL(3u, f1.program.num_executors());
- EXPECT_EQUAL(2u, f1.program.program_size());
+ EXPECT_EQUAL(3u, count_features(f1.program));
+ EXPECT_EQUAL(1u, count_const_features(f1.program));
}
-TEST_F("require that const features are calculated during setup", MySetup()) {
+TEST_F("require that const features work", MySetup()) {
f1.add("mysum(value(10),value(5))").compile();
EXPECT_EQUAL(15.0, f1.get());
EXPECT_EQUAL(3u, f1.program.num_executors());
- EXPECT_EQUAL(0u, f1.program.program_size());
+ EXPECT_EQUAL(3u, count_features(f1.program));
+ EXPECT_EQUAL(3u, count_const_features(f1.program));
}
-TEST_F("require that non-const features are calculated during run", MySetup()) {
+TEST_F("require that non-const features work", MySetup()) {
f1.add("mysum(ivalue(10),ivalue(5))").compile();
- EXPECT_EQUAL(0.0, f1.get());
- f1.run();
EXPECT_EQUAL(15.0, f1.get());
EXPECT_EQUAL(3u, f1.program.num_executors());
- EXPECT_EQUAL(3u, f1.program.program_size());
+ EXPECT_EQUAL(3u, count_features(f1.program));
+ EXPECT_EQUAL(0u, count_const_features(f1.program));
}
TEST_F("require that a single program can calculate multiple output features", MySetup()) {
f1.add("value(1)").add("ivalue(2)").add("ivalue(3)");
f1.add("mysum(value(1),value(2),ivalue(3))");
- f1.compile().run();
+ f1.compile();
EXPECT_EQUAL(5u, f1.program.num_executors());
- EXPECT_EQUAL(3u, f1.program.program_size());
- EXPECT_EQUAL(5u, count_unique_features(f1.program));
+ EXPECT_EQUAL(5u, count_features(f1.program));
+ EXPECT_EQUAL(2u, count_const_features(f1.program));
auto result = f1.all();
EXPECT_EQUAL(4u, result.size());
EXPECT_EQUAL(1.0, result["value(1)"]);
@@ -146,20 +189,20 @@ TEST_F("require that a single program can calculate multiple output features", M
TEST_F("require that a single executor can produce multiple features", MySetup()) {
f1.add("mysum(value(1,2,3).0,value(1,2,3).1,value(1,2,3).2)");
- EXPECT_EQUAL(6.0, f1.compile().run().get());
+ EXPECT_EQUAL(6.0, f1.compile().get());
EXPECT_EQUAL(2u, f1.program.num_executors());
- EXPECT_EQUAL(0u, f1.program.program_size());
- EXPECT_EQUAL(4u, count_unique_features(f1.program));
+ EXPECT_EQUAL(4u, count_features(f1.program));
+ EXPECT_EQUAL(4u, count_const_features(f1.program));
}
TEST_F("require that feature values can be overridden", MySetup()) {
f1.add("value(1)").add("ivalue(2)").add("ivalue(3)");
f1.add("mysum(value(1),value(2),ivalue(3))");
f1.override("value(2)", 20.0).override("ivalue(3)", 30.0);
- f1.compile().run();
+ f1.compile();
EXPECT_EQUAL(5u, f1.program.num_executors());
- EXPECT_EQUAL(3u, f1.program.program_size());
- EXPECT_EQUAL(5u, count_unique_features(f1.program));
+ EXPECT_EQUAL(5u, count_features(f1.program));
+ EXPECT_EQUAL(2u, count_const_features(f1.program));
auto result = f1.all();
EXPECT_EQUAL(4u, result.size());
EXPECT_EQUAL(1.0, result["value(1)"]);
@@ -168,4 +211,14 @@ TEST_F("require that feature values can be overridden", MySetup()) {
EXPECT_EQUAL(51.0, result["mysum(value(1),value(2),ivalue(3))"]);
}
+TEST_F("require that the rank program can calculate scores for multiple documents", MySetup()) {
+ f1.add("mysum(value(10),docid)").compile();
+ EXPECT_EQUAL(3u, count_features(f1.program));
+ EXPECT_EQUAL(1u, count_const_features(f1.program));
+ EXPECT_EQUAL(f1.get(1), 11.0);
+ EXPECT_EQUAL(f1.get(2), 12.0);
+ EXPECT_EQUAL(f1.get(3), 13.0);
+ EXPECT_EQUAL(f1.get(1), 11.0);
+}
+
TEST_MAIN() { TEST_RUN_ALL(); }