aboutsummaryrefslogtreecommitdiffstats
path: root/searchlib/src/tests
diff options
context:
space:
mode:
Diffstat (limited to 'searchlib/src/tests')
-rw-r--r--searchlib/src/tests/attribute/bitvector_search_cache/bitvector_search_cache_test.cpp13
-rw-r--r--searchlib/src/tests/attribute/imported_search_context/imported_search_context_test.cpp4
-rw-r--r--searchlib/src/tests/attribute/tensorattribute/tensorattribute_test.cpp77
-rw-r--r--searchlib/src/tests/features/element_similarity_feature/CMakeLists.txt2
-rw-r--r--searchlib/src/tests/features/euclidean_distance/euclidean_distance_test.cpp1
-rw-r--r--searchlib/src/tests/features/first_phase_rank/CMakeLists.txt11
-rw-r--r--searchlib/src/tests/features/first_phase_rank/first_phase_rank_test.cpp143
-rw-r--r--searchlib/src/tests/features/prod_features_test.cpp27
-rw-r--r--searchlib/src/tests/fef/phrasesplitter/benchmark.cpp46
-rw-r--r--searchlib/src/tests/fef/properties/CMakeLists.txt1
-rw-r--r--searchlib/src/tests/fef/properties/properties_test.cpp564
-rw-r--r--searchlib/src/tests/fef/table/CMakeLists.txt1
-rw-r--r--searchlib/src/tests/fef/table/table_test.cpp98
-rw-r--r--searchlib/src/tests/hitcollector/CMakeLists.txt2
-rw-r--r--searchlib/src/tests/hitcollector/hitcollector_test.cpp272
-rw-r--r--searchlib/src/tests/hitcollector/sorted_hit_sequence_test.cpp14
-rw-r--r--searchlib/src/tests/nearsearch/CMakeLists.txt1
-rw-r--r--searchlib/src/tests/nearsearch/nearsearch_test.cpp132
-rw-r--r--searchlib/src/tests/query/CMakeLists.txt1
-rw-r--r--searchlib/src/tests/query/templatetermvisitor_test.cpp27
-rw-r--r--searchlib/src/tests/queryeval/blueprint/CMakeLists.txt1
-rw-r--r--searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp50
-rw-r--r--searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp12
-rw-r--r--searchlib/src/tests/queryeval/blueprint/leaf_blueprints_test.cpp73
-rw-r--r--searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp2
-rw-r--r--searchlib/src/tests/queryeval/flow/queryeval_flow_test.cpp30
-rw-r--r--searchlib/src/tests/queryeval/iterator_benchmark/intermediate_blueprint_factory.cpp42
-rw-r--r--searchlib/src/tests/queryeval/iterator_benchmark/intermediate_blueprint_factory.h25
-rw-r--r--searchlib/src/tests/queryeval/iterator_benchmark/iterator_benchmark_test.cpp178
-rw-r--r--searchlib/src/tests/queryeval/parallel_weak_and/parallel_weak_and_test.cpp52
-rw-r--r--searchlib/src/tests/queryeval/sourceblender/sourceblender_test.cpp35
-rw-r--r--searchlib/src/tests/queryeval/sparse_vector_benchmark/sparse_vector_benchmark_test.cpp8
-rw-r--r--searchlib/src/tests/queryeval/termwise_eval/termwise_eval_test.cpp2
-rw-r--r--searchlib/src/tests/queryeval/weak_and/wand_bench_setup.hpp112
-rw-r--r--searchlib/src/tests/queryeval/weak_and/weak_and_test.cpp23
-rw-r--r--searchlib/src/tests/queryeval/weak_and/weak_and_test_expensive.cpp9
-rw-r--r--searchlib/src/tests/queryeval/weak_and_scorers/weak_and_scorers_test.cpp23
-rw-r--r--searchlib/src/tests/ranksetup/CMakeLists.txt1
-rw-r--r--searchlib/src/tests/ranksetup/ranksetup_test.cpp382
-rw-r--r--searchlib/src/tests/sort/CMakeLists.txt1
-rw-r--r--searchlib/src/tests/sort/uca.cpp53
-rw-r--r--searchlib/src/tests/tensor/distance_calculator/distance_calculator_test.cpp1
-rw-r--r--searchlib/src/tests/tensor/distance_functions/CMakeLists.txt7
-rw-r--r--searchlib/src/tests/tensor/distance_functions/distance_functions_benchmark.cpp133
-rw-r--r--searchlib/src/tests/tensor/distance_functions/distance_functions_test.cpp71
-rw-r--r--searchlib/src/tests/tensor/hnsw_index/hnsw_index_test.cpp38
-rw-r--r--searchlib/src/tests/util/token_extractor/token_extractor_test.cpp2
47 files changed, 1762 insertions, 1041 deletions
diff --git a/searchlib/src/tests/attribute/bitvector_search_cache/bitvector_search_cache_test.cpp b/searchlib/src/tests/attribute/bitvector_search_cache/bitvector_search_cache_test.cpp
index d51ec22a54a..1d66eefaff7 100644
--- a/searchlib/src/tests/attribute/bitvector_search_cache/bitvector_search_cache_test.cpp
+++ b/searchlib/src/tests/attribute/bitvector_search_cache/bitvector_search_cache_test.cpp
@@ -3,6 +3,7 @@
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/searchlib/attribute/bitvector_search_cache.h>
#include <vespa/searchlib/common/bitvector.h>
+#include <vespa/vespalib/util/memoryusage.h>
using namespace search;
using namespace search::attribute;
@@ -31,9 +32,13 @@ struct Fixture {
TEST_F("require that bit vectors can be inserted and retrieved", Fixture)
{
EXPECT_EQUAL(0u, f.cache.size());
+ auto old_mem_usage = f.cache.get_memory_usage();
f.cache.insert("foo", f.entry1);
f.cache.insert("bar", f.entry2);
EXPECT_EQUAL(2u, f.cache.size());
+ auto new_mem_usage = f.cache.get_memory_usage();
+ EXPECT_LESS(old_mem_usage.usedBytes(), new_mem_usage.usedBytes());
+ EXPECT_LESS(old_mem_usage.allocatedBytes(), new_mem_usage.allocatedBytes());
EXPECT_EQUAL(f.entry1, f.cache.find("foo"));
EXPECT_EQUAL(f.entry2, f.cache.find("bar"));
@@ -43,9 +48,13 @@ TEST_F("require that bit vectors can be inserted and retrieved", Fixture)
TEST_F("require that insert() doesn't replace existing bit vector", Fixture)
{
f.cache.insert("foo", f.entry1);
+ auto old_mem_usage = f.cache.get_memory_usage();
f.cache.insert("foo", f.entry2);
+ auto new_mem_usage = f.cache.get_memory_usage();
EXPECT_EQUAL(1u, f.cache.size());
EXPECT_EQUAL(f.entry1, f.cache.find("foo"));
+ EXPECT_EQUAL(old_mem_usage.usedBytes(), new_mem_usage.usedBytes());
+ EXPECT_EQUAL(old_mem_usage.allocatedBytes(), new_mem_usage.allocatedBytes());
}
TEST_F("require that cache can be cleared", Fixture)
@@ -53,11 +62,15 @@ TEST_F("require that cache can be cleared", Fixture)
f.cache.insert("foo", f.entry1);
f.cache.insert("bar", f.entry2);
EXPECT_EQUAL(2u, f.cache.size());
+ auto old_mem_usage = f.cache.get_memory_usage();
f.cache.clear();
+ auto new_mem_usage = f.cache.get_memory_usage();
EXPECT_EQUAL(0u, f.cache.size());
EXPECT_TRUE(f.cache.find("foo").get() == nullptr);
EXPECT_TRUE(f.cache.find("bar").get() == nullptr);
+ EXPECT_GREATER(old_mem_usage.usedBytes(), new_mem_usage.usedBytes());
+ EXPECT_GREATER(old_mem_usage.allocatedBytes(), new_mem_usage.allocatedBytes());
}
TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/searchlib/src/tests/attribute/imported_search_context/imported_search_context_test.cpp b/searchlib/src/tests/attribute/imported_search_context/imported_search_context_test.cpp
index 41ec377dece..7c38c322bc8 100644
--- a/searchlib/src/tests/attribute/imported_search_context/imported_search_context_test.cpp
+++ b/searchlib/src/tests/attribute/imported_search_context/imported_search_context_test.cpp
@@ -508,6 +508,7 @@ assertBitVector(const std::vector<uint32_t> &expDocIds, const BitVector &bitVect
TEST_F("Entry is inserted into search cache if bit vector posting list is used", SearchCacheFixture)
{
EXPECT_EQUAL(0u, f.imported_attr->getSearchCache()->size());
+ auto old_mem_usage = f.imported_attr->get_memory_usage();
auto ctx = f.create_context(word_term("5678"));
ctx->fetchPostings(queryeval::ExecuteInfo::FULL, true);
TermFieldMatchData match;
@@ -515,6 +516,9 @@ TEST_F("Entry is inserted into search cache if bit vector posting list is used",
TEST_DO(f.assertSearch({3, 5}, *iter));
EXPECT_EQUAL(1u, f.imported_attr->getSearchCache()->size());
+ auto new_mem_usage = f.imported_attr->get_memory_usage();
+ EXPECT_LESS(old_mem_usage.usedBytes(), new_mem_usage.usedBytes());
+ EXPECT_LESS(old_mem_usage.allocatedBytes(), new_mem_usage.allocatedBytes());
auto cacheEntry = f.imported_attr->getSearchCache()->find("5678");
EXPECT_EQUAL(cacheEntry->docIdLimit, f.get_imported_attr()->getNumDocs());
TEST_DO(assertBitVector({3, 5}, *cacheEntry->bitVector));
diff --git a/searchlib/src/tests/attribute/tensorattribute/tensorattribute_test.cpp b/searchlib/src/tests/attribute/tensorattribute/tensorattribute_test.cpp
index b1b2235165f..cce72837dad 100644
--- a/searchlib/src/tests/attribute/tensorattribute/tensorattribute_test.cpp
+++ b/searchlib/src/tests/attribute/tensorattribute/tensorattribute_test.cpp
@@ -210,8 +210,10 @@ public:
}
void expect_entry(uint32_t exp_docid, const DoubleVector& exp_vector, const EntryVector& entries) const {
EXPECT_EQUAL(1u, entries.size());
- EXPECT_EQUAL(exp_docid, entries.back().first);
- EXPECT_EQUAL(exp_vector, entries.back().second);
+ if (entries.size() >= 1u) {
+ EXPECT_EQUAL(exp_docid, entries.back().first);
+ EXPECT_EQUAL(exp_vector, entries.back().second);
+ }
}
void expect_add(uint32_t exp_docid, const DoubleVector& exp_vector) const {
expect_entry(exp_docid, exp_vector, _adds);
@@ -329,6 +331,10 @@ public:
static search::tensor::DistanceFunctionFactory::UP my_dist_fun = search::tensor::make_distance_function_factory(search::attribute::DistanceMetric::Euclidean, vespalib::eval::CellType::DOUBLE);
return *my_dist_fun;
}
+
+ uint32_t check_consistency(uint32_t) const noexcept override {
+ return 0;
+ }
};
class MockNearestNeighborIndexFactory : public NearestNeighborIndexFactory {
@@ -1077,8 +1083,22 @@ TEST_F("Populates address space usage in mixed tensor attribute with hnsw index"
class DenseTensorAttributeMockIndex : public Fixture {
public:
DenseTensorAttributeMockIndex() : Fixture(vec_2d_spec, FixtureTraits().mock_hnsw()) {}
+ void add_vec_a();
};
+void
+DenseTensorAttributeMockIndex::add_vec_a()
+{
+ auto& index = mock_index();
+ auto vec_a = vec_2d(3, 5);
+ auto prepare_result = prepare_set_tensor(1, vec_a);
+ index.expect_prepare_add(1, {3, 5});
+ complete_set_tensor(1, vec_a, std::move(prepare_result));
+ assertGetTensor(vec_a, 1);
+ index.expect_complete_add(1, {3, 5});
+ index.clear();
+}
+
TEST_F("setTensor() updates nearest neighbor index", DenseTensorAttributeMockIndex)
{
auto& index = f.mock_index();
@@ -1097,15 +1117,7 @@ TEST_F("setTensor() updates nearest neighbor index", DenseTensorAttributeMockInd
TEST_F("nearest neighbor index can be updated in two phases", DenseTensorAttributeMockIndex)
{
auto& index = f.mock_index();
- {
- auto vec_a = vec_2d(3, 5);
- auto prepare_result = f.prepare_set_tensor(1, vec_a);
- index.expect_prepare_add(1, {3, 5});
- f.complete_set_tensor(1, vec_a, std::move(prepare_result));
- f.assertGetTensor(vec_a, 1);
- index.expect_complete_add(1, {3, 5});
- }
- index.clear();
+ f.add_vec_a();
{
// Replaces previous value.
auto vec_b = vec_2d(7, 9);
@@ -1121,15 +1133,7 @@ TEST_F("nearest neighbor index can be updated in two phases", DenseTensorAttribu
TEST_F("nearest neighbor index is NOT updated when tensor value is unchanged", DenseTensorAttributeMockIndex)
{
auto& index = f.mock_index();
- {
- auto vec_a = vec_2d(3, 5);
- auto prepare_result = f.prepare_set_tensor(1, vec_a);
- index.expect_prepare_add(1, {3, 5});
- f.complete_set_tensor(1, vec_a, std::move(prepare_result));
- f.assertGetTensor(vec_a, 1);
- index.expect_complete_add(1, {3, 5});
- }
- index.clear();
+ f.add_vec_a();
{
// Replaces previous value with the same value
auto vec_b = vec_2d(3, 5);
@@ -1139,6 +1143,39 @@ TEST_F("nearest neighbor index is NOT updated when tensor value is unchanged", D
f.complete_set_tensor(1, vec_b, std::move(prepare_result));
f.assertGetTensor(vec_b, 1);
index.expect_empty_complete_add();
+ index.expect_empty_add();
+ }
+}
+
+TEST_F("nearest neighbor index is updated when value changes from A to B to A", DenseTensorAttributeMockIndex)
+{
+ auto& index = f.mock_index();
+ f.add_vec_a();
+ {
+ // Prepare replace of A with B
+ auto vec_b = vec_2d(7, 9);
+ auto prepare_result_b = f.prepare_set_tensor(1, vec_b);
+ index.expect_prepare_add(1, {7, 9});
+ index.clear();
+ // Prepare replace of B with A, but prepare sees original A
+ auto vec_a = vec_2d(3, 5);
+ auto prepare_result_a = f.prepare_set_tensor(1, vec_a);
+ EXPECT_TRUE(prepare_result_a.get() == nullptr);
+ index.expect_empty_prepare_add();
+ index.clear();
+ // Complete set B
+ f.complete_set_tensor(1, vec_b, std::move(prepare_result_b));
+ index.expect_remove(1, {3, 5});
+ f.assertGetTensor(vec_b, 1);
+ index.expect_complete_add(1, {7, 9});
+ index.expect_empty_add();
+ index.clear();
+ // Complete set A, no prepare result but tensor cells changed
+ f.complete_set_tensor(1, vec_a, std::move(prepare_result_a));
+ index.expect_remove(1, {7, 9});
+ index.expect_empty_complete_add();
+ index.expect_add(1, {3, 5});
+ f.assertGetTensor(vec_a, 1);
}
}
diff --git a/searchlib/src/tests/features/element_similarity_feature/CMakeLists.txt b/searchlib/src/tests/features/element_similarity_feature/CMakeLists.txt
index 748556b0fcd..7703d9be0c6 100644
--- a/searchlib/src/tests/features/element_similarity_feature/CMakeLists.txt
+++ b/searchlib/src/tests/features/element_similarity_feature/CMakeLists.txt
@@ -6,4 +6,4 @@ vespa_add_executable(searchlib_element_similarity_feature_test_app TEST
searchlib
searchlib_test
)
-vespa_add_test(NAME searchlib_element_similarity_feature_test_app COMMAND searchlib_element_similarity_feature_test_app)
+vespa_add_test(NAME searchlib_element_similarity_feature_test_app COMMAND searchlib_element_similarity_feature_test_app COST 50)
diff --git a/searchlib/src/tests/features/euclidean_distance/euclidean_distance_test.cpp b/searchlib/src/tests/features/euclidean_distance/euclidean_distance_test.cpp
index e7523288e8f..82e227e0d35 100644
--- a/searchlib/src/tests/features/euclidean_distance/euclidean_distance_test.cpp
+++ b/searchlib/src/tests/features/euclidean_distance/euclidean_distance_test.cpp
@@ -1,5 +1,4 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/searchcommon/attribute/config.h>
#include <vespa/searchlib/attribute/attributefactory.h>
diff --git a/searchlib/src/tests/features/first_phase_rank/CMakeLists.txt b/searchlib/src/tests/features/first_phase_rank/CMakeLists.txt
new file mode 100644
index 00000000000..5aa83399d3d
--- /dev/null
+++ b/searchlib/src/tests/features/first_phase_rank/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+vespa_add_executable(searchlib_features_first_phase_rank_test_app TEST
+ SOURCES
+ first_phase_rank_test.cpp
+ DEPENDS
+ searchlib
+ searchlib_test
+ GTest::GTest
+)
+vespa_add_test(NAME searchlib_features_first_phase_rank_test_app COMMAND searchlib_features_first_phase_rank_test_app)
diff --git a/searchlib/src/tests/features/first_phase_rank/first_phase_rank_test.cpp b/searchlib/src/tests/features/first_phase_rank/first_phase_rank_test.cpp
new file mode 100644
index 00000000000..01ba6c36124
--- /dev/null
+++ b/searchlib/src/tests/features/first_phase_rank/first_phase_rank_test.cpp
@@ -0,0 +1,143 @@
+// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/searchlib/features/first_phase_rank_feature.h>
+#include <vespa/searchlib/features/setup.h>
+#include <vespa/searchlib/fef/blueprintfactory.h>
+#include <vespa/searchlib/fef/test/dummy_dependency_handler.h>
+#include <vespa/searchlib/fef/test/indexenvironment.h>
+#include <vespa/searchlib/fef/test/indexenvironmentbuilder.h>
+#define ENABLE_GTEST_MIGRATION
+#include <vespa/searchlib/test/ft_test_app_base.h>
+#include <vespa/vespalib/gtest/gtest.h>
+
+using search::features::FirstPhaseRankBlueprint;
+using search::features::FirstPhaseRankLookup;
+using search::features::setup_search_features;
+using search::fef::Blueprint;
+using search::fef::BlueprintFactory;
+using search::fef::ObjectStore;
+using search::fef::test::IndexEnvironment;
+using search::fef::test::DummyDependencyHandler;
+using StringVector = std::vector<vespalib::string>;
+
+constexpr feature_t unranked = std::numeric_limits<feature_t>::max();
+
+struct FirstPhaseRankBlueprintTest : public ::testing::Test {
+ BlueprintFactory factory;
+ IndexEnvironment index_env;
+
+ FirstPhaseRankBlueprintTest()
+ : ::testing::Test(),
+ factory(),
+ index_env()
+ {
+ setup_search_features(factory);
+ }
+
+ ~FirstPhaseRankBlueprintTest() override;
+
+ std::shared_ptr<Blueprint> make_blueprint() const {
+ return factory.createBlueprint("firstPhaseRank");
+ }
+
+ void expect_setup_fail(const StringVector& params, const vespalib::string& exp_fail_msg) {
+ auto blueprint = make_blueprint();
+ DummyDependencyHandler deps(*blueprint);
+ EXPECT_FALSE(blueprint->setup(index_env, params));
+ EXPECT_EQ(exp_fail_msg, deps.fail_msg);
+ }
+
+ std::shared_ptr<Blueprint> expect_setup_succeed(const StringVector& params) {
+ auto blueprint = make_blueprint();
+ DummyDependencyHandler deps(*blueprint);
+ EXPECT_TRUE(blueprint->setup(index_env, params));
+ EXPECT_EQ(0, deps.input.size());
+ EXPECT_EQ(StringVector({"score"}), deps.output);
+ return blueprint;
+ }
+};
+
+FirstPhaseRankBlueprintTest::~FirstPhaseRankBlueprintTest() = default;
+
+TEST_F(FirstPhaseRankBlueprintTest, blueprint_can_be_created_from_factory)
+{
+ auto bp = make_blueprint();
+ EXPECT_TRUE(bp);
+ EXPECT_TRUE(dynamic_pointer_cast<FirstPhaseRankBlueprint>(bp));
+}
+
+TEST_F(FirstPhaseRankBlueprintTest, blueprint_setup_fails_when_parameter_list_is_not_empty)
+{
+ expect_setup_fail({"is"},
+ "The parameter list used for setting up rank feature firstPhaseRank is not valid: "
+ "Expected 0 parameter(s), but got 1");
+}
+
+TEST_F(FirstPhaseRankBlueprintTest, blueprint_setup_succeeds)
+{
+ expect_setup_succeed({});
+}
+
+TEST_F(FirstPhaseRankBlueprintTest, blueprint_can_prepare_shared_state)
+{
+ auto blueprint = expect_setup_succeed({});
+ search::fef::test::QueryEnvironment query_env;
+ ObjectStore store;
+ EXPECT_EQ(nullptr, FirstPhaseRankLookup::get_mutable_shared_state(store));
+ EXPECT_EQ(nullptr, FirstPhaseRankLookup::get_shared_state(store));
+ blueprint->prepareSharedState(query_env, store);
+ EXPECT_NE(nullptr, FirstPhaseRankLookup::get_mutable_shared_state(store));
+ EXPECT_NE(nullptr, FirstPhaseRankLookup::get_shared_state(store));
+}
+
+TEST_F(FirstPhaseRankBlueprintTest, dump_features)
+{
+ FtTestAppBase::FT_DUMP_EMPTY(factory, "firstPhaseRank", index_env);
+}
+
+struct FirstPhaseRankExecutorTest : public ::testing::Test {
+ BlueprintFactory factory;
+ FtFeatureTest test;
+
+ FirstPhaseRankExecutorTest()
+ : ::testing::Test(),
+ factory(),
+ test(factory, "firstPhaseRank")
+ {
+ setup_search_features(factory);
+ }
+ ~FirstPhaseRankExecutorTest() override;
+ void setup(std::vector<std::pair<uint32_t,uint32_t>> ranks) {
+ EXPECT_TRUE(test.setup());
+ auto* lookup = FirstPhaseRankLookup::get_mutable_shared_state(test.getQueryEnv().getObjectStore());
+ ASSERT_NE(nullptr, lookup);
+ for (auto& entry : ranks) {
+ lookup->add(entry.first, entry.second);
+ }
+ }
+ bool execute(feature_t exp_score, uint32_t docid) {
+ return test.execute(exp_score, 0.000001, docid);
+ }
+};
+
+FirstPhaseRankExecutorTest::~FirstPhaseRankExecutorTest() = default;
+
+TEST_F(FirstPhaseRankExecutorTest, unranked_docid_gives_huge_output)
+{
+ setup({});
+ EXPECT_TRUE(execute(unranked, 1));
+}
+
+TEST_F(FirstPhaseRankExecutorTest, ranked_docid_gives_expected_output)
+{
+ setup({{3, 5}, {7, 4}});
+ EXPECT_TRUE(execute(unranked, 2));
+ EXPECT_TRUE(execute(5, 3));
+ EXPECT_TRUE(execute(unranked, 4));
+ EXPECT_TRUE(execute(unranked, 5));
+ EXPECT_TRUE(execute(unranked, 6));
+ EXPECT_TRUE(execute(4, 7));
+ EXPECT_TRUE(execute(unranked, 8));
+}
+
+GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/searchlib/src/tests/features/prod_features_test.cpp b/searchlib/src/tests/features/prod_features_test.cpp
index 22105533895..fb00b4ff5e6 100644
--- a/searchlib/src/tests/features/prod_features_test.cpp
+++ b/searchlib/src/tests/features/prod_features_test.cpp
@@ -33,6 +33,7 @@
#include <vespa/searchlib/features/random_normal_stable_feature.h>
#include <vespa/searchlib/features/randomfeature.h>
#include <vespa/searchlib/features/rankingexpressionfeature.h>
+#include <vespa/searchlib/features/second_phase_feature.h>
#include <vespa/searchlib/features/setup.h>
#include <vespa/searchlib/features/termfeature.h>
#include <vespa/searchlib/features/utils.h>
@@ -614,6 +615,32 @@ TEST_F(ProdFeaturesTest, test_first_phase)
}
}
+TEST_F(ProdFeaturesTest, test_second_phase)
+{
+ { // Test blueprint.
+ SecondPhaseBlueprint pt;
+
+ EXPECT_TRUE(assertCreateInstance(pt, "secondPhase"));
+
+ FtIndexEnvironment ie;
+ ie.getProperties().add(indexproperties::rank::SecondPhase::NAME, "random");
+
+ StringList params, in, out;
+ FT_SETUP_OK(pt, ie, params, in.add("random"), out.add("score"));
+ FT_SETUP_FAIL(pt, params.add("foo"));
+ params.clear();
+
+ FT_DUMP_EMPTY(_factory, "secondPhase", ie);
+ }
+
+ { // Test executor.
+ FtFeatureTest ft(_factory, "secondPhase");
+ ft.getIndexEnv().getProperties().add(indexproperties::rank::SecondPhase::NAME, "value(11)");
+ ASSERT_TRUE(ft.setup());
+ ASSERT_TRUE(ft.execute(11.0f));
+ }
+}
+
TEST_F(ProdFeaturesTest, test_foreach)
{
{ // Test blueprint.
diff --git a/searchlib/src/tests/fef/phrasesplitter/benchmark.cpp b/searchlib/src/tests/fef/phrasesplitter/benchmark.cpp
index 93a5a01262d..6be252380da 100644
--- a/searchlib/src/tests/fef/phrasesplitter/benchmark.cpp
+++ b/searchlib/src/tests/fef/phrasesplitter/benchmark.cpp
@@ -1,18 +1,16 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/vespalib/testkit/testapp.h>
+
#include <vespa/searchlib/fef/matchdatalayout.h>
#include <vespa/searchlib/fef/phrasesplitter.h>
#include <vespa/searchlib/fef/phrase_splitter_query_env.h>
#include <vespa/searchlib/fef/test/queryenvironment.h>
+#include <vespa/vespalib/util/time.h>
#include <iomanip>
#include <iostream>
-#include <vespa/log/log.h>
-LOG_SETUP("phrasesplitter_test");
-
namespace search::fef {
-class Benchmark : public vespalib::TestApp
+class Benchmark
{
private:
vespalib::Timer _timer;
@@ -20,12 +18,16 @@ private:
void start() { _timer = vespalib::Timer(); }
void sample() { _sample = _timer.elapsed(); }
- void run(size_t numRuns, size_t numPositions);
public:
- Benchmark() : _timer(), _sample(0) {}
- ~Benchmark() override;
- int Main() override;
+ Benchmark()
+ : _timer(),
+ _sample(0)
+ {
+ }
+ ~Benchmark();
+ void run(size_t numRuns, size_t numPositions);
+ vespalib::duration get_sample() const noexcept { return _sample; }
};
Benchmark::~Benchmark() = default;
@@ -61,28 +63,24 @@ Benchmark::run(size_t numRuns, size_t numPositions)
sample();
}
+}
+
int
-Benchmark::Main()
+main(int argc, char* argv[])
{
-
- TEST_INIT("benchmark");
-
- if (_argc != 3) {
+ if (argc != 3) {
std::cout << "Must specify <numRuns> and <numPositions>" << std::endl;
return 0;
}
- size_t numRuns = strtoull(_argv[1], nullptr, 10);
- size_t numPositions = strtoull(_argv[2], nullptr, 10);
+ size_t numRuns = strtoull(argv[1], nullptr, 10);
+ size_t numPositions = strtoull(argv[2], nullptr, 10);
- run(numRuns, numPositions);
+ auto app = std::make_unique<search::fef::Benchmark>();
+ app->run(numRuns, numPositions);
+ auto sample = app->get_sample();
- std::cout << "TET: " << vespalib::count_ms(_sample) << " (ms)" << std::endl;
- std::cout << "ETPD: " << std::fixed << std::setprecision(10) << (vespalib::count_ns(_sample) / (numRuns * 1000000.0)) << " (ms)" << std::endl;
+ std::cout << "TET: " << vespalib::count_ms(sample) << " (ms)" << std::endl;
+ std::cout << "ETPD: " << std::fixed << std::setprecision(10) << (vespalib::count_ns(sample) / (numRuns * 1000000.0)) << " (ms)" << std::endl;
- TEST_DONE();
}
-
-}
-
-TEST_APPHOOK(search::fef::Benchmark);
diff --git a/searchlib/src/tests/fef/properties/CMakeLists.txt b/searchlib/src/tests/fef/properties/CMakeLists.txt
index dd1eb83b0c2..d0abf5bd377 100644
--- a/searchlib/src/tests/fef/properties/CMakeLists.txt
+++ b/searchlib/src/tests/fef/properties/CMakeLists.txt
@@ -4,5 +4,6 @@ vespa_add_executable(searchlib_properties_test_app TEST
properties_test.cpp
DEPENDS
searchlib
+ GTest::gtest
)
vespa_add_test(NAME searchlib_properties_test_app COMMAND searchlib_properties_test_app)
diff --git a/searchlib/src/tests/fef/properties/properties_test.cpp b/searchlib/src/tests/fef/properties/properties_test.cpp
index c8073739b3e..80a7b64a2e0 100644
--- a/searchlib/src/tests/fef/properties/properties_test.cpp
+++ b/searchlib/src/tests/fef/properties/properties_test.cpp
@@ -1,7 +1,7 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/searchlib/fef/indexproperties.h>
#include <vespa/searchlib/fef/properties.h>
+#include <vespa/vespalib/gtest/gtest.h>
#include <limits>
using namespace search::fef;
@@ -30,7 +30,8 @@ Properties make_props(std::initializer_list<std::pair<const char *, std::initial
return props;
}
-TEST("require that namespace visitation works") {
+TEST(PropertiesTest, require_that_namespace_visitation_works)
+{
Properties props = make_props({ {"foo", {"outside"}},
{"foo.a", {"a_value"}},
{"foo.b", {"b_value"}},
@@ -39,20 +40,21 @@ TEST("require that namespace visitation works") {
Properties result;
CopyVisitor copy_visitor(result);
props.visitNamespace("foo", copy_visitor);
- EXPECT_EQUAL(2u, result.numKeys());
- EXPECT_EQUAL(result.lookup("a").get(), Property::Value("a_value"));
- EXPECT_EQUAL(result.lookup("b").get(), Property::Value("b_value"));
+ EXPECT_EQ(2u, result.numKeys());
+ EXPECT_EQ(result.lookup("a").get(), Property::Value("a_value"));
+ EXPECT_EQ(result.lookup("b").get(), Property::Value("b_value"));
}
-TEST("test stuff") {
+TEST(PropertiesTest, test_stuff)
+{
{ // empty lookup result
Property p;
- EXPECT_EQUAL(p.found(), false);
- EXPECT_EQUAL(p.get(), Property::Value(""));
- EXPECT_EQUAL(p.get("fb"), Property::Value("fb"));
- EXPECT_EQUAL(p.size(), 0u);
- EXPECT_EQUAL(p.getAt(0), Property::Value(""));
+ EXPECT_EQ(p.found(), false);
+ EXPECT_EQ(p.get(), Property::Value(""));
+ EXPECT_EQ(p.get("fb"), Property::Value("fb"));
+ EXPECT_EQ(p.size(), 0u);
+ EXPECT_EQ(p.getAt(0), Property::Value(""));
}
{ // add / count / remove
Properties p = make_props({ {"a", {"a1", "a2", "a3"}},
@@ -61,48 +63,48 @@ TEST("test stuff") {
});
const Properties &pc = p;
- EXPECT_EQUAL(pc.numKeys(), 3u);
- EXPECT_EQUAL(pc.numValues(), 6u);
- EXPECT_EQUAL(pc.count("a"), 3u);
- EXPECT_EQUAL(pc.count("b"), 2u);
- EXPECT_EQUAL(pc.count("c"), 1u);
- EXPECT_EQUAL(pc.count("d"), 0u);
+ EXPECT_EQ(pc.numKeys(), 3u);
+ EXPECT_EQ(pc.numValues(), 6u);
+ EXPECT_EQ(pc.count("a"), 3u);
+ EXPECT_EQ(pc.count("b"), 2u);
+ EXPECT_EQ(pc.count("c"), 1u);
+ EXPECT_EQ(pc.count("d"), 0u);
p.remove("d");
- EXPECT_EQUAL(pc.numKeys(), 3u);
- EXPECT_EQUAL(pc.numValues(), 6u);
- EXPECT_EQUAL(pc.count("a"), 3u);
- EXPECT_EQUAL(pc.count("b"), 2u);
- EXPECT_EQUAL(pc.count("c"), 1u);
- EXPECT_EQUAL(pc.count("d"), 0u);
+ EXPECT_EQ(pc.numKeys(), 3u);
+ EXPECT_EQ(pc.numValues(), 6u);
+ EXPECT_EQ(pc.count("a"), 3u);
+ EXPECT_EQ(pc.count("b"), 2u);
+ EXPECT_EQ(pc.count("c"), 1u);
+ EXPECT_EQ(pc.count("d"), 0u);
p.remove("c");
- EXPECT_EQUAL(pc.numKeys(), 2u);
- EXPECT_EQUAL(pc.numValues(), 5u);
- EXPECT_EQUAL(pc.count("a"), 3u);
- EXPECT_EQUAL(pc.count("b"), 2u);
- EXPECT_EQUAL(pc.count("c"), 0u);
- EXPECT_EQUAL(pc.count("d"), 0u);
+ EXPECT_EQ(pc.numKeys(), 2u);
+ EXPECT_EQ(pc.numValues(), 5u);
+ EXPECT_EQ(pc.count("a"), 3u);
+ EXPECT_EQ(pc.count("b"), 2u);
+ EXPECT_EQ(pc.count("c"), 0u);
+ EXPECT_EQ(pc.count("d"), 0u);
p.remove("b");
- EXPECT_EQUAL(pc.numKeys(), 1u);
- EXPECT_EQUAL(pc.numValues(), 3u);
- EXPECT_EQUAL(pc.count("a"), 3u);
- EXPECT_EQUAL(pc.count("b"), 0u);
- EXPECT_EQUAL(pc.count("c"), 0u);
- EXPECT_EQUAL(pc.count("d"), 0u);
+ EXPECT_EQ(pc.numKeys(), 1u);
+ EXPECT_EQ(pc.numValues(), 3u);
+ EXPECT_EQ(pc.count("a"), 3u);
+ EXPECT_EQ(pc.count("b"), 0u);
+ EXPECT_EQ(pc.count("c"), 0u);
+ EXPECT_EQ(pc.count("d"), 0u);
p.remove("a");
- EXPECT_EQUAL(pc.numKeys(), 0u);
- EXPECT_EQUAL(pc.numValues(), 0u);
- EXPECT_EQUAL(pc.count("a"), 0u);
- EXPECT_EQUAL(pc.count("b"), 0u);
- EXPECT_EQUAL(pc.count("c"), 0u);
- EXPECT_EQUAL(pc.count("d"), 0u);
+ EXPECT_EQ(pc.numKeys(), 0u);
+ EXPECT_EQ(pc.numValues(), 0u);
+ EXPECT_EQ(pc.count("a"), 0u);
+ EXPECT_EQ(pc.count("b"), 0u);
+ EXPECT_EQ(pc.count("c"), 0u);
+ EXPECT_EQ(pc.count("d"), 0u);
}
{ // lookup / import / visit / compare / hash
Properties p;
@@ -114,38 +116,38 @@ TEST("test stuff") {
p.add("list", "e1").add("list", "e2").add("list", "e3");
- EXPECT_EQUAL(p.numKeys(), 5u);
- EXPECT_EQUAL(p.numValues(), 7u);
-
- EXPECT_EQUAL(p.lookup("x").found(), true);
- EXPECT_EQUAL(p.lookup("a.x").found(), true);
- EXPECT_EQUAL(p.lookup("a.b.x").found(), true);
- EXPECT_EQUAL(p.lookup("a.b.c.x").found(), true);
- EXPECT_EQUAL(p.lookup("list").found(), true);
- EXPECT_EQUAL(p.lookup("y").found(), false);
-
- EXPECT_EQUAL(p.lookup("x").get(), Property::Value("x1"));
- EXPECT_EQUAL(p.lookup("a.x").get(), Property::Value("x2"));
- EXPECT_EQUAL(p.lookup("a.b.x").get(), Property::Value("x3"));
- EXPECT_EQUAL(p.lookup("a.b.c.x").get(), Property::Value("x4"));
- EXPECT_EQUAL(p.lookup("list").get(), Property::Value("e1"));
- EXPECT_EQUAL(p.lookup("y").get(), Property::Value(""));
-
- EXPECT_EQUAL(p.lookup("x").get(), Property::Value("x1"));
- EXPECT_EQUAL(p.lookup("a", "x").get(), Property::Value("x2"));
- EXPECT_EQUAL(p.lookup("a", "b", "x").get(), Property::Value("x3"));
- EXPECT_EQUAL(p.lookup("a", "b", "c", "x").get(), Property::Value("x4"));
-
- EXPECT_EQUAL(p.lookup("x").get("fallback"), Property::Value("x1"));
- EXPECT_EQUAL(p.lookup("y").get("fallback"), Property::Value("fallback"));
-
- EXPECT_EQUAL(p.lookup("y").size(), 0u);
- EXPECT_EQUAL(p.lookup("x").size(), 1u);
- EXPECT_EQUAL(p.lookup("list").size(), 3u);
- EXPECT_EQUAL(p.lookup("list").getAt(0), Property::Value("e1"));
- EXPECT_EQUAL(p.lookup("list").getAt(1), Property::Value("e2"));
- EXPECT_EQUAL(p.lookup("list").getAt(2), Property::Value("e3"));
- EXPECT_EQUAL(p.lookup("list").getAt(3), Property::Value(""));
+ EXPECT_EQ(p.numKeys(), 5u);
+ EXPECT_EQ(p.numValues(), 7u);
+
+ EXPECT_EQ(p.lookup("x").found(), true);
+ EXPECT_EQ(p.lookup("a.x").found(), true);
+ EXPECT_EQ(p.lookup("a.b.x").found(), true);
+ EXPECT_EQ(p.lookup("a.b.c.x").found(), true);
+ EXPECT_EQ(p.lookup("list").found(), true);
+ EXPECT_EQ(p.lookup("y").found(), false);
+
+ EXPECT_EQ(p.lookup("x").get(), Property::Value("x1"));
+ EXPECT_EQ(p.lookup("a.x").get(), Property::Value("x2"));
+ EXPECT_EQ(p.lookup("a.b.x").get(), Property::Value("x3"));
+ EXPECT_EQ(p.lookup("a.b.c.x").get(), Property::Value("x4"));
+ EXPECT_EQ(p.lookup("list").get(), Property::Value("e1"));
+ EXPECT_EQ(p.lookup("y").get(), Property::Value(""));
+
+ EXPECT_EQ(p.lookup("x").get(), Property::Value("x1"));
+ EXPECT_EQ(p.lookup("a", "x").get(), Property::Value("x2"));
+ EXPECT_EQ(p.lookup("a", "b", "x").get(), Property::Value("x3"));
+ EXPECT_EQ(p.lookup("a", "b", "c", "x").get(), Property::Value("x4"));
+
+ EXPECT_EQ(p.lookup("x").get("fallback"), Property::Value("x1"));
+ EXPECT_EQ(p.lookup("y").get("fallback"), Property::Value("fallback"));
+
+ EXPECT_EQ(p.lookup("y").size(), 0u);
+ EXPECT_EQ(p.lookup("x").size(), 1u);
+ EXPECT_EQ(p.lookup("list").size(), 3u);
+ EXPECT_EQ(p.lookup("list").getAt(0), Property::Value("e1"));
+ EXPECT_EQ(p.lookup("list").getAt(1), Property::Value("e2"));
+ EXPECT_EQ(p.lookup("list").getAt(2), Property::Value("e3"));
+ EXPECT_EQ(p.lookup("list").getAt(3), Property::Value(""));
Properties p2;
@@ -153,29 +155,29 @@ TEST("test stuff") {
p2.add("y", "y1");
p2.add("list", "foo").add("list", "bar");
- EXPECT_EQUAL(p2.numKeys(), 3u);
- EXPECT_EQUAL(p2.numValues(), 4u);
+ EXPECT_EQ(p2.numKeys(), 3u);
+ EXPECT_EQ(p2.numValues(), 4u);
p.import(p2);
- EXPECT_EQUAL(p.numKeys(), 6u);
- EXPECT_EQUAL(p.numValues(), 7u);
+ EXPECT_EQ(p.numKeys(), 6u);
+ EXPECT_EQ(p.numValues(), 7u);
- EXPECT_EQUAL(p.lookup("y").size(), 1u);
- EXPECT_EQUAL(p.lookup("y").get(), Property::Value("y1"));
+ EXPECT_EQ(p.lookup("y").size(), 1u);
+ EXPECT_EQ(p.lookup("y").get(), Property::Value("y1"));
- EXPECT_EQUAL(p.lookup("x").size(), 1u);
- EXPECT_EQUAL(p.lookup("x").get(), Property::Value("new_x"));
+ EXPECT_EQ(p.lookup("x").size(), 1u);
+ EXPECT_EQ(p.lookup("x").get(), Property::Value("new_x"));
- EXPECT_EQUAL(p.lookup("z").size(), 0u);
+ EXPECT_EQ(p.lookup("z").size(), 0u);
- EXPECT_EQUAL(p.lookup("a", "x").size(), 1u);
- EXPECT_EQUAL(p.lookup("a", "x").get(), Property::Value("x2"));
+ EXPECT_EQ(p.lookup("a", "x").size(), 1u);
+ EXPECT_EQ(p.lookup("a", "x").get(), Property::Value("x2"));
- EXPECT_EQUAL(p.lookup("list").size(), 2u);
- EXPECT_EQUAL(p.lookup("list").getAt(0), Property::Value("foo"));
- EXPECT_EQUAL(p.lookup("list").getAt(1), Property::Value("bar"));
- EXPECT_EQUAL(p.lookup("list").getAt(2), Property::Value(""));
+ EXPECT_EQ(p.lookup("list").size(), 2u);
+ EXPECT_EQ(p.lookup("list").getAt(0), Property::Value("foo"));
+ EXPECT_EQ(p.lookup("list").getAt(1), Property::Value("bar"));
+ EXPECT_EQ(p.lookup("list").getAt(2), Property::Value(""));
Properties p3;
@@ -189,32 +191,32 @@ TEST("test stuff") {
CopyVisitor cv(p3);
p.visitProperties(cv);
- EXPECT_EQUAL(p3.numKeys(), 6u);
- EXPECT_EQUAL(p3.numValues(), 7u);
+ EXPECT_EQ(p3.numKeys(), 6u);
+ EXPECT_EQ(p3.numValues(), 7u);
EXPECT_TRUE(p == p3);
EXPECT_TRUE(p3 == p);
- EXPECT_EQUAL(p.hashCode(), p3.hashCode());
+ EXPECT_EQ(p.hashCode(), p3.hashCode());
p.clear();
- EXPECT_EQUAL(p.numKeys(), 0u);
- EXPECT_EQUAL(p.numValues(), 0u);
+ EXPECT_EQ(p.numKeys(), 0u);
+ EXPECT_EQ(p.numValues(), 0u);
EXPECT_TRUE(!(p == p3));
EXPECT_TRUE(!(p3 == p));
Properties p4;
CopyVisitor cv2(p4);
p.visitProperties(cv);
- EXPECT_EQUAL(p4.numKeys(), 0u);
- EXPECT_EQUAL(p4.numValues(), 0u);
+ EXPECT_EQ(p4.numKeys(), 0u);
+ EXPECT_EQ(p4.numValues(), 0u);
EXPECT_TRUE(p == p4);
EXPECT_TRUE(p4 == p);
- EXPECT_EQUAL(p.hashCode(), p4.hashCode());
+ EXPECT_EQ(p.hashCode(), p4.hashCode());
}
{ // test index properties known by the framework
{ // vespa.eval.lazy_expressions
- EXPECT_EQUAL(eval::LazyExpressions::NAME, vespalib::string("vespa.eval.lazy_expressions"));
+ EXPECT_EQ(eval::LazyExpressions::NAME, vespalib::string("vespa.eval.lazy_expressions"));
{
Properties p;
EXPECT_TRUE(eval::LazyExpressions::check(p, true));
@@ -234,201 +236,203 @@ TEST("test stuff") {
}
}
{ // vespa.eval.use_fast_forest
- EXPECT_EQUAL(eval::UseFastForest::NAME, vespalib::string("vespa.eval.use_fast_forest"));
- EXPECT_EQUAL(eval::UseFastForest::DEFAULT_VALUE, false);
+ EXPECT_EQ(eval::UseFastForest::NAME, vespalib::string("vespa.eval.use_fast_forest"));
+ EXPECT_EQ(eval::UseFastForest::DEFAULT_VALUE, false);
Properties p;
- EXPECT_EQUAL(eval::UseFastForest::check(p), false);
+ EXPECT_EQ(eval::UseFastForest::check(p), false);
p.add("vespa.eval.use_fast_forest", "true");
- EXPECT_EQUAL(eval::UseFastForest::check(p), true);
+ EXPECT_EQ(eval::UseFastForest::check(p), true);
}
{ // vespa.rank.firstphase
- EXPECT_EQUAL(rank::FirstPhase::NAME, vespalib::string("vespa.rank.firstphase"));
- EXPECT_EQUAL(rank::FirstPhase::DEFAULT_VALUE, vespalib::string("nativeRank"));
+ EXPECT_EQ(rank::FirstPhase::NAME, vespalib::string("vespa.rank.firstphase"));
+ EXPECT_EQ(rank::FirstPhase::DEFAULT_VALUE, vespalib::string("nativeRank"));
Properties p;
- EXPECT_EQUAL(rank::FirstPhase::lookup(p), vespalib::string("nativeRank"));
+ EXPECT_EQ(rank::FirstPhase::lookup(p), vespalib::string("nativeRank"));
p.add("vespa.rank.firstphase", "specialrank");
- EXPECT_EQUAL(rank::FirstPhase::lookup(p), vespalib::string("specialrank"));
+ EXPECT_EQ(rank::FirstPhase::lookup(p), vespalib::string("specialrank"));
}
{ // vespa.rank.secondphase
- EXPECT_EQUAL(rank::SecondPhase::NAME, vespalib::string("vespa.rank.secondphase"));
- EXPECT_EQUAL(rank::SecondPhase::DEFAULT_VALUE, vespalib::string(""));
+ EXPECT_EQ(rank::SecondPhase::NAME, vespalib::string("vespa.rank.secondphase"));
+ EXPECT_EQ(rank::SecondPhase::DEFAULT_VALUE, vespalib::string(""));
Properties p;
- EXPECT_EQUAL(rank::SecondPhase::lookup(p), vespalib::string(""));
+ EXPECT_EQ(rank::SecondPhase::lookup(p), vespalib::string(""));
p.add("vespa.rank.secondphase", "specialrank");
- EXPECT_EQUAL(rank::SecondPhase::lookup(p), vespalib::string("specialrank"));
+ EXPECT_EQ(rank::SecondPhase::lookup(p), vespalib::string("specialrank"));
}
{ // vespa.dump.feature
- EXPECT_EQUAL(dump::Feature::NAME, vespalib::string("vespa.dump.feature"));
- EXPECT_EQUAL(dump::Feature::DEFAULT_VALUE.size(), 0u);
+ EXPECT_EQ(dump::Feature::NAME, vespalib::string("vespa.dump.feature"));
+ EXPECT_EQ(dump::Feature::DEFAULT_VALUE.size(), 0u);
Properties p;
- EXPECT_EQUAL(dump::Feature::lookup(p).size(), 0u);
+ EXPECT_EQ(dump::Feature::lookup(p).size(), 0u);
p.add("vespa.dump.feature", "foo");
p.add("vespa.dump.feature", "bar");
std::vector<vespalib::string> a = dump::Feature::lookup(p);
ASSERT_TRUE(a.size() == 2);
- EXPECT_EQUAL(a[0], vespalib::string("foo"));
- EXPECT_EQUAL(a[1], vespalib::string("bar"));
+ EXPECT_EQ(a[0], vespalib::string("foo"));
+ EXPECT_EQ(a[1], vespalib::string("bar"));
}
{ // vespa.dump.ignoredefaultfeatures
- EXPECT_EQUAL(dump::IgnoreDefaultFeatures::NAME, vespalib::string("vespa.dump.ignoredefaultfeatures"));
- EXPECT_EQUAL(dump::IgnoreDefaultFeatures::DEFAULT_VALUE, "false");
+ EXPECT_EQ(dump::IgnoreDefaultFeatures::NAME, vespalib::string("vespa.dump.ignoredefaultfeatures"));
+ EXPECT_EQ(dump::IgnoreDefaultFeatures::DEFAULT_VALUE, "false");
Properties p;
EXPECT_TRUE(!dump::IgnoreDefaultFeatures::check(p));
p.add("vespa.dump.ignoredefaultfeatures", "true");
EXPECT_TRUE(dump::IgnoreDefaultFeatures::check(p));
}
{ // vespa.matching.termwise_limit
- EXPECT_EQUAL(matching::TermwiseLimit::NAME, vespalib::string("vespa.matching.termwise_limit"));
- EXPECT_EQUAL(matching::TermwiseLimit::DEFAULT_VALUE, 1.0);
+ EXPECT_EQ(matching::TermwiseLimit::NAME, vespalib::string("vespa.matching.termwise_limit"));
+ EXPECT_EQ(matching::TermwiseLimit::DEFAULT_VALUE, 1.0);
Properties p;
- EXPECT_EQUAL(matching::TermwiseLimit::lookup(p), 1.0);
+ EXPECT_EQ(matching::TermwiseLimit::lookup(p), 1.0);
p.add("vespa.matching.termwise_limit", "0.05");
- EXPECT_EQUAL(matching::TermwiseLimit::lookup(p), 0.05);
+ EXPECT_EQ(matching::TermwiseLimit::lookup(p), 0.05);
}
{ // vespa.matching.numthreads
- EXPECT_EQUAL(matching::NumThreadsPerSearch::NAME, vespalib::string("vespa.matching.numthreadspersearch"));
- EXPECT_EQUAL(matching::NumThreadsPerSearch::DEFAULT_VALUE, std::numeric_limits<uint32_t>::max());
+ EXPECT_EQ(matching::NumThreadsPerSearch::NAME, vespalib::string("vespa.matching.numthreadspersearch"));
+ EXPECT_EQ(matching::NumThreadsPerSearch::DEFAULT_VALUE, std::numeric_limits<uint32_t>::max());
Properties p;
- EXPECT_EQUAL(matching::NumThreadsPerSearch::lookup(p), std::numeric_limits<uint32_t>::max());
+ EXPECT_EQ(matching::NumThreadsPerSearch::lookup(p), std::numeric_limits<uint32_t>::max());
p.add("vespa.matching.numthreadspersearch", "50");
- EXPECT_EQUAL(matching::NumThreadsPerSearch::lookup(p), 50u);
+ EXPECT_EQ(matching::NumThreadsPerSearch::lookup(p), 50u);
}
{ // vespa.matching.minhitsperthread
- EXPECT_EQUAL(matching::MinHitsPerThread::NAME, vespalib::string("vespa.matching.minhitsperthread"));
- EXPECT_EQUAL(matching::MinHitsPerThread::DEFAULT_VALUE, 0u);
+ EXPECT_EQ(matching::MinHitsPerThread::NAME, vespalib::string("vespa.matching.minhitsperthread"));
+ EXPECT_EQ(matching::MinHitsPerThread::DEFAULT_VALUE, 0u);
Properties p;
- EXPECT_EQUAL(matching::MinHitsPerThread::lookup(p), 0u);
+ EXPECT_EQ(matching::MinHitsPerThread::lookup(p), 0u);
p.add("vespa.matching.minhitsperthread", "50");
- EXPECT_EQUAL(matching::MinHitsPerThread::lookup(p), 50u);
+ EXPECT_EQ(matching::MinHitsPerThread::lookup(p), 50u);
}
{
- EXPECT_EQUAL(matching::NumSearchPartitions::NAME, vespalib::string("vespa.matching.numsearchpartitions"));
- EXPECT_EQUAL(matching::NumSearchPartitions::DEFAULT_VALUE, 1u);
+ EXPECT_EQ(matching::NumSearchPartitions::NAME, vespalib::string("vespa.matching.numsearchpartitions"));
+ EXPECT_EQ(matching::NumSearchPartitions::DEFAULT_VALUE, 1u);
Properties p;
- EXPECT_EQUAL(matching::NumSearchPartitions::lookup(p), 1u);
+ EXPECT_EQ(matching::NumSearchPartitions::lookup(p), 1u);
p.add("vespa.matching.numsearchpartitions", "50");
- EXPECT_EQUAL(matching::NumSearchPartitions::lookup(p), 50u);
+ EXPECT_EQ(matching::NumSearchPartitions::lookup(p), 50u);
}
{ // vespa.matchphase.degradation.attribute
- EXPECT_EQUAL(matchphase::DegradationAttribute::NAME, vespalib::string("vespa.matchphase.degradation.attribute"));
- EXPECT_EQUAL(matchphase::DegradationAttribute::DEFAULT_VALUE, "");
+ EXPECT_EQ(matchphase::DegradationAttribute::NAME, vespalib::string("vespa.matchphase.degradation.attribute"));
+ EXPECT_EQ(matchphase::DegradationAttribute::DEFAULT_VALUE, "");
Properties p;
- EXPECT_EQUAL(matchphase::DegradationAttribute::lookup(p), "");
+ EXPECT_EQ(matchphase::DegradationAttribute::lookup(p), "");
p.add("vespa.matchphase.degradation.attribute", "foobar");
- EXPECT_EQUAL(matchphase::DegradationAttribute::lookup(p), "foobar");
+ EXPECT_EQ(matchphase::DegradationAttribute::lookup(p), "foobar");
}
{ // vespa.matchphase.degradation.ascending
- EXPECT_EQUAL(matchphase::DegradationAscendingOrder::NAME, vespalib::string("vespa.matchphase.degradation.ascendingorder"));
- EXPECT_EQUAL(matchphase::DegradationAscendingOrder::DEFAULT_VALUE, false);
+ EXPECT_EQ(matchphase::DegradationAscendingOrder::NAME, vespalib::string("vespa.matchphase.degradation.ascendingorder"));
+ EXPECT_EQ(matchphase::DegradationAscendingOrder::DEFAULT_VALUE, false);
Properties p;
- EXPECT_EQUAL(matchphase::DegradationAscendingOrder::lookup(p), false);
+ EXPECT_EQ(matchphase::DegradationAscendingOrder::lookup(p), false);
p.add("vespa.matchphase.degradation.ascendingorder", "true");
- EXPECT_EQUAL(matchphase::DegradationAscendingOrder::lookup(p), true);
+ EXPECT_EQ(matchphase::DegradationAscendingOrder::lookup(p), true);
}
{ // vespa.matchphase.degradation.maxhits
- EXPECT_EQUAL(matchphase::DegradationMaxHits::NAME, vespalib::string("vespa.matchphase.degradation.maxhits"));
- EXPECT_EQUAL(matchphase::DegradationMaxHits::DEFAULT_VALUE, 0u);
+ EXPECT_EQ(matchphase::DegradationMaxHits::NAME, vespalib::string("vespa.matchphase.degradation.maxhits"));
+ EXPECT_EQ(matchphase::DegradationMaxHits::DEFAULT_VALUE, 0u);
Properties p;
- EXPECT_EQUAL(matchphase::DegradationMaxHits::lookup(p), 0u);
+ EXPECT_EQ(matchphase::DegradationMaxHits::lookup(p), 0u);
p.add("vespa.matchphase.degradation.maxhits", "123789");
- EXPECT_EQUAL(matchphase::DegradationMaxHits::lookup(p), 123789u);
+ EXPECT_EQ(matchphase::DegradationMaxHits::lookup(p), 123789u);
}
{ // vespa.matchphase.degradation.samplepercentage
- EXPECT_EQUAL(matchphase::DegradationSamplePercentage::NAME, vespalib::string("vespa.matchphase.degradation.samplepercentage"));
- EXPECT_EQUAL(matchphase::DegradationSamplePercentage::DEFAULT_VALUE, 0.2);
+ EXPECT_EQ(matchphase::DegradationSamplePercentage::NAME, vespalib::string("vespa.matchphase.degradation.samplepercentage"));
+ EXPECT_EQ(matchphase::DegradationSamplePercentage::DEFAULT_VALUE, 0.2);
Properties p;
- EXPECT_EQUAL(matchphase::DegradationSamplePercentage::lookup(p), 0.2);
+ EXPECT_EQ(matchphase::DegradationSamplePercentage::lookup(p), 0.2);
p.add("vespa.matchphase.degradation.samplepercentage", "0.9");
- EXPECT_EQUAL(matchphase::DegradationSamplePercentage::lookup(p), 0.9);
+ EXPECT_EQ(matchphase::DegradationSamplePercentage::lookup(p), 0.9);
}
{ // vespa.matchphase.degradation.maxfiltercoverage
- EXPECT_EQUAL(matchphase::DegradationMaxFilterCoverage::NAME, vespalib::string("vespa.matchphase.degradation.maxfiltercoverage"));
- EXPECT_EQUAL(matchphase::DegradationMaxFilterCoverage::DEFAULT_VALUE, 0.2);
+ EXPECT_EQ(matchphase::DegradationMaxFilterCoverage::NAME, vespalib::string("vespa.matchphase.degradation.maxfiltercoverage"));
+ EXPECT_EQ(matchphase::DegradationMaxFilterCoverage::DEFAULT_VALUE, 0.2);
Properties p;
- EXPECT_EQUAL(matchphase::DegradationMaxFilterCoverage::lookup(p), 0.2);
+ EXPECT_EQ(matchphase::DegradationMaxFilterCoverage::lookup(p), 0.2);
p.add("vespa.matchphase.degradation.maxfiltercoverage", "0.076");
- EXPECT_EQUAL(matchphase::DegradationMaxFilterCoverage::lookup(p), 0.076);
+ EXPECT_EQ(matchphase::DegradationMaxFilterCoverage::lookup(p), 0.076);
}
{ // vespa.matchphase.degradation.postfiltermultiplier
- EXPECT_EQUAL(matchphase::DegradationPostFilterMultiplier::NAME, vespalib::string("vespa.matchphase.degradation.postfiltermultiplier"));
- EXPECT_EQUAL(matchphase::DegradationPostFilterMultiplier::DEFAULT_VALUE, 1.0);
+ EXPECT_EQ(matchphase::DegradationPostFilterMultiplier::NAME, vespalib::string("vespa.matchphase.degradation.postfiltermultiplier"));
+ EXPECT_EQ(matchphase::DegradationPostFilterMultiplier::DEFAULT_VALUE, 1.0);
Properties p;
- EXPECT_EQUAL(matchphase::DegradationPostFilterMultiplier::lookup(p), 1.0);
+ EXPECT_EQ(matchphase::DegradationPostFilterMultiplier::lookup(p), 1.0);
p.add("vespa.matchphase.degradation.postfiltermultiplier", "0.9");
- EXPECT_EQUAL(matchphase::DegradationPostFilterMultiplier::lookup(p), 0.9);
+ EXPECT_EQ(matchphase::DegradationPostFilterMultiplier::lookup(p), 0.9);
}
{ // vespa.matchphase.diversity.attribute
- EXPECT_EQUAL(matchphase::DiversityAttribute::NAME, vespalib::string("vespa.matchphase.diversity.attribute"));
- EXPECT_EQUAL(matchphase::DiversityAttribute::DEFAULT_VALUE, "");
+ EXPECT_EQ(matchphase::DiversityAttribute::NAME, vespalib::string("vespa.matchphase.diversity.attribute"));
+ EXPECT_EQ(matchphase::DiversityAttribute::DEFAULT_VALUE, "");
Properties p;
- EXPECT_EQUAL(matchphase::DiversityAttribute::lookup(p), "");
+ EXPECT_EQ(matchphase::DiversityAttribute::lookup(p), "");
p.add("vespa.matchphase.diversity.attribute", "foobar");
- EXPECT_EQUAL(matchphase::DiversityAttribute::lookup(p), "foobar");
+ EXPECT_EQ(matchphase::DiversityAttribute::lookup(p), "foobar");
}
{ // vespa.matchphase.diversity.mingroups
- EXPECT_EQUAL(matchphase::DiversityMinGroups::NAME, vespalib::string("vespa.matchphase.diversity.mingroups"));
- EXPECT_EQUAL(matchphase::DiversityMinGroups::DEFAULT_VALUE, 1u);
+ EXPECT_EQ(matchphase::DiversityMinGroups::NAME, vespalib::string("vespa.matchphase.diversity.mingroups"));
+ EXPECT_EQ(matchphase::DiversityMinGroups::DEFAULT_VALUE, 1u);
Properties p;
- EXPECT_EQUAL(matchphase::DiversityMinGroups::lookup(p), 1u);
+ EXPECT_EQ(matchphase::DiversityMinGroups::lookup(p), 1u);
p.add("vespa.matchphase.diversity.mingroups", "5");
- EXPECT_EQUAL(matchphase::DiversityMinGroups::lookup(p), 5u);
+ EXPECT_EQ(matchphase::DiversityMinGroups::lookup(p), 5u);
}
{ // vespa.hitcollector.heapsize
- EXPECT_EQUAL(hitcollector::HeapSize::NAME, vespalib::string("vespa.hitcollector.heapsize"));
- EXPECT_EQUAL(hitcollector::HeapSize::DEFAULT_VALUE, 100u);
+ EXPECT_EQ(hitcollector::HeapSize::NAME, vespalib::string("vespa.hitcollector.heapsize"));
+ EXPECT_EQ(hitcollector::HeapSize::DEFAULT_VALUE, 100u);
Properties p;
- EXPECT_EQUAL(hitcollector::HeapSize::lookup(p), 100u);
+ EXPECT_EQ(hitcollector::HeapSize::lookup(p), 100u);
p.add("vespa.hitcollector.heapsize", "50");
- EXPECT_EQUAL(hitcollector::HeapSize::lookup(p), 50u);
+ EXPECT_EQ(hitcollector::HeapSize::lookup(p), 50u);
}
{ // vespa.hitcollector.arraysize
- EXPECT_EQUAL(hitcollector::ArraySize::NAME, vespalib::string("vespa.hitcollector.arraysize"));
- EXPECT_EQUAL(hitcollector::ArraySize::DEFAULT_VALUE, 10000u);
+ EXPECT_EQ(hitcollector::ArraySize::NAME, vespalib::string("vespa.hitcollector.arraysize"));
+ EXPECT_EQ(hitcollector::ArraySize::DEFAULT_VALUE, 10000u);
Properties p;
- EXPECT_EQUAL(hitcollector::ArraySize::lookup(p), 10000u);
+ EXPECT_EQ(hitcollector::ArraySize::lookup(p), 10000u);
p.add("vespa.hitcollector.arraysize", "50");
- EXPECT_EQUAL(hitcollector::ArraySize::lookup(p), 50u);
+ EXPECT_EQ(hitcollector::ArraySize::lookup(p), 50u);
}
{ // vespa.hitcollector.estimatepoint
- EXPECT_EQUAL(hitcollector::EstimatePoint::NAME, vespalib::string("vespa.hitcollector.estimatepoint"));
- EXPECT_EQUAL(hitcollector::EstimatePoint::DEFAULT_VALUE, 0xffffffffu);
+ EXPECT_EQ(hitcollector::EstimatePoint::NAME, vespalib::string("vespa.hitcollector.estimatepoint"));
+ EXPECT_EQ(hitcollector::EstimatePoint::DEFAULT_VALUE, 0xffffffffu);
Properties p;
- EXPECT_EQUAL(hitcollector::EstimatePoint::lookup(p), 0xffffffffu);
+ EXPECT_EQ(hitcollector::EstimatePoint::lookup(p), 0xffffffffu);
p.add("vespa.hitcollector.estimatepoint", "50");
- EXPECT_EQUAL(hitcollector::EstimatePoint::lookup(p), 50u);
+ EXPECT_EQ(hitcollector::EstimatePoint::lookup(p), 50u);
}
{ // vespa.hitcollector.estimatelimit
- EXPECT_EQUAL(hitcollector::EstimateLimit::NAME, vespalib::string("vespa.hitcollector.estimatelimit"));
- EXPECT_EQUAL(hitcollector::EstimateLimit::DEFAULT_VALUE, 0xffffffffu);
+ EXPECT_EQ(hitcollector::EstimateLimit::NAME, vespalib::string("vespa.hitcollector.estimatelimit"));
+ EXPECT_EQ(hitcollector::EstimateLimit::DEFAULT_VALUE, 0xffffffffu);
Properties p;
- EXPECT_EQUAL(hitcollector::EstimateLimit::lookup(p), 0xffffffffu);
+ EXPECT_EQ(hitcollector::EstimateLimit::lookup(p), 0xffffffffu);
p.add("vespa.hitcollector.estimatelimit", "50");
- EXPECT_EQUAL(hitcollector::EstimateLimit::lookup(p), 50u);
+ EXPECT_EQ(hitcollector::EstimateLimit::lookup(p), 50u);
}
{ // vespa.hitcollector.rankscoredroplimit
- EXPECT_EQUAL(hitcollector::RankScoreDropLimit::NAME, vespalib::string("vespa.hitcollector.rankscoredroplimit"));
- search::feature_t got1 = hitcollector::RankScoreDropLimit::DEFAULT_VALUE;
- EXPECT_TRUE(got1 != got1);
- Properties p;
- search::feature_t got2= hitcollector::RankScoreDropLimit::lookup(p);
- EXPECT_TRUE(got2 != got2);
+ EXPECT_EQ(vespalib::string("vespa.hitcollector.rankscoredroplimit"), hitcollector::FirstPhaseRankScoreDropLimit::NAME);
+ Properties p;
+ auto got2 = hitcollector::FirstPhaseRankScoreDropLimit::lookup(p);
+ EXPECT_EQ(std::optional<search::feature_t>(), got2);
+ got2 = hitcollector::FirstPhaseRankScoreDropLimit::lookup(p, std::nullopt);
+ EXPECT_EQ(std::optional<search::feature_t>(), got2);
+ got2 = hitcollector::FirstPhaseRankScoreDropLimit::lookup(p, 4.5);
+ EXPECT_EQ(std::optional<search::feature_t>(4.5), got2);
p.add("vespa.hitcollector.rankscoredroplimit", "-123456789.12345");
- EXPECT_EQUAL(hitcollector::RankScoreDropLimit::lookup(p), -123456789.12345);
+ EXPECT_EQ(std::optional<search::feature_t>(-123456789.12345), hitcollector::FirstPhaseRankScoreDropLimit::lookup(p));
p.clear().add("vespa.hitcollector.rankscoredroplimit", "123456789.12345");
- EXPECT_EQUAL(hitcollector::RankScoreDropLimit::lookup(p), 123456789.12345);
+ EXPECT_EQ(std::optional<search::feature_t>(123456789.12345), hitcollector::FirstPhaseRankScoreDropLimit::lookup(p));
}
{ // vespa.fieldweight.
- EXPECT_EQUAL(FieldWeight::BASE_NAME, vespalib::string("vespa.fieldweight."));
- EXPECT_EQUAL(FieldWeight::DEFAULT_VALUE, 100u);
+ EXPECT_EQ(FieldWeight::BASE_NAME, vespalib::string("vespa.fieldweight."));
+ EXPECT_EQ(FieldWeight::DEFAULT_VALUE, 100u);
Properties p;
- EXPECT_EQUAL(FieldWeight::lookup(p, "foo"), 100u);
+ EXPECT_EQ(FieldWeight::lookup(p, "foo"), 100u);
p.add("vespa.fieldweight.foo", "200");
- EXPECT_EQUAL(FieldWeight::lookup(p, "foo"), 200u);
+ EXPECT_EQ(FieldWeight::lookup(p, "foo"), 200u);
}
{ // vespa.isfilterfield.
- EXPECT_EQUAL(IsFilterField::BASE_NAME, "vespa.isfilterfield.");
- EXPECT_EQUAL(IsFilterField::DEFAULT_VALUE, "false");
+ EXPECT_EQ(IsFilterField::BASE_NAME, "vespa.isfilterfield.");
+ EXPECT_EQ(IsFilterField::DEFAULT_VALUE, "false");
Properties p;
EXPECT_TRUE(!IsFilterField::check(p, "foo"));
p.add("vespa.isfilterfield.foo", "true");
@@ -438,192 +442,206 @@ TEST("test stuff") {
EXPECT_TRUE(IsFilterField::check(p, "bar"));
}
{
- EXPECT_EQUAL(mutate::on_match::Attribute::NAME, vespalib::string("vespa.mutate.on_match.attribute"));
- EXPECT_EQUAL(mutate::on_match::Attribute::DEFAULT_VALUE, "");
+ EXPECT_EQ(mutate::on_match::Attribute::NAME, vespalib::string("vespa.mutate.on_match.attribute"));
+ EXPECT_EQ(mutate::on_match::Attribute::DEFAULT_VALUE, "");
Properties p;
- EXPECT_EQUAL(mutate::on_match::Attribute::lookup(p), "");
+ EXPECT_EQ(mutate::on_match::Attribute::lookup(p), "");
p.add("vespa.mutate.on_match.attribute", "foobar");
- EXPECT_EQUAL(mutate::on_match::Attribute::lookup(p), "foobar");
+ EXPECT_EQ(mutate::on_match::Attribute::lookup(p), "foobar");
}
{
- EXPECT_EQUAL(mutate::on_match::Operation::NAME, vespalib::string("vespa.mutate.on_match.operation"));
- EXPECT_EQUAL(mutate::on_match::Operation::DEFAULT_VALUE, "");
+ EXPECT_EQ(mutate::on_match::Operation::NAME, vespalib::string("vespa.mutate.on_match.operation"));
+ EXPECT_EQ(mutate::on_match::Operation::DEFAULT_VALUE, "");
Properties p;
- EXPECT_EQUAL(mutate::on_match::Operation::lookup(p), "");
+ EXPECT_EQ(mutate::on_match::Operation::lookup(p), "");
p.add("vespa.mutate.on_match.operation", "+=1");
- EXPECT_EQUAL(mutate::on_match::Operation::lookup(p), "+=1");
+ EXPECT_EQ(mutate::on_match::Operation::lookup(p), "+=1");
}
{
- EXPECT_EQUAL(mutate::on_first_phase::Attribute::NAME, vespalib::string("vespa.mutate.on_first_phase.attribute"));
- EXPECT_EQUAL(mutate::on_first_phase::Attribute::DEFAULT_VALUE, "");
+ EXPECT_EQ(mutate::on_first_phase::Attribute::NAME, vespalib::string("vespa.mutate.on_first_phase.attribute"));
+ EXPECT_EQ(mutate::on_first_phase::Attribute::DEFAULT_VALUE, "");
Properties p;
- EXPECT_EQUAL(mutate::on_first_phase::Attribute::lookup(p), "");
+ EXPECT_EQ(mutate::on_first_phase::Attribute::lookup(p), "");
p.add("vespa.mutate.on_first_phase.attribute", "foobar");
- EXPECT_EQUAL(mutate::on_first_phase::Attribute::lookup(p), "foobar");
+ EXPECT_EQ(mutate::on_first_phase::Attribute::lookup(p), "foobar");
}
{
- EXPECT_EQUAL(mutate::on_first_phase::Operation::NAME, vespalib::string("vespa.mutate.on_first_phase.operation"));
- EXPECT_EQUAL(mutate::on_first_phase::Operation::DEFAULT_VALUE, "");
+ EXPECT_EQ(mutate::on_first_phase::Operation::NAME, vespalib::string("vespa.mutate.on_first_phase.operation"));
+ EXPECT_EQ(mutate::on_first_phase::Operation::DEFAULT_VALUE, "");
Properties p;
- EXPECT_EQUAL(mutate::on_first_phase::Operation::lookup(p), "");
+ EXPECT_EQ(mutate::on_first_phase::Operation::lookup(p), "");
p.add("vespa.mutate.on_first_phase.operation", "+=1");
- EXPECT_EQUAL(mutate::on_first_phase::Operation::lookup(p), "+=1");
+ EXPECT_EQ(mutate::on_first_phase::Operation::lookup(p), "+=1");
}
{
- EXPECT_EQUAL(mutate::on_second_phase::Attribute::NAME, vespalib::string("vespa.mutate.on_second_phase.attribute"));
- EXPECT_EQUAL(mutate::on_second_phase::Attribute::DEFAULT_VALUE, "");
+ EXPECT_EQ(mutate::on_second_phase::Attribute::NAME, vespalib::string("vespa.mutate.on_second_phase.attribute"));
+ EXPECT_EQ(mutate::on_second_phase::Attribute::DEFAULT_VALUE, "");
Properties p;
- EXPECT_EQUAL(mutate::on_second_phase::Attribute::lookup(p), "");
+ EXPECT_EQ(mutate::on_second_phase::Attribute::lookup(p), "");
p.add("vespa.mutate.on_second_phase.attribute", "foobar");
- EXPECT_EQUAL(mutate::on_second_phase::Attribute::lookup(p), "foobar");
+ EXPECT_EQ(mutate::on_second_phase::Attribute::lookup(p), "foobar");
}
{
- EXPECT_EQUAL(mutate::on_second_phase::Operation::NAME, vespalib::string("vespa.mutate.on_second_phase.operation"));
- EXPECT_EQUAL(mutate::on_second_phase::Operation::DEFAULT_VALUE, "");
+ EXPECT_EQ(mutate::on_second_phase::Operation::NAME, vespalib::string("vespa.mutate.on_second_phase.operation"));
+ EXPECT_EQ(mutate::on_second_phase::Operation::DEFAULT_VALUE, "");
Properties p;
- EXPECT_EQUAL(mutate::on_second_phase::Operation::lookup(p), "");
+ EXPECT_EQ(mutate::on_second_phase::Operation::lookup(p), "");
p.add("vespa.mutate.on_second_phase.operation", "+=1");
- EXPECT_EQUAL(mutate::on_second_phase::Operation::lookup(p), "+=1");
+ EXPECT_EQ(mutate::on_second_phase::Operation::lookup(p), "+=1");
}
{
- EXPECT_EQUAL(mutate::on_summary::Attribute::NAME, vespalib::string("vespa.mutate.on_summary.attribute"));
- EXPECT_EQUAL(mutate::on_summary::Attribute::DEFAULT_VALUE, "");
+ EXPECT_EQ(mutate::on_summary::Attribute::NAME, vespalib::string("vespa.mutate.on_summary.attribute"));
+ EXPECT_EQ(mutate::on_summary::Attribute::DEFAULT_VALUE, "");
Properties p;
- EXPECT_EQUAL(mutate::on_summary::Attribute::lookup(p), "");
+ EXPECT_EQ(mutate::on_summary::Attribute::lookup(p), "");
p.add("vespa.mutate.on_summary.attribute", "foobar");
- EXPECT_EQUAL(mutate::on_summary::Attribute::lookup(p), "foobar");
+ EXPECT_EQ(mutate::on_summary::Attribute::lookup(p), "foobar");
}
{
- EXPECT_EQUAL(mutate::on_summary::Operation::NAME, vespalib::string("vespa.mutate.on_summary.operation"));
- EXPECT_EQUAL(mutate::on_summary::Operation::DEFAULT_VALUE, "");
+ EXPECT_EQ(mutate::on_summary::Operation::NAME, vespalib::string("vespa.mutate.on_summary.operation"));
+ EXPECT_EQ(mutate::on_summary::Operation::DEFAULT_VALUE, "");
Properties p;
- EXPECT_EQUAL(mutate::on_summary::Operation::lookup(p), "");
+ EXPECT_EQ(mutate::on_summary::Operation::lookup(p), "");
p.add("vespa.mutate.on_summary.operation", "+=1");
- EXPECT_EQUAL(mutate::on_summary::Operation::lookup(p), "+=1");
+ EXPECT_EQ(mutate::on_summary::Operation::lookup(p), "+=1");
}
{
- EXPECT_EQUAL(execute::onmatch::Attribute::NAME, vespalib::string("vespa.execute.onmatch.attribute"));
- EXPECT_EQUAL(execute::onmatch::Attribute::DEFAULT_VALUE, "");
+ EXPECT_EQ(execute::onmatch::Attribute::NAME, vespalib::string("vespa.execute.onmatch.attribute"));
+ EXPECT_EQ(execute::onmatch::Attribute::DEFAULT_VALUE, "");
Properties p;
- EXPECT_EQUAL(execute::onmatch::Attribute::lookup(p), "");
+ EXPECT_EQ(execute::onmatch::Attribute::lookup(p), "");
p.add("vespa.execute.onmatch.attribute", "foobar");
- EXPECT_EQUAL(execute::onmatch::Attribute::lookup(p), "foobar");
+ EXPECT_EQ(execute::onmatch::Attribute::lookup(p), "foobar");
}
{
- EXPECT_EQUAL(execute::onmatch::Operation::NAME, vespalib::string("vespa.execute.onmatch.operation"));
- EXPECT_EQUAL(execute::onmatch::Operation::DEFAULT_VALUE, "");
+ EXPECT_EQ(execute::onmatch::Operation::NAME, vespalib::string("vespa.execute.onmatch.operation"));
+ EXPECT_EQ(execute::onmatch::Operation::DEFAULT_VALUE, "");
Properties p;
- EXPECT_EQUAL(execute::onmatch::Operation::lookup(p), "");
+ EXPECT_EQ(execute::onmatch::Operation::lookup(p), "");
p.add("vespa.execute.onmatch.operation", "++");
- EXPECT_EQUAL(execute::onmatch::Operation::lookup(p), "++");
+ EXPECT_EQ(execute::onmatch::Operation::lookup(p), "++");
}
{
- EXPECT_EQUAL(execute::onrerank::Attribute::NAME, vespalib::string("vespa.execute.onrerank.attribute"));
- EXPECT_EQUAL(execute::onrerank::Attribute::DEFAULT_VALUE, "");
+ EXPECT_EQ(execute::onrerank::Attribute::NAME, vespalib::string("vespa.execute.onrerank.attribute"));
+ EXPECT_EQ(execute::onrerank::Attribute::DEFAULT_VALUE, "");
Properties p;
- EXPECT_EQUAL(execute::onrerank::Attribute::lookup(p), "");
+ EXPECT_EQ(execute::onrerank::Attribute::lookup(p), "");
p.add("vespa.execute.onrerank.attribute", "foobar");
- EXPECT_EQUAL(execute::onrerank::Attribute::lookup(p), "foobar");
+ EXPECT_EQ(execute::onrerank::Attribute::lookup(p), "foobar");
}
{
- EXPECT_EQUAL(execute::onrerank::Operation::NAME, vespalib::string("vespa.execute.onrerank.operation"));
- EXPECT_EQUAL(execute::onrerank::Operation::DEFAULT_VALUE, "");
+ EXPECT_EQ(execute::onrerank::Operation::NAME, vespalib::string("vespa.execute.onrerank.operation"));
+ EXPECT_EQ(execute::onrerank::Operation::DEFAULT_VALUE, "");
Properties p;
- EXPECT_EQUAL(execute::onrerank::Operation::lookup(p), "");
+ EXPECT_EQ(execute::onrerank::Operation::lookup(p), "");
p.add("vespa.execute.onrerank.operation", "++");
- EXPECT_EQUAL(execute::onrerank::Operation::lookup(p), "++");
+ EXPECT_EQ(execute::onrerank::Operation::lookup(p), "++");
}
{
- EXPECT_EQUAL(execute::onsummary::Attribute::NAME, vespalib::string("vespa.execute.onsummary.attribute"));
- EXPECT_EQUAL(execute::onsummary::Attribute::DEFAULT_VALUE, "");
+ EXPECT_EQ(execute::onsummary::Attribute::NAME, vespalib::string("vespa.execute.onsummary.attribute"));
+ EXPECT_EQ(execute::onsummary::Attribute::DEFAULT_VALUE, "");
Properties p;
- EXPECT_EQUAL(execute::onsummary::Attribute::lookup(p), "");
+ EXPECT_EQ(execute::onsummary::Attribute::lookup(p), "");
p.add("vespa.execute.onsummary.attribute", "foobar");
- EXPECT_EQUAL(execute::onsummary::Attribute::lookup(p), "foobar");
+ EXPECT_EQ(execute::onsummary::Attribute::lookup(p), "foobar");
}
{
- EXPECT_EQUAL(execute::onsummary::Operation::NAME, vespalib::string("vespa.execute.onsummary.operation"));
- EXPECT_EQUAL(execute::onsummary::Operation::DEFAULT_VALUE, "");
+ EXPECT_EQ(execute::onsummary::Operation::NAME, vespalib::string("vespa.execute.onsummary.operation"));
+ EXPECT_EQ(execute::onsummary::Operation::DEFAULT_VALUE, "");
Properties p;
- EXPECT_EQUAL(execute::onsummary::Operation::lookup(p), "");
+ EXPECT_EQ(execute::onsummary::Operation::lookup(p), "");
p.add("vespa.execute.onsummary.operation", "++");
- EXPECT_EQUAL(execute::onsummary::Operation::lookup(p), "++");
+ EXPECT_EQ(execute::onsummary::Operation::lookup(p), "++");
}
{
- EXPECT_EQUAL(softtimeout::Enabled::NAME, vespalib::string("vespa.softtimeout.enable"));
+ EXPECT_EQ(softtimeout::Enabled::NAME, vespalib::string("vespa.softtimeout.enable"));
EXPECT_TRUE(softtimeout::Enabled::DEFAULT_VALUE);
Properties p;
p.add(softtimeout::Enabled::NAME, "false");
EXPECT_FALSE(softtimeout::Enabled::lookup(p));
}
{
- EXPECT_EQUAL(softtimeout::Factor::NAME, vespalib::string("vespa.softtimeout.factor"));
- EXPECT_EQUAL(0.5, softtimeout::Factor::DEFAULT_VALUE);
+ EXPECT_EQ(softtimeout::Factor::NAME, vespalib::string("vespa.softtimeout.factor"));
+ EXPECT_EQ(0.5, softtimeout::Factor::DEFAULT_VALUE);
Properties p;
p.add(softtimeout::Factor::NAME, "0.33");
- EXPECT_EQUAL(0.33, softtimeout::Factor::lookup(p));
+ EXPECT_EQ(0.33, softtimeout::Factor::lookup(p));
}
{
- EXPECT_EQUAL(softtimeout::TailCost::NAME, vespalib::string("vespa.softtimeout.tailcost"));
- EXPECT_EQUAL(0.1, softtimeout::TailCost::DEFAULT_VALUE);
+ EXPECT_EQ(softtimeout::TailCost::NAME, vespalib::string("vespa.softtimeout.tailcost"));
+ EXPECT_EQ(0.1, softtimeout::TailCost::DEFAULT_VALUE);
Properties p;
p.add(softtimeout::TailCost::NAME, "0.17");
- EXPECT_EQUAL(0.17, softtimeout::TailCost::lookup(p));
+ EXPECT_EQ(0.17, softtimeout::TailCost::lookup(p));
}
}
}
-TEST("test attribute type properties")
+TEST(PropertiesTest, test_attribute_type_properties)
{
Properties p;
p.add("vespa.type.attribute.foo", "tensor(x[10])");
- EXPECT_EQUAL("tensor(x[10])", type::Attribute::lookup(p, "foo"));
- EXPECT_EQUAL("", type::Attribute::lookup(p, "bar"));
+ EXPECT_EQ("tensor(x[10])", type::Attribute::lookup(p, "foo"));
+ EXPECT_EQ("", type::Attribute::lookup(p, "bar"));
}
-TEST("test query feature type properties")
+TEST(PropertiesTest, test_query_feature_type_properties)
{
Properties p;
p.add("vespa.type.query.foo", "tensor(x[10])");
- EXPECT_EQUAL("tensor(x[10])", type::QueryFeature::lookup(p, "foo"));
- EXPECT_EQUAL("", type::QueryFeature::lookup(p, "bar"));
+ EXPECT_EQ("tensor(x[10])", type::QueryFeature::lookup(p, "foo"));
+ EXPECT_EQ("", type::QueryFeature::lookup(p, "bar"));
}
-TEST("test integer lookup")
+TEST(PropertiesTest, test_integer_lookup)
{
- EXPECT_EQUAL(matching::NumThreadsPerSearch::NAME, vespalib::string("vespa.matching.numthreadspersearch"));
- EXPECT_EQUAL(matching::NumThreadsPerSearch::DEFAULT_VALUE, std::numeric_limits<uint32_t>::max());
+ EXPECT_EQ(matching::NumThreadsPerSearch::NAME, vespalib::string("vespa.matching.numthreadspersearch"));
+ EXPECT_EQ(matching::NumThreadsPerSearch::DEFAULT_VALUE, std::numeric_limits<uint32_t>::max());
{
Properties p;
p.add("vespa.matching.numthreadspersearch", "50");
- EXPECT_EQUAL(matching::NumThreadsPerSearch::lookup(p), 50u);
+ EXPECT_EQ(matching::NumThreadsPerSearch::lookup(p), 50u);
}
{
Properties p;
p.add("vespa.matching.numthreadspersearch", "50 ");
- EXPECT_EQUAL(matching::NumThreadsPerSearch::lookup(p), 50u);
+ EXPECT_EQ(matching::NumThreadsPerSearch::lookup(p), 50u);
}
{
Properties p;
p.add("vespa.matching.numthreadspersearch", " 50");
- EXPECT_EQUAL(matching::NumThreadsPerSearch::lookup(p), 50u);
+ EXPECT_EQ(matching::NumThreadsPerSearch::lookup(p), 50u);
}
{
Properties p;
p.add("vespa.matching.numthreadspersearch", " ");
- EXPECT_EQUAL(matching::NumThreadsPerSearch::lookup(p), matching::NumThreadsPerSearch::DEFAULT_VALUE);
+ EXPECT_EQ(matching::NumThreadsPerSearch::lookup(p), matching::NumThreadsPerSearch::DEFAULT_VALUE);
}
{
Properties p;
p.add("vespa.matching.numthreadspersearch", "50x");
- EXPECT_EQUAL(matching::NumThreadsPerSearch::lookup(p), 50u);
+ EXPECT_EQ(matching::NumThreadsPerSearch::lookup(p), 50u);
}
{
Properties p;
p.add("vespa.matching.numthreadspersearch", "x");
- EXPECT_EQUAL(matching::NumThreadsPerSearch::lookup(p), matching::NumThreadsPerSearch::DEFAULT_VALUE);
+ EXPECT_EQ(matching::NumThreadsPerSearch::lookup(p), matching::NumThreadsPerSearch::DEFAULT_VALUE);
}
}
+TEST(PropertiesTest, second_phase_rank_score_drop_limit)
+{
+ vespalib::stringref name = hitcollector::SecondPhaseRankScoreDropLimit::NAME;
+ EXPECT_EQ(vespalib::string("vespa.hitcollector.secondphase.rankscoredroplimit"), name);
+ Properties p;
+ EXPECT_EQ(std::optional<search::feature_t>(), hitcollector::SecondPhaseRankScoreDropLimit::lookup(p));
+ EXPECT_EQ(std::optional<search::feature_t>(4.0), hitcollector::SecondPhaseRankScoreDropLimit::lookup(p, 4.0));
+ p.add(name, "-123456789.12345");
+ EXPECT_EQ(std::optional<search::feature_t>(-123456789.12345), hitcollector::SecondPhaseRankScoreDropLimit::lookup(p));
+ EXPECT_EQ(std::optional<search::feature_t>(-123456789.12345), hitcollector::SecondPhaseRankScoreDropLimit::lookup(p, 4.0));
+ p.clear().add(name, "123456789.12345");
+ EXPECT_EQ(std::optional<search::feature_t>(123456789.12345), hitcollector::SecondPhaseRankScoreDropLimit::lookup(p));
+ EXPECT_EQ(std::optional<search::feature_t>(123456789.12345), hitcollector::SecondPhaseRankScoreDropLimit::lookup(p, 4.0));
+}
-TEST_MAIN() { TEST_RUN_ALL(); }
+GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/searchlib/src/tests/fef/table/CMakeLists.txt b/searchlib/src/tests/fef/table/CMakeLists.txt
index 6cc6856e0ce..2353fd50c95 100644
--- a/searchlib/src/tests/fef/table/CMakeLists.txt
+++ b/searchlib/src/tests/fef/table/CMakeLists.txt
@@ -4,5 +4,6 @@ vespa_add_executable(searchlib_table_test_app TEST
table_test.cpp
DEPENDS
searchlib
+ GTest::gtest
)
vespa_add_test(NAME searchlib_table_test_app COMMAND searchlib_table_test_app)
diff --git a/searchlib/src/tests/fef/table/table_test.cpp b/searchlib/src/tests/fef/table/table_test.cpp
index b0a47a8bdbc..9c15274c093 100644
--- a/searchlib/src/tests/fef/table/table_test.cpp
+++ b/searchlib/src/tests/fef/table/table_test.cpp
@@ -1,18 +1,21 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/vespalib/testkit/testapp.h>
#include <vespa/searchlib/fef/filetablefactory.h>
#include <vespa/searchlib/fef/functiontablefactory.h>
#include <vespa/searchlib/fef/tablemanager.h>
+#include <vespa/vespalib/gtest/gtest.h>
+#include <vespa/vespalib/testkit/test_path.h>
#include <fstream>
#include <iostream>
-namespace search {
-namespace fef {
+namespace search::fef {
-class TableTest : public vespalib::TestApp
+class TableTest : public ::testing::Test
{
-private:
+protected:
+ const std::string _tables1Dir;
+ const std::string _tables2Dir;
+
bool assertTable(const Table & act, const Table & exp);
bool assertCreateTable(const ITableFactory & tf, const vespalib::string & name, const Table & exp);
void testTable();
@@ -20,29 +23,32 @@ private:
void testFunctionTableFactory();
void testTableManager();
- const std::string _tables1Dir;
- const std::string _tables2Dir;
-public:
TableTest();
- ~TableTest();
- int Main() override;
+ ~TableTest() override;
};
-TableTest::TableTest() :
- vespalib::TestApp(),
- _tables1Dir(TEST_PATH("tables1")),
- _tables2Dir(TEST_PATH("tables2"))
+TableTest::TableTest()
+ : ::testing::Test(),
+ _tables1Dir(TEST_PATH("tables1")),
+ _tables2Dir(TEST_PATH("tables2"))
{
}
-TableTest::~TableTest() {}
+TableTest::~TableTest() = default;
bool
TableTest::assertTable(const Table & act, const Table & exp)
{
- if (!EXPECT_EQUAL(act.size(), exp.size())) return false;
+ bool failed = false;
+ EXPECT_EQ(act.size(), exp.size()) << (failed = true, "");
+ if (failed) {
+ return false;
+ }
for (size_t i = 0; i < act.size(); ++i) {
- if (!EXPECT_APPROX(act[i], exp[i], 0.01)) return false;
+ EXPECT_NEAR(act[i], exp[i], 0.01) << (failed = true, "");
+ if (failed) {
+ return false;
+ }
}
return true;
}
@@ -51,33 +57,35 @@ bool
TableTest::assertCreateTable(const ITableFactory & tf, const vespalib::string & name, const Table & exp)
{
Table::SP t = tf.createTable(name);
- if (!EXPECT_TRUE(t.get() != NULL)) return false;
+ bool failed = false;
+ EXPECT_TRUE(t.get() != nullptr) << (failed = true, "");
+ if (failed) {
+ return false;
+ }
return assertTable(*t, exp);
}
-void
-TableTest::testTable()
+TEST_F(TableTest, table)
{
Table t;
- EXPECT_EQUAL(t.size(), 0u);
- EXPECT_EQUAL(t.max(), -std::numeric_limits<double>::max());
+ EXPECT_EQ(t.size(), 0u);
+ EXPECT_EQ(t.max(), -std::numeric_limits<double>::max());
t.add(1).add(2);
- EXPECT_EQUAL(t.size(), 2u);
- EXPECT_EQUAL(t.max(), 2);
- EXPECT_EQUAL(t[0], 1);
- EXPECT_EQUAL(t[1], 2);
+ EXPECT_EQ(t.size(), 2u);
+ EXPECT_EQ(t.max(), 2);
+ EXPECT_EQ(t[0], 1);
+ EXPECT_EQ(t[1], 2);
t.add(10);
- EXPECT_EQUAL(t.size(), 3u);
- EXPECT_EQUAL(t.max(), 10);
- EXPECT_EQUAL(t[2], 10);
+ EXPECT_EQ(t.size(), 3u);
+ EXPECT_EQ(t.max(), 10);
+ EXPECT_EQ(t[2], 10);
t.add(5);
- EXPECT_EQUAL(t.size(), 4u);
- EXPECT_EQUAL(t.max(), 10);
- EXPECT_EQUAL(t[3], 5);
+ EXPECT_EQ(t.size(), 4u);
+ EXPECT_EQ(t.max(), 10);
+ EXPECT_EQ(t[3], 5);
}
-void
-TableTest::testFileTableFactory()
+TEST_F(TableTest, file_table_factory)
{
{
FileTableFactory ftf(_tables1Dir);
@@ -90,8 +98,7 @@ TableTest::testFileTableFactory()
}
}
-void
-TableTest::testFunctionTableFactory()
+TEST_F(TableTest, function_table_factory)
{
FunctionTableFactory ftf(2);
EXPECT_TRUE(assertCreateTable(ftf, "expdecay(400,12)",
@@ -117,8 +124,7 @@ TableTest::testFunctionTableFactory()
EXPECT_TRUE(ftf.createTable("none)(").get() == NULL);
}
-void
-TableTest::testTableManager()
+TEST_F(TableTest, table_manager)
{
{
TableManager tm;
@@ -148,20 +154,6 @@ TableTest::testTableManager()
}
}
-int
-TableTest::Main()
-{
- TEST_INIT("table_test");
-
- testTable();
- testFileTableFactory();
- testFunctionTableFactory();
- testTableManager();
-
- TEST_DONE();
-}
-
-}
}
-TEST_APPHOOK(search::fef::TableTest);
+GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/searchlib/src/tests/hitcollector/CMakeLists.txt b/searchlib/src/tests/hitcollector/CMakeLists.txt
index 5cedbcbd7e6..cc62dd82af4 100644
--- a/searchlib/src/tests/hitcollector/CMakeLists.txt
+++ b/searchlib/src/tests/hitcollector/CMakeLists.txt
@@ -4,6 +4,7 @@ vespa_add_executable(searchlib_hitcollector_test_app TEST
hitcollector_test.cpp
DEPENDS
searchlib
+ GTest::gtest
)
vespa_add_test(NAME searchlib_hitcollector_test_app COMMAND searchlib_hitcollector_test_app)
vespa_add_executable(searchlib_sorted_hit_sequence_test_app TEST
@@ -11,5 +12,6 @@ vespa_add_executable(searchlib_sorted_hit_sequence_test_app TEST
sorted_hit_sequence_test.cpp
DEPENDS
searchlib
+ GTest::gtest
)
vespa_add_test(NAME searchlib_sorted_hit_sequence_test_app COMMAND searchlib_sorted_hit_sequence_test_app)
diff --git a/searchlib/src/tests/hitcollector/hitcollector_test.cpp b/searchlib/src/tests/hitcollector/hitcollector_test.cpp
index e6e38181412..784afea7801 100644
--- a/searchlib/src/tests/hitcollector/hitcollector_test.cpp
+++ b/searchlib/src/tests/hitcollector/hitcollector_test.cpp
@@ -1,9 +1,9 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/vespalib/testkit/testapp.h>
#include <vespa/searchlib/common/bitvector.h>
#include <vespa/searchlib/fef/fef.h>
#include <vespa/searchlib/queryeval/hitcollector.h>
+#include <vespa/vespalib/gtest/gtest.h>
#include <vespa/log/log.h>
LOG_SETUP("hitcollector_test");
@@ -13,6 +13,8 @@ using namespace search::fef;
using namespace search::queryeval;
using ScoreMap = std::map<uint32_t, feature_t>;
+using DocidVector = std::vector<uint32_t>;
+using RankedHitVector = std::vector<RankedHit>;
using Ranges = std::pair<Scores, Scores>;
@@ -67,11 +69,11 @@ void checkResult(const ResultSet & rs, const std::vector<RankedHit> & exp)
if ( ! exp.empty()) {
const RankedHit * rh = rs.getArray();
ASSERT_TRUE(rh != nullptr);
- ASSERT_EQUAL(rs.getArrayUsed(), exp.size());
+ ASSERT_EQ(rs.getArrayUsed(), exp.size());
for (uint32_t i = 0; i < exp.size(); ++i) {
- EXPECT_EQUAL(rh[i].getDocId(), exp[i].getDocId());
- EXPECT_EQUAL(rh[i].getRank() + 1.0, exp[i].getRank() + 1.0);
+ EXPECT_EQ(rh[i].getDocId(), exp[i].getDocId());
+ EXPECT_DOUBLE_EQ(rh[i].getRank() + 64.0, exp[i].getRank() + 64.0);
}
} else {
ASSERT_TRUE(rs.getArray() == nullptr);
@@ -93,21 +95,24 @@ void checkResult(ResultSet & rs, BitVector * exp)
}
}
-void testAddHit(uint32_t numDocs, uint32_t maxHitsSize)
+void testAddHit(uint32_t numDocs, uint32_t maxHitsSize, const vespalib::string& label)
{
+ SCOPED_TRACE(label);
LOG(info, "testAddHit: no hits");
- { // no hits
+ {
+ SCOPED_TRACE("no hits");
HitCollector hc(numDocs, maxHitsSize);
std::vector<RankedHit> expRh;
std::unique_ptr<ResultSet> rs = hc.getResultSet();
- TEST_DO(checkResult(*rs, expRh));
- TEST_DO(checkResult(*rs, nullptr));
+ checkResult(*rs, expRh);
+ checkResult(*rs, nullptr);
}
LOG(info, "testAddHit: only ranked hits");
- { // only ranked hits
+ {
+ SCOPED_TRACE("only ranked hits");
HitCollector hc(numDocs, maxHitsSize);
std::vector<RankedHit> expRh;
@@ -121,12 +126,13 @@ void testAddHit(uint32_t numDocs, uint32_t maxHitsSize)
}
std::unique_ptr<ResultSet> rs = hc.getResultSet();
- TEST_DO(checkResult(*rs, expRh));
- TEST_DO(checkResult(*rs, nullptr));
+ checkResult(*rs, expRh);
+ checkResult(*rs, nullptr);
}
LOG(info, "testAddHit: both ranked hits and bit vector hits");
- { // both ranked hits and bit vector hits
+ {
+ SCOPED_TRACE("both ranked hits and bitvector hits");
HitCollector hc(numDocs, maxHitsSize);
std::vector<RankedHit> expRh;
BitVector::UP expBv(BitVector::create(numDocs));
@@ -144,14 +150,15 @@ void testAddHit(uint32_t numDocs, uint32_t maxHitsSize)
}
std::unique_ptr<ResultSet> rs = hc.getResultSet();
- TEST_DO(checkResult(*rs, expRh));
- TEST_DO(checkResult(*rs, expBv.get()));
+ checkResult(*rs, expRh);
+ checkResult(*rs, expBv.get());
}
}
-TEST("testAddHit") {
- TEST_DO(testAddHit(30, 10));
- TEST_DO(testAddHit(400, 10)); // 400/32 = 12 which is bigger than 10.
+TEST(HitCollectorTest, testAddHit)
+{
+ testAddHit(30, 10, "numDocs==30");
+ testAddHit(400, 10, "numDocs==400"); // 400/32 = 12 which is bigger than 10.
}
struct Fixture {
@@ -197,14 +204,17 @@ struct DescendingScoreFixture : Fixture {
DescendingScoreFixture::~DescendingScoreFixture() = default;
-TEST_F("testReRank - empty", Fixture) {
- EXPECT_EQUAL(0u, f.reRank());
+TEST(HitCollectorTest, rerank_empty)
+{
+ Fixture f;
+ EXPECT_EQ(0u, f.reRank());
}
-TEST_F("testReRank - ascending", AscendingScoreFixture)
+TEST(HitCollectorTest, rerank_ascending)
{
+ AscendingScoreFixture f;
f.addHits();
- EXPECT_EQUAL(5u, f.reRank());
+ EXPECT_EQ(5u, f.reRank());
std::vector<RankedHit> expRh;
for (uint32_t i = 10; i < 20; ++i) { // 10 last are the best
@@ -213,17 +223,18 @@ TEST_F("testReRank - ascending", AscendingScoreFixture)
expRh.back()._rankValue = i + 200; // after reranking
}
}
- EXPECT_EQUAL(expRh.size(), 10u);
+ EXPECT_EQ(expRh.size(), 10u);
std::unique_ptr<ResultSet> rs = f.hc.getResultSet();
- TEST_DO(checkResult(*rs, expRh));
- TEST_DO(checkResult(*rs, f.expBv.get()));
+ checkResult(*rs, expRh);
+ checkResult(*rs, f.expBv.get());
}
-TEST_F("testReRank - descending", DescendingScoreFixture)
+TEST(HitCollectorTest, rerank_descending)
{
+ DescendingScoreFixture f;
f.addHits();
- EXPECT_EQUAL(5u, f.reRank());
+ EXPECT_EQ(5u, f.reRank());
std::vector<RankedHit> expRh;
for (uint32_t i = 0; i < 10; ++i) { // 10 first are the best
@@ -232,17 +243,18 @@ TEST_F("testReRank - descending", DescendingScoreFixture)
expRh.back()._rankValue = i + 200; // after reranking
}
}
- EXPECT_EQUAL(expRh.size(), 10u);
+ EXPECT_EQ(expRh.size(), 10u);
std::unique_ptr<ResultSet> rs = f.hc.getResultSet();
- TEST_DO(checkResult(*rs, expRh));
- TEST_DO(checkResult(*rs, f.expBv.get()));
+ checkResult(*rs, expRh);
+ checkResult(*rs, f.expBv.get());
}
-TEST_F("testReRank - partial", AscendingScoreFixture)
+TEST(HitCollectorTest, rerank_partial)
{
+ AscendingScoreFixture f;
f.addHits();
- EXPECT_EQUAL(3u, f.reRank(3));
+ EXPECT_EQ(3u, f.reRank(3));
std::vector<RankedHit> expRh;
for (uint32_t i = 10; i < 20; ++i) { // 10 last are the best
@@ -251,36 +263,39 @@ TEST_F("testReRank - partial", AscendingScoreFixture)
expRh.back()._rankValue = i + 200; // after reranking
}
}
- EXPECT_EQUAL(expRh.size(), 10u);
+ EXPECT_EQ(expRh.size(), 10u);
std::unique_ptr<ResultSet> rs = f.hc.getResultSet();
- TEST_DO(checkResult(*rs, expRh));
- TEST_DO(checkResult(*rs, f.expBv.get()));
+ checkResult(*rs, expRh);
+ checkResult(*rs, f.expBv.get());
}
-TEST_F("require that hits for 2nd phase candidates can be retrieved", DescendingScoreFixture)
+TEST(HitCollectorTest, require_that_hits_for_2nd_phase_candidates_can_be_retrieved)
{
+ DescendingScoreFixture f;
f.addHits();
std::vector<HitCollector::Hit> scores = extract(f.hc.getSortedHitSequence(5));
- ASSERT_EQUAL(5u, scores.size());
- EXPECT_EQUAL(100, scores[0].second);
- EXPECT_EQUAL(99, scores[1].second);
- EXPECT_EQUAL(98, scores[2].second);
- EXPECT_EQUAL(97, scores[3].second);
- EXPECT_EQUAL(96, scores[4].second);
+ ASSERT_EQ(5u, scores.size());
+ EXPECT_EQ(100, scores[0].second);
+ EXPECT_EQ(99, scores[1].second);
+ EXPECT_EQ(98, scores[2].second);
+ EXPECT_EQ(97, scores[3].second);
+ EXPECT_EQ(96, scores[4].second);
}
-TEST("require that score ranges can be read and set.") {
+TEST(HitCollectorTest, require_that_score_ranges_can_be_read_and_set)
+{
std::pair<Scores, Scores> ranges = std::make_pair(Scores(1.0, 2.0), Scores(3.0, 4.0));
HitCollector hc(20, 10);
hc.setRanges(ranges);
- EXPECT_EQUAL(ranges.first.low, hc.getRanges().first.low);
- EXPECT_EQUAL(ranges.first.high, hc.getRanges().first.high);
- EXPECT_EQUAL(ranges.second.low, hc.getRanges().second.low);
- EXPECT_EQUAL(ranges.second.high, hc.getRanges().second.high);
+ EXPECT_EQ(ranges.first.low, hc.getRanges().first.low);
+ EXPECT_EQ(ranges.first.high, hc.getRanges().first.high);
+ EXPECT_EQ(ranges.second.low, hc.getRanges().second.low);
+ EXPECT_EQ(ranges.second.high, hc.getRanges().second.high);
}
-TEST("testNoHitsToReRank") {
+TEST(HitCollectorTest, no_hits_to_rerank)
+{
uint32_t numDocs = 20;
uint32_t maxHitsSize = 10;
@@ -299,8 +314,8 @@ TEST("testNoHitsToReRank") {
}
std::unique_ptr<ResultSet> rs = hc.getResultSet();
- TEST_DO(checkResult(*rs, expRh));
- TEST_DO(checkResult(*rs, nullptr));
+ checkResult(*rs, expRh);
+ checkResult(*rs, nullptr);
}
}
@@ -317,14 +332,15 @@ void testScaling(const std::vector<feature_t> &initScores,
PredefinedScorer scorer(std::move(finalScores));
// perform second phase ranking
- EXPECT_EQUAL(2u, do_reRank(scorer, hc, 2));
+ EXPECT_EQ(2u, do_reRank(scorer, hc, 2));
// check results
std::unique_ptr<ResultSet> rs = hc.getResultSet();
- TEST_DO(checkResult(*rs, expected));
+ checkResult(*rs, expected);
}
-TEST("testScaling") {
+TEST(HitCollectorTest, scaling)
+{
std::vector<feature_t> initScores(5);
initScores[0] = 1000;
initScores[1] = 2000;
@@ -338,7 +354,8 @@ TEST("testScaling") {
exp[i]._docId = i;
}
- { // scale down and adjust down
+ {
+ SCOPED_TRACE("scale down and adjust down");
exp[0]._rankValue = 0; // scaled
exp[1]._rankValue = 100; // scaled
exp[2]._rankValue = 200; // scaled
@@ -350,9 +367,10 @@ TEST("testScaling") {
finalScores[3] = 300;
finalScores[4] = 400;
- TEST_DO(testScaling(initScores, std::move(finalScores), exp));
+ testScaling(initScores, std::move(finalScores), exp);
}
- { // scale down and adjust up
+ {
+ SCOPED_TRACE("scale down and adjust up");
exp[0]._rankValue = 200; // scaled
exp[1]._rankValue = 300; // scaled
exp[2]._rankValue = 400; // scaled
@@ -364,10 +382,10 @@ TEST("testScaling") {
finalScores[3] = 500;
finalScores[4] = 600;
- TEST_DO(testScaling(initScores, std::move(finalScores), exp));
+ testScaling(initScores, std::move(finalScores), exp);
}
- { // scale up and adjust down
-
+ {
+ SCOPED_TRACE("scale up and adjust down");
exp[0]._rankValue = -500; // scaled (-500)
exp[1]._rankValue = 750; // scaled
exp[2]._rankValue = 2000; // scaled
@@ -379,9 +397,10 @@ TEST("testScaling") {
finalScores[3] = 3250;
finalScores[4] = 4500;
- TEST_DO(testScaling(initScores, std::move(finalScores), exp));
+ testScaling(initScores, std::move(finalScores), exp);
}
- { // minimal scale (second phase range = 0 (4 - 4) -> 1)
+ {
+ SCOPED_TRACE("minimal scale (second phase range = 0 (4 - 4) -> 1)");
exp[0]._rankValue = 1; // scaled
exp[1]._rankValue = 2; // scaled
exp[2]._rankValue = 3; // scaled
@@ -393,9 +412,10 @@ TEST("testScaling") {
finalScores[3] = 4;
finalScores[4] = 4;
- TEST_DO(testScaling(initScores, std::move(finalScores), exp));
+ testScaling(initScores, std::move(finalScores), exp);
}
- { // minimal scale (first phase range = 0 (4000 - 4000) -> 1)
+ {
+ SCOPED_TRACE("minimal scale (first phase range = 0 (4000 - 4000) -> 1)");
std::vector<feature_t> is(initScores);
is[4] = 4000;
exp[0]._rankValue = -299600; // scaled
@@ -409,11 +429,12 @@ TEST("testScaling") {
finalScores[3] = 400;
finalScores[4] = 500;
- TEST_DO(testScaling(is, std::move(finalScores), exp));
+ testScaling(is, std::move(finalScores), exp);
}
}
-TEST("testOnlyBitVector") {
+TEST(HitCollectorTest, only_bitvector)
+{
uint32_t numDocs = 20;
LOG(info, "testOnlyBitVector: test it");
{
@@ -428,8 +449,8 @@ TEST("testOnlyBitVector") {
std::unique_ptr<ResultSet> rs = hc.getResultSet();
std::vector<RankedHit> expRh;
- TEST_DO(checkResult(*rs, expRh)); // no ranked hits
- TEST_DO(checkResult(*rs, expBv.get())); // only bit vector
+ checkResult(*rs, expRh); // no ranked hits
+ checkResult(*rs, expBv.get()); // only bit vector
}
}
@@ -443,9 +464,9 @@ struct MergeResultSetFixture {
{}
};
-TEST_F("require that result set is merged correctly with first phase ranking",
- MergeResultSetFixture)
+TEST(HitCollectorTest, require_that_result_set_is_merged_correctly_with_first_phase_ranking)
{
+ MergeResultSetFixture f;
std::vector<RankedHit> expRh;
for (uint32_t i = 0; i < f.numDocs; ++i) {
f.hc.addHit(i, i + 1000);
@@ -457,7 +478,7 @@ TEST_F("require that result set is merged correctly with first phase ranking",
expRh.back()._rankValue = (i < f.numDocs - f.maxHitsSize) ? default_rank_value : i + 1000;
}
std::unique_ptr<ResultSet> rs = f.hc.getResultSet();
- TEST_DO(checkResult(*rs, expRh));
+ checkResult(*rs, expRh);
}
void
@@ -474,9 +495,9 @@ addExpectedHitForMergeTest(const MergeResultSetFixture &f, std::vector<RankedHit
}
}
-TEST_F("require that result set is merged correctly with second phase ranking (document scorer)",
- MergeResultSetFixture)
+TEST(HitCollectorTest, require_that_result_set_is_merged_correctly_with_second_phase_ranking_using_document_scorer)
{
+ MergeResultSetFixture f;
// with second phase ranking that triggers rescoring / scaling
BasicScorer scorer(500); // second phase ranking setting score to docId + 500
std::vector<RankedHit> expRh;
@@ -484,12 +505,13 @@ TEST_F("require that result set is merged correctly with second phase ranking (d
f.hc.addHit(i, i + 1000);
addExpectedHitForMergeTest(f, expRh, i);
}
- EXPECT_EQUAL(f.maxHeapSize, do_reRank(scorer, f.hc, f.maxHeapSize));
+ EXPECT_EQ(f.maxHeapSize, do_reRank(scorer, f.hc, f.maxHeapSize));
std::unique_ptr<ResultSet> rs = f.hc.getResultSet();
- TEST_DO(checkResult(*rs, expRh));
+ checkResult(*rs, expRh);
}
-TEST("require that hits can be added out of order") {
+TEST(HitCollectorTest, require_that_hits_can_be_added_out_of_order)
+{
HitCollector hc(1000, 100);
std::vector<RankedHit> expRh;
// produce expected result in normal order
@@ -503,11 +525,12 @@ TEST("require that hits can be added out of order") {
hc.addHit(i, i + 100);
}
std::unique_ptr<ResultSet> rs = hc.getResultSet();
- TEST_DO(checkResult(*rs, expRh));
- TEST_DO(checkResult(*rs, nullptr));
+ checkResult(*rs, expRh);
+ checkResult(*rs, nullptr);
}
-TEST("require that hits can be added out of order when passing array limit") {
+TEST(HitCollectorTest, require_that_hits_can_be_added_out_of_order_when_passing_array_limit)
+{
HitCollector hc(10000, 100);
std::vector<RankedHit> expRh;
// produce expected result in normal order
@@ -525,11 +548,12 @@ TEST("require that hits can be added out of order when passing array limit") {
hc.addHit(i, i + 100);
}
std::unique_ptr<ResultSet> rs = hc.getResultSet();
- TEST_DO(checkResult(*rs, expRh));
- TEST_DO(checkResult(*rs, nullptr));
+ checkResult(*rs, expRh);
+ checkResult(*rs, nullptr);
}
-TEST("require that hits can be added out of order only after passing array limit") {
+TEST(HitCollectorTest, require_that_hits_can_be_added_out_of_order_only_after_passing_array_limit)
+{
HitCollector hc(10000, 100);
std::vector<RankedHit> expRh;
// produce expected result in normal order
@@ -548,8 +572,90 @@ TEST("require that hits can be added out of order only after passing array limit
hc.addHit(i, i + 100);
}
std::unique_ptr<ResultSet> rs = hc.getResultSet();
- TEST_DO(checkResult(*rs, expRh));
- TEST_DO(checkResult(*rs, nullptr));
+ checkResult(*rs, expRh);
+ checkResult(*rs, nullptr);
+}
+
+struct RankDropFixture {
+ uint32_t _docid_limit;
+ HitCollector _hc;
+ std::vector<uint32_t> _dropped;
+ RankDropFixture(uint32_t docid_limit, uint32_t max_hits_size)
+ : _docid_limit(docid_limit),
+ _hc(docid_limit, max_hits_size)
+ {
+ }
+ ~RankDropFixture();
+ void add(std::vector<RankedHit> hits) {
+ for (const auto& hit : hits) {
+ _hc.addHit(hit.getDocId(), hit.getRank());
+ }
+ }
+ void rerank(ScoreMap score_map, size_t count) {
+ PredefinedScorer scorer(score_map);
+ EXPECT_EQ(count, do_reRank(scorer, _hc, count));
+ }
+ std::unique_ptr<BitVector> make_bv(DocidVector docids) {
+ auto bv = BitVector::create(_docid_limit);
+ for (auto& docid : docids) {
+ bv->setBit(docid);
+ }
+ return bv;
+ }
+
+ void setup() {
+ // Initial 7 hits from first phase
+ add({{5, 1100},{10, 1200},{11, 1300},{12, 1400},{14, 500},{15, 900},{16,1000}});
+ // Rerank two best hits, calculate old and new ranges for reranked
+ // hits that will cause hits not reranked to later be rescored by
+ // dividing by 100.
+ rerank({{11,14},{12,13}}, 2);
+ }
+ void check_result(std::optional<double> rank_drop_limit, RankedHitVector exp_array,
+ std::unique_ptr<BitVector> exp_bv, DocidVector exp_dropped) {
+ auto rs = _hc.get_result_set(rank_drop_limit, &_dropped);
+ checkResult(*rs, exp_array);
+ checkResult(*rs, exp_bv.get());
+ EXPECT_EQ(exp_dropped, _dropped);
+ }
+};
+
+RankDropFixture::~RankDropFixture() = default;
+
+TEST(HitCollectorTest, require_that_second_phase_rank_drop_limit_is_enforced)
+{
+ // Track rank score for all 7 hits from first phase
+ RankDropFixture f(10000, 10);
+ f.setup();
+ f.check_result(9.0, {{5,11},{10,12},{11,14},{12,13},{16,10}},
+ {}, {14, 15});
+}
+
+TEST(HitCollectorTest, require_that_second_phase_rank_drop_limit_is_enforced_when_docid_vector_is_used)
+{
+ // Track rank score for 4 best hits from first phase, overflow to docid vector
+ RankDropFixture f(10000, 4);
+ f.setup();
+ f.check_result(13.0, {{11,14}},
+ {}, {5,10,12,14,15,16});
+}
+
+TEST(HitCollectorTest, require_that_bitvector_is_not_dropped_without_second_phase_rank_drop_limit)
+{
+ // Track rank score for 4 best hits from first phase, overflow to bitvector
+ RankDropFixture f(20, 4);
+ f.setup();
+ f.check_result(std::nullopt, {{5,11},{10,12},{11,14},{12,13}},
+ f.make_bv({5,10,11,12,14,15,16}), {});
+}
+
+TEST(HitCollectorTest, require_that_bitvector_is_dropped_with_second_phase_rank_drop_limit)
+{
+ // Track rank for 4 best hits from first phase, overflow to bitvector
+ RankDropFixture f(20, 4);
+ f.setup();
+ f.check_result(9.0, {{5,11},{10,12},{11,14},{12,13}},
+ {}, {14,15,16});
}
-TEST_MAIN() { TEST_RUN_ALL(); }
+GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/searchlib/src/tests/hitcollector/sorted_hit_sequence_test.cpp b/searchlib/src/tests/hitcollector/sorted_hit_sequence_test.cpp
index c1c3a550d9b..4eefa5b5dfa 100644
--- a/searchlib/src/tests/hitcollector/sorted_hit_sequence_test.cpp
+++ b/searchlib/src/tests/hitcollector/sorted_hit_sequence_test.cpp
@@ -1,7 +1,7 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/searchlib/queryeval/sorted_hit_sequence.h>
+#include <vespa/vespalib/gtest/gtest.h>
using search::queryeval::SortedHitSequence;
using Hits = std::vector<SortedHitSequence::Hit>;
@@ -10,20 +10,22 @@ using Refs = std::vector<SortedHitSequence::Ref>;
Hits hits({{1,10.0},{2,30.0},{3,20.0}});
Refs refs({1,2,0});
-TEST("require that empty hit sequence is empty") {
+TEST(SortedHitsSEquenceTest, require_that_empty_hit_sequence_is_empty)
+{
EXPECT_TRUE(!SortedHitSequence(nullptr, nullptr, 0).valid());
EXPECT_TRUE(!SortedHitSequence(&hits[0], &refs[0], 0).valid());
}
-TEST("require that sorted hit sequence can be iterated") {
+TEST(SortedHitsSEquenceTest, require_that_sorted_hit_sequence_can_be_iterated)
+{
SortedHitSequence seq(&hits[0], &refs[0], refs.size());
for (const auto &expect: Hits({{2,30.0},{3,20.0},{1,10.0}})) {
ASSERT_TRUE(seq.valid());
- EXPECT_EQUAL(expect.first, seq.get().first);
- EXPECT_EQUAL(expect.second, seq.get().second);
+ EXPECT_EQ(expect.first, seq.get().first);
+ EXPECT_EQ(expect.second, seq.get().second);
seq.next();
}
EXPECT_TRUE(!seq.valid());
}
-TEST_MAIN() { TEST_RUN_ALL(); }
+GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/searchlib/src/tests/nearsearch/CMakeLists.txt b/searchlib/src/tests/nearsearch/CMakeLists.txt
index 4f249380063..8d23b54963e 100644
--- a/searchlib/src/tests/nearsearch/CMakeLists.txt
+++ b/searchlib/src/tests/nearsearch/CMakeLists.txt
@@ -4,5 +4,6 @@ vespa_add_executable(searchlib_nearsearch_test_app TEST
nearsearch_test.cpp
DEPENDS
searchlib
+ GTest::gtest
)
vespa_add_test(NAME searchlib_nearsearch_test_app COMMAND searchlib_nearsearch_test_app)
diff --git a/searchlib/src/tests/nearsearch/nearsearch_test.cpp b/searchlib/src/tests/nearsearch/nearsearch_test.cpp
index 4011366c7a1..aa578108b6b 100644
--- a/searchlib/src/tests/nearsearch/nearsearch_test.cpp
+++ b/searchlib/src/tests/nearsearch/nearsearch_test.cpp
@@ -11,7 +11,7 @@ LOG_SETUP("nearsearch_test");
#include <vespa/searchlib/fef/matchdatalayout.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <set>
-#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/vespalib/gtest/gtest.h>
////////////////////////////////////////////////////////////////////////////////
//
@@ -108,28 +108,20 @@ MyQuery::~MyQuery() {}
//
////////////////////////////////////////////////////////////////////////////////
-class Test : public vespalib::TestApp {
-private:
- bool testNearSearch(MyQuery &query, uint32_t matchId);
+class NearSearchTest : public ::testing::Test {
+protected:
+ void testNearSearch(MyQuery &query, uint32_t matchId, const vespalib::string& label);
-public:
- int Main() override;
- void testBasicNear();
- void testRepeatedTerms();
+ NearSearchTest();
+ ~NearSearchTest() override;
};
-int
-Test::Main()
+NearSearchTest::NearSearchTest()
+ : ::testing::Test()
{
- TEST_INIT("nearsearch_test");
-
- testBasicNear(); TEST_FLUSH();
- testRepeatedTerms(); TEST_FLUSH();
-
- TEST_DONE();
}
-TEST_APPHOOK(Test);
+NearSearchTest::~NearSearchTest() = default;
////////////////////////////////////////////////////////////////////////////////
//
@@ -137,84 +129,89 @@ TEST_APPHOOK(Test);
//
////////////////////////////////////////////////////////////////////////////////
-void
-Test::testBasicNear()
+TEST_F(NearSearchTest, basic_near)
{
MyTerm foo(UIntList().add(69),
UIntList().add(6).add(11));
for (uint32_t i = 0; i <= 1; ++i) {
- TEST_STATE(vespalib::make_string("i = %u", i).c_str());
- TEST_DO(testNearSearch(MyQuery(false, i).addTerm(foo), 69));
- TEST_DO(testNearSearch(MyQuery(true, i).addTerm(foo), 69));
+ SCOPED_TRACE(vespalib::make_string("i = %u", i));
+ testNearSearch(MyQuery(false, i).addTerm(foo), 69, "near 1");
+ testNearSearch(MyQuery(true, i).addTerm(foo), 69, "onear 1");
}
MyTerm bar(UIntList().add(68).add(69).add(70),
UIntList().add(7).add(10));
- TEST_DO(testNearSearch(MyQuery(false, 0).addTerm(foo).addTerm(bar), 0));
- TEST_DO(testNearSearch(MyQuery(true, 0).addTerm(foo).addTerm(bar), 0));
+ testNearSearch(MyQuery(false, 0).addTerm(foo).addTerm(bar), 0, "near 2");
+ testNearSearch(MyQuery(true, 0).addTerm(foo).addTerm(bar), 0, "onear 2");
for (uint32_t i = 1; i <= 2; ++i) {
- TEST_DO(testNearSearch(MyQuery(false, i).addTerm(foo).addTerm(bar), 69));
- TEST_DO(testNearSearch(MyQuery(true, i).addTerm(foo).addTerm(bar), 69));
+ SCOPED_TRACE(vespalib::make_string("i = %u", i));
+ testNearSearch(MyQuery(false, i).addTerm(foo).addTerm(bar), 69, "near 3");
+ testNearSearch(MyQuery(true, i).addTerm(foo).addTerm(bar), 69, "onear 3");
}
MyTerm baz(UIntList().add(69).add(70).add(71),
UIntList().add(8).add(9));
for (uint32_t i = 0; i <= 1; ++i) {
- TEST_DO(testNearSearch(MyQuery(false, i).addTerm(foo).addTerm(bar).addTerm(baz), 0));
- TEST_DO(testNearSearch(MyQuery(false, i).addTerm(foo).addTerm(baz).addTerm(bar), 0));
- TEST_DO(testNearSearch(MyQuery(false, i).addTerm(bar).addTerm(baz).addTerm(foo), 0));
- TEST_DO(testNearSearch(MyQuery(false, i).addTerm(bar).addTerm(foo).addTerm(baz), 0));
- TEST_DO(testNearSearch(MyQuery(false, i).addTerm(baz).addTerm(foo).addTerm(bar), 0));
- TEST_DO(testNearSearch(MyQuery(false, i).addTerm(baz).addTerm(bar).addTerm(foo), 0));
- TEST_DO(testNearSearch(MyQuery(true, i).addTerm(foo).addTerm(bar).addTerm(baz), 0));
- TEST_DO(testNearSearch(MyQuery(true, i).addTerm(foo).addTerm(baz).addTerm(bar), 0));
- TEST_DO(testNearSearch(MyQuery(true, i).addTerm(bar).addTerm(baz).addTerm(foo), 0));
- TEST_DO(testNearSearch(MyQuery(true, i).addTerm(bar).addTerm(foo).addTerm(baz), 0));
- TEST_DO(testNearSearch(MyQuery(true, i).addTerm(baz).addTerm(foo).addTerm(bar), 0));
- TEST_DO(testNearSearch(MyQuery(true, i).addTerm(baz).addTerm(bar).addTerm(foo), 0));
+ SCOPED_TRACE(vespalib::make_string("i = %u", i));
+ testNearSearch(MyQuery(false, i).addTerm(foo).addTerm(bar).addTerm(baz), 0, "near 10");
+ testNearSearch(MyQuery(false, i).addTerm(foo).addTerm(baz).addTerm(bar), 0, "near 11");
+ testNearSearch(MyQuery(false, i).addTerm(bar).addTerm(baz).addTerm(foo), 0, "near 12");
+ testNearSearch(MyQuery(false, i).addTerm(bar).addTerm(foo).addTerm(baz), 0, "near 13");
+ testNearSearch(MyQuery(false, i).addTerm(baz).addTerm(foo).addTerm(bar), 0, "near 14");
+ testNearSearch(MyQuery(false, i).addTerm(baz).addTerm(bar).addTerm(foo), 0, "near 15");
+ testNearSearch(MyQuery(true, i).addTerm(foo).addTerm(bar).addTerm(baz), 0, "onear 10");
+ testNearSearch(MyQuery(true, i).addTerm(foo).addTerm(baz).addTerm(bar), 0, "onear 11");
+ testNearSearch(MyQuery(true, i).addTerm(bar).addTerm(baz).addTerm(foo), 0, "onear 12");
+ testNearSearch(MyQuery(true, i).addTerm(bar).addTerm(foo).addTerm(baz), 0, "onear 13");
+ testNearSearch(MyQuery(true, i).addTerm(baz).addTerm(foo).addTerm(bar), 0, "onear 14");
+ testNearSearch(MyQuery(true, i).addTerm(baz).addTerm(bar).addTerm(foo), 0, "onear 15");
}
for (uint32_t i = 2; i <= 3; ++i) {
- TEST_DO(testNearSearch(MyQuery(false, i).addTerm(foo).addTerm(bar).addTerm(baz), 69));
- TEST_DO(testNearSearch(MyQuery(false, i).addTerm(foo).addTerm(baz).addTerm(bar), 69));
- TEST_DO(testNearSearch(MyQuery(false, i).addTerm(bar).addTerm(baz).addTerm(foo), 69));
- TEST_DO(testNearSearch(MyQuery(false, i).addTerm(bar).addTerm(foo).addTerm(baz), 69));
- TEST_DO(testNearSearch(MyQuery(false, i).addTerm(baz).addTerm(foo).addTerm(bar), 69));
- TEST_DO(testNearSearch(MyQuery(false, i).addTerm(baz).addTerm(bar).addTerm(foo), 69));
- TEST_DO(testNearSearch(MyQuery(true, i).addTerm(foo).addTerm(bar).addTerm(baz), 69));
- TEST_DO(testNearSearch(MyQuery(true, i).addTerm(foo).addTerm(baz).addTerm(bar), 0));
- TEST_DO(testNearSearch(MyQuery(true, i).addTerm(bar).addTerm(baz).addTerm(foo), 0));
- TEST_DO(testNearSearch(MyQuery(true, i).addTerm(bar).addTerm(foo).addTerm(baz), 0));
- TEST_DO(testNearSearch(MyQuery(true, i).addTerm(baz).addTerm(foo).addTerm(bar), 0));
- TEST_DO(testNearSearch(MyQuery(true, i).addTerm(baz).addTerm(bar).addTerm(foo), 69));
+ SCOPED_TRACE(vespalib::make_string("i = %u", i));
+ testNearSearch(MyQuery(false, i).addTerm(foo).addTerm(bar).addTerm(baz), 69, "near 20");
+ testNearSearch(MyQuery(false, i).addTerm(foo).addTerm(baz).addTerm(bar), 69, "near 21");
+ testNearSearch(MyQuery(false, i).addTerm(bar).addTerm(baz).addTerm(foo), 69, "near 22");
+ testNearSearch(MyQuery(false, i).addTerm(bar).addTerm(foo).addTerm(baz), 69, "near 23");
+ testNearSearch(MyQuery(false, i).addTerm(baz).addTerm(foo).addTerm(bar), 69, "near 24");
+ testNearSearch(MyQuery(false, i).addTerm(baz).addTerm(bar).addTerm(foo), 69, "near 25");
+ testNearSearch(MyQuery(true, i).addTerm(foo).addTerm(bar).addTerm(baz), 69, "onear 20");
+ testNearSearch(MyQuery(true, i).addTerm(foo).addTerm(baz).addTerm(bar), 0, "onear 21");
+ testNearSearch(MyQuery(true, i).addTerm(bar).addTerm(baz).addTerm(foo), 0, "onear 22");
+ testNearSearch(MyQuery(true, i).addTerm(bar).addTerm(foo).addTerm(baz), 0, "onear 23");
+ testNearSearch(MyQuery(true, i).addTerm(baz).addTerm(foo).addTerm(bar), 0, "onear 24");
+ testNearSearch(MyQuery(true, i).addTerm(baz).addTerm(bar).addTerm(foo), 69, "onear 25");
}
}
-void
-Test::testRepeatedTerms()
+
+TEST_F(NearSearchTest, repeated_terms)
{
MyTerm foo(UIntList().add(69),
UIntList().add(1).add(2).add(3));
- TEST_DO(testNearSearch(MyQuery(false, 0).addTerm(foo).addTerm(foo), 69));
- TEST_DO(testNearSearch(MyQuery(true, 0).addTerm(foo).addTerm(foo), 0));
+ testNearSearch(MyQuery(false, 0).addTerm(foo).addTerm(foo), 69, "near 50");
+ testNearSearch(MyQuery(true, 0).addTerm(foo).addTerm(foo), 0, "onear 50");
for (uint32_t i = 1; i <= 2; ++i) {
- TEST_DO(testNearSearch(MyQuery(false, i).addTerm(foo).addTerm(foo), 69));
- TEST_DO(testNearSearch(MyQuery(true, i).addTerm(foo).addTerm(foo), 69));
+ SCOPED_TRACE(vespalib::make_string("i = %u", i));
+ testNearSearch(MyQuery(false, i).addTerm(foo).addTerm(foo), 69, "near 51");
+ testNearSearch(MyQuery(true, i).addTerm(foo).addTerm(foo), 69, "onear 51");
}
for (uint32_t i = 0; i <= 1; ++i) {
- TEST_DO(testNearSearch(MyQuery(false, i).addTerm(foo).addTerm(foo).addTerm(foo), 69));
- TEST_DO(testNearSearch(MyQuery(true, i).addTerm(foo).addTerm(foo).addTerm(foo), 0));
+ SCOPED_TRACE(vespalib::make_string("i = %u", i));
+ testNearSearch(MyQuery(false, i).addTerm(foo).addTerm(foo).addTerm(foo), 69, "near 52");
+ testNearSearch(MyQuery(true, i).addTerm(foo).addTerm(foo).addTerm(foo), 0, "onear 52");
}
for (uint32_t i = 2; i <= 3; ++i) {
- TEST_DO(testNearSearch(MyQuery(false, i).addTerm(foo).addTerm(foo).addTerm(foo), 69));
- TEST_DO(testNearSearch(MyQuery(true, i).addTerm(foo).addTerm(foo).addTerm(foo), 69));
+ SCOPED_TRACE(vespalib::make_string("i = %u", i));
+ testNearSearch(MyQuery(false, i).addTerm(foo).addTerm(foo).addTerm(foo), 69, "near 53");
+ testNearSearch(MyQuery(true, i).addTerm(foo).addTerm(foo).addTerm(foo), 69, "onear 53");
}
}
-bool
-Test::testNearSearch(MyQuery &query, uint32_t matchId)
+void
+NearSearchTest::testNearSearch(MyQuery &query, uint32_t matchId, const vespalib::string& label)
{
- LOG(info, "testNearSearch(%d)", matchId);
+ SCOPED_TRACE(vespalib::make_string("%s - %u", label.c_str(), matchId));
search::queryeval::IntermediateBlueprint *near_b = nullptr;
if (query.isOrdered()) {
near_b = new search::queryeval::ONearBlueprint(query.getWindow());
@@ -240,13 +237,14 @@ Test::testNearSearch(MyQuery &query, uint32_t matchId)
if (docId == matchId) {
foundMatch = true;
} else {
- LOG(info, "Document %d matched unexpectedly.", docId);
- return false;
+ FAIL() << "Document " << docId << " matched unexpectedly.";
}
}
if (matchId == 0) {
- return EXPECT_TRUE(!foundMatch);
+ EXPECT_TRUE(!foundMatch);
} else {
- return EXPECT_TRUE(foundMatch);
+ EXPECT_TRUE(foundMatch);
}
}
+
+GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/searchlib/src/tests/query/CMakeLists.txt b/searchlib/src/tests/query/CMakeLists.txt
index 0cb6c9413b0..39ef50b1d8c 100644
--- a/searchlib/src/tests/query/CMakeLists.txt
+++ b/searchlib/src/tests/query/CMakeLists.txt
@@ -18,6 +18,7 @@ vespa_add_executable(searchlib_templatetermvisitor_test_app TEST
templatetermvisitor_test.cpp
DEPENDS
searchlib
+ GTest::gtest
)
vespa_add_test(NAME searchlib_templatetermvisitor_test_app COMMAND searchlib_templatetermvisitor_test_app)
vespa_add_executable(searchlib_querybuilder_test_app TEST
diff --git a/searchlib/src/tests/query/templatetermvisitor_test.cpp b/searchlib/src/tests/query/templatetermvisitor_test.cpp
index b6dd6ceab8d..591aaffcbee 100644
--- a/searchlib/src/tests/query/templatetermvisitor_test.cpp
+++ b/searchlib/src/tests/query/templatetermvisitor_test.cpp
@@ -1,14 +1,11 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
// Unit tests for templatetermvisitor.
-#include <vespa/log/log.h>
-LOG_SETUP("templatetermvisitor_test");
-
#include <vespa/searchlib/query/tree/intermediatenodes.h>
#include <vespa/searchlib/query/tree/templatetermvisitor.h>
#include <vespa/searchlib/query/tree/simplequery.h>
#include <vespa/searchlib/query/tree/termnodes.h>
-#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/vespalib/gtest/gtest.h>
using namespace search::query;
@@ -16,23 +13,6 @@ namespace {
class MyVisitor;
-class Test : public vespalib::TestApp {
- void requireThatAllTermsCanBeVisited();
-
-public:
- int Main() override;
-};
-
-int
-Test::Main()
-{
- TEST_INIT("templatetermvisitor_test");
-
- TEST_DO(requireThatAllTermsCanBeVisited());
-
- TEST_DONE();
-}
-
class MyVisitor : public TemplateTermVisitor<MyVisitor, SimpleQueryNodeTypes>
{
public:
@@ -60,7 +40,8 @@ bool checkVisit() {
return checkVisit(new T(typename T::Type(), "field", 0, Weight(0)));
}
-void Test::requireThatAllTermsCanBeVisited() {
+TEST(TemplateTermVisitorTest, require_that_all_terms_can_be_visited)
+{
EXPECT_TRUE(checkVisit<SimpleNumberTerm>());
EXPECT_TRUE(checkVisit<SimpleLocationTerm>());
EXPECT_TRUE(checkVisit<SimplePrefixTerm>());
@@ -83,4 +64,4 @@ void Test::requireThatAllTermsCanBeVisited() {
} // namespace
-TEST_APPHOOK(Test);
+GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/searchlib/src/tests/queryeval/blueprint/CMakeLists.txt b/searchlib/src/tests/queryeval/blueprint/CMakeLists.txt
index e46ad1085e3..ef8d974151a 100644
--- a/searchlib/src/tests/queryeval/blueprint/CMakeLists.txt
+++ b/searchlib/src/tests/queryeval/blueprint/CMakeLists.txt
@@ -11,6 +11,7 @@ vespa_add_executable(searchlib_leaf_blueprints_test_app TEST
leaf_blueprints_test.cpp
DEPENDS
searchlib
+ GTest::gtest
)
vespa_add_test(NAME searchlib_leaf_blueprints_test_app COMMAND searchlib_leaf_blueprints_test_app || diff -u lhs.out rhs.out)
vespa_add_executable(searchlib_intermediate_blueprints_test_app TEST
diff --git a/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp b/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp
index 485410e0eba..f7745da174c 100644
--- a/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp
+++ b/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp
@@ -13,7 +13,7 @@
LOG_SETUP("blueprint_test");
using namespace search::queryeval;
-using namespace search::fef;
+using MatchData = search::fef::MatchData;
namespace {
@@ -44,9 +44,7 @@ public:
}
SearchIterator::UP
- createIntermediateSearch(MultiSearch::Children subSearches,
- MatchData &md) const override
- {
+ createIntermediateSearch(MultiSearch::Children subSearches, MatchData &md) const override {
return std::make_unique<MySearch>("or", std::move(subSearches), &md, strict());
}
SearchIteratorUP createFilterSearch(FilterConstraint constraint) const override {
@@ -63,9 +61,7 @@ class OtherOr : public OrBlueprint
private:
public:
SearchIterator::UP
- createIntermediateSearch(MultiSearch::Children subSearches,
- MatchData &md) const override
- {
+ createIntermediateSearch(MultiSearch::Children subSearches, MatchData &md) const override {
return std::make_unique<MySearch>("or", std::move(subSearches), &md, strict());
}
@@ -89,9 +85,7 @@ public:
}
SearchIterator::UP
- createIntermediateSearch(MultiSearch::Children subSearches,
- MatchData &md) const override
- {
+ createIntermediateSearch(MultiSearch::Children subSearches, MatchData &md) const override {
return std::make_unique<MySearch>("and", std::move(subSearches), &md, strict());
}
@@ -106,9 +100,7 @@ class OtherAnd : public AndBlueprint
private:
public:
SearchIterator::UP
- createIntermediateSearch(MultiSearch::Children subSearches,
- MatchData &md) const override
- {
+ createIntermediateSearch(MultiSearch::Children subSearches, MatchData &md) const override {
return std::make_unique<MySearch>("and", std::move(subSearches), &md, strict());
}
@@ -121,9 +113,7 @@ class OtherAndNot : public AndNotBlueprint
{
public:
SearchIterator::UP
- createIntermediateSearch(MultiSearch::Children subSearches,
- MatchData &md) const override
- {
+ createIntermediateSearch(MultiSearch::Children subSearches, MatchData &md) const override {
return std::make_unique<MySearch>("andnot", std::move(subSearches), &md, strict());
}
@@ -658,6 +648,7 @@ getExpectedBlueprint()
" strict_cost: 0\n"
" sourceId: 4294967295\n"
" docid_limit: 0\n"
+ " id: 0\n"
" strict: false\n"
" children: std::vector {\n"
" [0]: (anonymous namespace)::MyTerm {\n"
@@ -681,6 +672,7 @@ getExpectedBlueprint()
" strict_cost: 0\n"
" sourceId: 4294967295\n"
" docid_limit: 0\n"
+ " id: 0\n"
" strict: false\n"
" }\n"
" }\n"
@@ -714,6 +706,7 @@ getExpectedSlimeBlueprint() {
" strict_cost: 0.0,"
" sourceId: 4294967295,"
" docid_limit: 0,"
+ " id: 0,"
" strict: false,"
" children: {"
" '[type]': 'std::vector',"
@@ -742,6 +735,7 @@ getExpectedSlimeBlueprint() {
" strict_cost: 0.0,"
" sourceId: 4294967295,"
" docid_limit: 0,"
+ " id: 0,"
" strict: false"
" }"
" }"
@@ -852,6 +846,30 @@ TEST("self strict resolving during sort") {
}
}
+void check_ids(Blueprint &bp, const std::vector<uint32_t> &expect) {
+ std::vector<uint32_t> actual;
+ bp.each_node_post_order([&](auto &node){ actual.push_back(node.id()); });
+ ASSERT_EQUAL(actual.size(), expect.size());
+ for (size_t i = 0; i < actual.size(); ++i) {
+ EXPECT_EQUAL(actual[i], expect[i]);
+ }
+}
+
+TEST("blueprint node enumeration") {
+ auto a = std::make_unique<AndBlueprint>();
+ a->addChild(std::make_unique<MyLeaf>());
+ a->addChild(std::make_unique<MyLeaf>());
+ auto b = std::make_unique<AndBlueprint>();
+ b->addChild(std::make_unique<MyLeaf>());
+ b->addChild(std::make_unique<MyLeaf>());
+ auto root = std::make_unique<OrBlueprint>();
+ root->addChild(std::move(a));
+ root->addChild(std::move(b));
+ TEST_DO(check_ids(*root, {0,0,0,0,0,0,0}));
+ root->enumerate(1);
+ TEST_DO(check_ids(*root, {3,4,2,6,7,5,1}));
+}
+
TEST_MAIN() {
TEST_DEBUG("lhs.out", "rhs.out");
TEST_RUN_ALL();
diff --git a/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp b/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp
index bddc9f92111..490f221d1d8 100644
--- a/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp
+++ b/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp
@@ -27,8 +27,9 @@
LOG_SETUP("blueprint_test");
using namespace search::queryeval;
-using namespace search::fef;
using namespace search::query;
+using search::fef::MatchData;
+using search::queryeval::Blueprint;
using search::BitVector;
using BlueprintVector = std::vector<std::unique_ptr<Blueprint>>;
using vespalib::Slime;
@@ -575,7 +576,9 @@ void compare(const Blueprint &bp1, const Blueprint &bp2, bool expect_eq) {
bp1.asSlime(SlimeInserter(a));
bp2.asSlime(SlimeInserter(b));
if (expect_eq) {
- EXPECT_TRUE(vespalib::slime::are_equal(a.get(), b.get(), cmp_hook));
+ if(!EXPECT_TRUE(vespalib::slime::are_equal(a.get(), b.get(), cmp_hook))) {
+ fprintf(stderr, "a: %s\n\nb: %s\n\n", bp1.asString().c_str(), bp2.asString().c_str());
+ }
} else {
EXPECT_FALSE(vespalib::slime::are_equal(a.get(), b.get(), cmp_hook));
}
@@ -613,7 +616,6 @@ TEST_F("test SourceBlender below AND partial optimization", SourceBlenderTestFix
auto expect = std::make_unique<AndBlueprint>();
addLeafs(*expect, {1,2,3});
- expect->addChild(addLeafsWithSourceId(std::make_unique<SourceBlenderBlueprint>(f.selector_2), {{10, 1}, {20, 2}}));
auto blender = std::make_unique<SourceBlenderBlueprint>(f.selector_1);
blender->addChild(addLeafsWithSourceId(3, std::make_unique<AndBlueprint>(), {{30, 3}, {300, 3}}));
@@ -621,6 +623,8 @@ TEST_F("test SourceBlender below AND partial optimization", SourceBlenderTestFix
blender->addChild(addLeafsWithSourceId(1, std::make_unique<AndBlueprint>(), {{10, 1}, {100, 1}, {1000, 1}}));
expect->addChild(std::move(blender));
+ expect->addChild(addLeafsWithSourceId(std::make_unique<SourceBlenderBlueprint>(f.selector_2), {{10, 1}, {20, 2}}));
+
optimize_and_compare(std::move(top), std::move(expect));
}
@@ -1401,7 +1405,7 @@ TEST("cost for ANDNOT") {
TEST("cost for SB") {
InvalidSelector sel;
- verify_cost(make::SB(sel), 1.3, 1.3); // max
+ verify_cost(make::SB(sel), 1.3+1.0, 1.3+(1.0-0.8*0.7*0.5)); // max, non_strict+1.0, strict+est
}
TEST("cost for NEAR") {
diff --git a/searchlib/src/tests/queryeval/blueprint/leaf_blueprints_test.cpp b/searchlib/src/tests/queryeval/blueprint/leaf_blueprints_test.cpp
index cb5473babbd..ea7f3d8fdc9 100644
--- a/searchlib/src/tests/queryeval/blueprint/leaf_blueprints_test.cpp
+++ b/searchlib/src/tests/queryeval/blueprint/leaf_blueprints_test.cpp
@@ -1,33 +1,20 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/vespalib/testkit/testapp.h>
#include <vespa/searchlib/queryeval/blueprint.h>
#include <vespa/searchlib/queryeval/leaf_blueprints.h>
#include <vespa/searchlib/fef/matchdata.h>
-
-#include <vespa/log/log.h>
-LOG_SETUP("blueprint_test");
+#include <vespa/vespalib/gtest/gtest.h>
using namespace search::queryeval;
using namespace search::fef;
-class Test : public vespalib::TestApp
-{
-public:
- void testEmptyBlueprint();
- void testSimpleBlueprint();
- void testFakeBlueprint();
- int Main() override;
-};
-
-void
-Test::testEmptyBlueprint()
+TEST(LeafBlueprintsTest, empty_blueprint)
{
MatchData::UP md(MatchData::makeTestInstance(100, 10));
EmptyBlueprint empty(FieldSpecBase(1, 11));
ASSERT_TRUE(empty.getState().numFields() == 1u);
- EXPECT_EQUAL(1u, empty.getState().field(0).getFieldId());
- EXPECT_EQUAL(11u, empty.getState().field(0).getHandle());
+ EXPECT_EQ(1u, empty.getState().field(0).getFieldId());
+ EXPECT_EQ(11u, empty.getState().field(0).getHandle());
empty.basic_plan(true, 100);
empty.fetchPostings(ExecuteInfo::FULL);
@@ -36,18 +23,17 @@ Test::testEmptyBlueprint()
SimpleResult res;
res.search(*search);
SimpleResult expect; // empty
- EXPECT_EQUAL(res, expect);
+ EXPECT_EQ(res, expect);
}
-void
-Test::testSimpleBlueprint()
+TEST(LeafBlueprintsTest, simple_blueprint)
{
MatchData::UP md(MatchData::makeTestInstance(100, 10));
SimpleResult a;
a.addHit(3).addHit(5).addHit(7);
SimpleBlueprint simple(a);
simple.tag("tag");
- EXPECT_EQUAL("tag", simple.tag());
+ EXPECT_EQ("tag", simple.tag());
simple.basic_plan(true, 100);
simple.fetchPostings(ExecuteInfo::FULL);
SearchIterator::UP search = simple.createSearch(*md);
@@ -56,11 +42,10 @@ Test::testSimpleBlueprint()
res.search(*search);
SimpleResult expect;
expect.addHit(3).addHit(5).addHit(7);
- EXPECT_EQUAL(res, expect);
+ EXPECT_EQ(res, expect);
}
-void
-Test::testFakeBlueprint()
+TEST(LeafBlueprintsTest, fake_blueprint)
{
MatchData::UP md(MatchData::makeTestInstance(100, 10));
FakeResult fake;
@@ -76,36 +61,36 @@ Test::testFakeBlueprint()
SearchIterator::UP search = orig.createSearch(*md);
search->initFullRange();
EXPECT_TRUE(!search->seek(1u));
- EXPECT_EQUAL(10u, search->getDocId());
+ EXPECT_EQ(10u, search->getDocId());
{
search->unpack(10u);
TermFieldMatchData &data = *md->resolveTermField(handle);
- EXPECT_EQUAL(fieldId, data.getFieldId());
- EXPECT_EQUAL(10u, data.getDocId());
- EXPECT_EQUAL(10u, data.getDocId());
+ EXPECT_EQ(fieldId, data.getFieldId());
+ EXPECT_EQ(10u, data.getDocId());
+ EXPECT_EQ(10u, data.getDocId());
FieldPositionsIterator itr = data.getIterator();
- EXPECT_EQUAL(50u, itr.getFieldLength());
- EXPECT_EQUAL(2u, itr.size());
+ EXPECT_EQ(50u, itr.getFieldLength());
+ EXPECT_EQ(2u, itr.size());
ASSERT_TRUE(itr.valid());
- EXPECT_EQUAL(2u, itr.getPosition());
+ EXPECT_EQ(2u, itr.getPosition());
itr.next();
ASSERT_TRUE(itr.valid());
- EXPECT_EQUAL(3u, itr.getPosition());
+ EXPECT_EQ(3u, itr.getPosition());
itr.next();
EXPECT_TRUE(!itr.valid());
}
EXPECT_TRUE(search->seek(25));
- EXPECT_EQUAL(25u, search->getDocId());
+ EXPECT_EQ(25u, search->getDocId());
{
search->unpack(25u);
TermFieldMatchData &data = *md->resolveTermField(handle);
- EXPECT_EQUAL(fieldId, data.getFieldId());
- EXPECT_EQUAL(25u, data.getDocId());
+ EXPECT_EQ(fieldId, data.getFieldId());
+ EXPECT_EQ(25u, data.getDocId());
FieldPositionsIterator itr = data.getIterator();
- EXPECT_EQUAL(10u, itr.getFieldLength());
- EXPECT_EQUAL(1u, itr.size());
+ EXPECT_EQ(10u, itr.getFieldLength());
+ EXPECT_EQ(1u, itr.size());
ASSERT_TRUE(itr.valid());
- EXPECT_EQUAL(5u, itr.getPosition());
+ EXPECT_EQ(5u, itr.getPosition());
itr.next();
EXPECT_TRUE(!itr.valid());
}
@@ -113,14 +98,4 @@ Test::testFakeBlueprint()
EXPECT_TRUE(search->isAtEnd());
}
-int
-Test::Main()
-{
- TEST_INIT("leaf_blueprints_test");
- testEmptyBlueprint();
- testSimpleBlueprint();
- testFakeBlueprint();
- TEST_DONE();
-}
-
-TEST_APPHOOK(Test);
+GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp b/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp
index 16e78f77eec..9fdf1417a92 100644
--- a/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp
+++ b/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp
@@ -356,7 +356,7 @@ DotProductAdapter::~DotProductAdapter() = default;
struct ParallelWeakAndAdapter {
FieldSpec field;
ParallelWeakAndBlueprint blueprint;
- ParallelWeakAndAdapter() : field("foo", 3, 7), blueprint(field, 100, 0.0, 1.0) {}
+ ParallelWeakAndAdapter() : field("foo", 3, 7), blueprint(field, 100, 0.0, 1.0, true) {}
void addChild(std::unique_ptr<Blueprint> child) {
auto child_field = blueprint.getNextChildField(field);
auto term = std::make_unique<LeafProxy>(child_field, std::move(child));
diff --git a/searchlib/src/tests/queryeval/flow/queryeval_flow_test.cpp b/searchlib/src/tests/queryeval/flow/queryeval_flow_test.cpp
index 57fddb0a819..d6008136d73 100644
--- a/searchlib/src/tests/queryeval/flow/queryeval_flow_test.cpp
+++ b/searchlib/src/tests/queryeval/flow/queryeval_flow_test.cpp
@@ -1,6 +1,7 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/searchlib/queryeval/flow.h>
+#include <vespa/searchlib/queryeval/flow_tuning.h>
#include <vespa/vespalib/gtest/gtest.h>
#include <vector>
#include <random>
@@ -349,6 +350,35 @@ TEST(FlowTest, blender_flow_cost_accumulation_is_max) {
}
}
+double my_non_strict_cost(double est, double adjust) {
+ return (1.0/adjust) * flow::forced_strict_cost(FlowStats(est, 0.0, est), adjust);
+}
+
+TEST(FlowTest, non_strict_btree_cost) {
+ for (double est: {0.001, 0.01, 0.1, 0.2, 0.3, 0.5, 0.75, 1.0}) {
+ auto prev = FlowStats(est, 1.0, est);
+ auto base = FlowStats(est, flow::non_strict_cost_of_strict_iterator(est, est), est);
+ auto opt05 = FlowStats(est, my_non_strict_cost(est, 0.5), est);
+ auto opt02 = FlowStats(est, my_non_strict_cost(est, 0.2), est);
+ auto opt01 = FlowStats(est, my_non_strict_cost(est, 0.1), est);
+ auto opt005 = FlowStats(est, my_non_strict_cost(est, 0.05), est);
+ auto opt003 = FlowStats(est, my_non_strict_cost(est, 0.03), est);
+ EXPECT_NEAR(strict_crossover(opt05), 0.5, 1e-6);
+ EXPECT_NEAR(strict_crossover(opt02), 0.2, 1e-6);
+ EXPECT_NEAR(strict_crossover(opt01), 0.1, 1e-6);
+ EXPECT_NEAR(strict_crossover(opt005), 0.05, 1e-6);
+ EXPECT_NEAR(strict_crossover(opt003), 0.03, 1e-6);
+ fprintf(stderr, "est: %5.3f\n", est);
+ fprintf(stderr, " prev crossover: %6.4f (cost: %6.4f)\n", strict_crossover(prev), prev.cost);
+ fprintf(stderr, " base crossover: %6.4f (cost: %6.4f)\n", strict_crossover(base), base.cost);
+ fprintf(stderr, " 0.5 crossover: %6.4f (cost: %6.4f)\n", strict_crossover(opt05), opt05.cost);
+ fprintf(stderr, " 0.2 crossover: %6.4f (cost: %6.4f)\n", strict_crossover(opt02), opt02.cost);
+ fprintf(stderr, " 0.1 crossover: %6.4f (cost: %6.4f)\n", strict_crossover(opt01), opt01.cost);
+ fprintf(stderr, " 0.05 crossover: %6.4f (cost: %6.4f)\n", strict_crossover(opt005), opt005.cost);
+ fprintf(stderr, " 0.03 crossover: %6.4f (cost: %6.4f)\n", strict_crossover(opt003), opt003.cost);
+ }
+}
+
TEST(FlowTest, optimal_and_flow) {
for (size_t i = 0; i < loop_cnt; ++i) {
for (bool strict: {false, true}) {
diff --git a/searchlib/src/tests/queryeval/iterator_benchmark/intermediate_blueprint_factory.cpp b/searchlib/src/tests/queryeval/iterator_benchmark/intermediate_blueprint_factory.cpp
index 8591ec1415d..51177850155 100644
--- a/searchlib/src/tests/queryeval/iterator_benchmark/intermediate_blueprint_factory.cpp
+++ b/searchlib/src/tests/queryeval/iterator_benchmark/intermediate_blueprint_factory.cpp
@@ -2,14 +2,14 @@
#include "intermediate_blueprint_factory.h"
#include <vespa/searchlib/queryeval/intermediate_blueprints.h>
+#include <vespa/searchlib/attribute/singlenumericattribute.h>
#include <iomanip>
#include <sstream>
namespace search::queryeval::test {
-template <typename BlueprintType>
char
-IntermediateBlueprintFactory<BlueprintType>::child_name(void* blueprint) const
+IntermediateBlueprintFactory::child_name(void* blueprint) const
{
auto itr = _child_names.find(blueprint);
if (itr != _child_names.end()) {
@@ -18,35 +18,33 @@ IntermediateBlueprintFactory<BlueprintType>::child_name(void* blueprint) const
return '?';
}
-template <typename BlueprintType>
-IntermediateBlueprintFactory<BlueprintType>::IntermediateBlueprintFactory(vespalib::stringref name)
+IntermediateBlueprintFactory::IntermediateBlueprintFactory(vespalib::stringref name)
: _name(name),
_children(),
_child_names()
{
}
-template <typename BlueprintType>
-IntermediateBlueprintFactory<BlueprintType>::~IntermediateBlueprintFactory() = default;
+IntermediateBlueprintFactory::~IntermediateBlueprintFactory() = default;
-template <typename BlueprintType>
std::unique_ptr<Blueprint>
-IntermediateBlueprintFactory<BlueprintType>::make_blueprint()
+IntermediateBlueprintFactory::make_blueprint()
{
- auto res = std::make_unique<BlueprintType>();
+ auto res = make_self();
_child_names.clear();
char name = 'A';
+ uint32_t source = 1;
for (const auto& factory : _children) {
auto child = factory->make_blueprint();
_child_names[child.get()] = name++;
+ child->setSourceId(source++); // ignored by non-source-blender blueprints
res->addChild(std::move(child));
}
return res;
}
-template <typename BlueprintType>
vespalib::string
-IntermediateBlueprintFactory<BlueprintType>::get_name(Blueprint& blueprint) const
+IntermediateBlueprintFactory::get_name(Blueprint& blueprint) const
{
auto* intermediate = blueprint.asIntermediate();
if (intermediate != nullptr) {
@@ -69,11 +67,29 @@ IntermediateBlueprintFactory<BlueprintType>::get_name(Blueprint& blueprint) cons
return get_class_name(blueprint);
}
-template class IntermediateBlueprintFactory<AndBlueprint>;
+//-----------------------------------------------------------------------------
AndBlueprintFactory::AndBlueprintFactory()
- : IntermediateBlueprintFactory<AndBlueprint>("AND")
+ : IntermediateBlueprintFactory("AND")
{}
+std::unique_ptr<IntermediateBlueprint>
+AndBlueprintFactory::make_self() const
+{
+ return std::make_unique<AndBlueprint>();
+}
+
+//-----------------------------------------------------------------------------
+
+SourceBlenderBlueprintFactory::SourceBlenderBlueprintFactory()
+ : IntermediateBlueprintFactory("SB"),
+ _selector(250, "my_source_blender", 1000)
+{}
+
+std::unique_ptr<IntermediateBlueprint>
+SourceBlenderBlueprintFactory::make_self() const
+{
+ return std::make_unique<SourceBlenderBlueprint>(_selector);
}
+}
diff --git a/searchlib/src/tests/queryeval/iterator_benchmark/intermediate_blueprint_factory.h b/searchlib/src/tests/queryeval/iterator_benchmark/intermediate_blueprint_factory.h
index 6f7fe4f9ee7..c791d866612 100644
--- a/searchlib/src/tests/queryeval/iterator_benchmark/intermediate_blueprint_factory.h
+++ b/searchlib/src/tests/queryeval/iterator_benchmark/intermediate_blueprint_factory.h
@@ -4,6 +4,7 @@
#include "benchmark_blueprint_factory.h"
#include <vespa/searchlib/queryeval/intermediate_blueprints.h>
+#include <vespa/searchlib/attribute/fixedsourceselector.h>
#include <unordered_map>
namespace search::queryeval::test {
@@ -11,7 +12,6 @@ namespace search::queryeval::test {
/**
* Factory that creates an IntermediateBlueprint (of the given type) with children created by the given factories.
*/
-template <typename BlueprintType>
class IntermediateBlueprintFactory : public BenchmarkBlueprintFactory {
private:
vespalib::string _name;
@@ -19,7 +19,8 @@ private:
std::unordered_map<void*, char> _child_names;
char child_name(void* blueprint) const;
-
+protected:
+ virtual std::unique_ptr<IntermediateBlueprint> make_self() const = 0;
public:
IntermediateBlueprintFactory(vespalib::stringref name);
~IntermediateBlueprintFactory();
@@ -30,10 +31,26 @@ public:
vespalib::string get_name(Blueprint& blueprint) const override;
};
-class AndBlueprintFactory : public IntermediateBlueprintFactory<AndBlueprint> {
+class AndBlueprintFactory : public IntermediateBlueprintFactory {
+protected:
+ std::unique_ptr<IntermediateBlueprint> make_self() const override;
public:
AndBlueprintFactory();
};
-}
+class SourceBlenderBlueprintFactory : public IntermediateBlueprintFactory
+{
+private:
+ FixedSourceSelector _selector;
+protected:
+ std::unique_ptr<IntermediateBlueprint> make_self() const override;
+public:
+ SourceBlenderBlueprintFactory();
+ void init_selector(auto f, uint32_t limit) {
+ for (uint32_t i = 0; i < limit; ++i) {
+ _selector.setSource(i, f(i));
+ }
+ }
+};
+}
diff --git a/searchlib/src/tests/queryeval/iterator_benchmark/iterator_benchmark_test.cpp b/searchlib/src/tests/queryeval/iterator_benchmark/iterator_benchmark_test.cpp
index f4a1ade8a66..e74fefac70e 100644
--- a/searchlib/src/tests/queryeval/iterator_benchmark/iterator_benchmark_test.cpp
+++ b/searchlib/src/tests/queryeval/iterator_benchmark/iterator_benchmark_test.cpp
@@ -13,19 +13,31 @@
#include <vector>
using namespace search::attribute;
-using namespace search::fef;
using namespace search::queryeval::test;
using namespace search::queryeval;
using namespace search;
using namespace vespalib;
using search::index::Schema;
+using search::fef::MatchData;
using vespalib::make_string_short::fmt;
const vespalib::string field_name = "myfield";
double budget_sec = 1.0;
+double estimate_actual_cost(Blueprint &bp, InFlow in_flow) {
+ if (in_flow.strict()) {
+ assert(bp.strict());
+ return bp.strict_cost();
+ } else if (bp.strict()) {
+ auto stats = FlowStats::from(flow::DefaultAdapter(), &bp);
+ return flow::forced_strict_cost(stats, in_flow.rate());
+ } else {
+ return bp.cost() * in_flow.rate();
+ }
+}
+
enum class PlanningAlgo {
Order,
Estimate,
@@ -236,7 +248,8 @@ strict_search(BenchmarkBlueprintFactory& factory, uint32_t docid_limit, Planning
timer.after();
}
FlowStats flow(ctx.blueprint->estimate(), ctx.blueprint->cost(), ctx.blueprint->strict_cost());
- return {timer.min_time() * 1000.0, hits + 1, hits, flow, flow.strict_cost, get_class_name(*ctx.iterator), factory.get_name(*ctx.blueprint)};
+ double actual_cost = estimate_actual_cost(*ctx.blueprint, InFlow(true));
+ return {timer.min_time() * 1000.0, hits + 1, hits, flow, actual_cost, get_class_name(*ctx.iterator), factory.get_name(*ctx.blueprint)};
}
template <bool do_unpack>
@@ -269,7 +282,7 @@ non_strict_search(BenchmarkBlueprintFactory& factory, uint32_t docid_limit, doub
timer.after();
}
FlowStats flow(ctx.blueprint->estimate(), ctx.blueprint->cost(), ctx.blueprint->strict_cost());
- double actual_cost = flow.cost * filter_hit_ratio;
+ double actual_cost = estimate_actual_cost(*ctx.blueprint, InFlow(filter_hit_ratio));
return {timer.min_time() * 1000.0, seeks, hits, flow, actual_cost, get_class_name(*ctx.iterator), factory.get_name(*ctx.blueprint)};
}
@@ -291,10 +304,6 @@ benchmark_search(BenchmarkBlueprintFactory& factory, uint32_t docid_limit, bool
}
}
-
-
-
-
//-----------------------------------------------------------------------------
double est_forced_strict_cost(double estimate, double strict_cost, double rate) {
@@ -317,26 +326,26 @@ struct Sample {
}
};
-double find_crossover(const char *type, const auto &calculate_at, double delta) {
+double find_crossover(const char *type, const char *a, const char *b, const auto &calculate_at, double delta) {
double min = delta;
double max = 1.0;
fprintf(stderr, "looking for %s crossover in the range [%g, %g]...\n", type, min, max);
auto at_min = calculate_at(min);
auto at_max = calculate_at(max);
- fprintf(stderr, " before: [%s, %s], after: [%s, %s]\n",
- at_min.first.str().c_str(), at_max.first.str().c_str(),
- at_min.second.str().c_str(), at_max.second.str().c_str());
- auto best_before = [](auto values) { return (values.first < values.second); };
- if (best_before(at_min) == best_before(at_max)) {
+ fprintf(stderr, " %s: [%s, %s], %s: [%s, %s]\n",
+ a, at_min.first.str().c_str(), at_max.first.str().c_str(),
+ b, at_min.second.str().c_str(), at_max.second.str().c_str());
+ auto a_best = [](auto values) { return (values.first < values.second); };
+ if (a_best(at_min) == a_best(at_max)) {
fprintf(stderr, " NO %s CROSSOVER FOUND\n", type);
return 0.0;
}
while (max > (min + delta)) {
double x = (min + max) / 2.0;
auto at_x = calculate_at(x);
- fprintf(stderr, " best@%g: %s (%s vs %s)\n", x, best_before(at_x) ? "before" : "after",
+ fprintf(stderr, " best@%g: %s (%s vs %s)\n", x, a_best(at_x) ? a : b,
at_x.first.str().c_str(), at_x.second.str().c_str());
- if (best_before(at_min) == best_before(at_x)) {
+ if (a_best(at_min) == a_best(at_x)) {
min = x;
at_min = at_x;
} else {
@@ -409,11 +418,11 @@ void analyze_crossover(BenchmarkBlueprintFactory &fixed, std::function<std::uniq
std::vector<double> results;
std::vector<const char *> names;
names.push_back("time crossover");
- results.push_back(find_crossover("TIME", combine(estimate_AND_time_ms), delta));
+ results.push_back(find_crossover("TIME", "before", "after", combine(estimate_AND_time_ms), delta));
names.push_back("cost crossover");
- results.push_back(find_crossover("COST", combine(calculate_AND_cost), delta));
+ results.push_back(find_crossover("COST", "before", "after", combine(calculate_AND_cost), delta));
names.push_back("abs_est crossover");
- results.push_back(find_crossover("ABS_EST", combine(first_abs_est), delta));
+ results.push_back(find_crossover("ABS_EST", "before", "after", combine(first_abs_est), delta));
sample_at("COST", combine(calculate_AND_cost), results, names);
sample_at("TIME", combine(estimate_AND_time_ms), results, names);
}
@@ -429,21 +438,37 @@ to_string(bool val)
void
print_result_header()
{
- std::cout << "| chn | f_ratio | o_ratio | a_ratio | f.est | f.cost | f.scost | hits | seeks | time_ms | act_cost | ns_per_seek | ms_per_act_cost | iterator | blueprint |" << std::endl;
+ std::cout << "| in_flow | chn | o_ratio | a_ratio | f.est | f.cost | f.act_cost | f.scost | f.act_scost | hits | seeks | time_ms | act_cost | ns_per_seek | ms_per_act_cost | iterator | blueprint |" << std::endl;
+}
+
+std::ostream &operator<<(std::ostream &dst, InFlow in_flow) {
+ auto old_w = dst.width();
+ auto old_p = dst.precision();
+ dst << std::setw(7) << std::setprecision(5);
+ if (in_flow.strict()) {
+ dst << " STRICT";
+ } else {
+ dst << in_flow.rate();
+ }
+ dst << std::setw(old_w);
+ dst << std::setprecision(old_p);
+ return dst;
}
void
-print_result(const BenchmarkResult& res, uint32_t children, double op_hit_ratio, double filter_hit_ratio, uint32_t num_docs)
+print_result(const BenchmarkResult& res, uint32_t children, double op_hit_ratio, InFlow in_flow, uint32_t num_docs)
{
std::cout << std::fixed << std::setprecision(5)
- << "| " << std::setw(5) << children
- << " | " << std::setw(7) << filter_hit_ratio
+ << "| " << in_flow
+ << " | " << std::setw(5) << children
<< " | " << std::setw(7) << op_hit_ratio
<< " | " << std::setw(7) << ((double) res.hits / (double) num_docs)
<< " | " << std::setw(6) << res.flow.estimate
<< std::setprecision(4)
<< " | " << std::setw(9) << res.flow.cost
+ << " | " << std::setw(10) << (res.flow.cost * in_flow.rate())
<< " | " << std::setw(7) << res.flow.strict_cost
+ << " | " << std::setw(11) << (in_flow.strict() ? res.flow.strict_cost : flow::forced_strict_cost(res.flow, in_flow.rate()))
<< " | " << std::setw(8) << res.hits
<< " | " << std::setw(8) << res.seeks
<< std::setprecision(3)
@@ -640,7 +665,7 @@ run_benchmark_case(const BenchmarkCaseSetup& setup)
if (filter_hit_ratio * setup.filter_crossover_factor <= op_hit_ratio) {
auto res = benchmark_search(*factory, setup.num_docs + 1,
setup.bcase.strict_context, setup.bcase.force_strict, setup.bcase.unpack_iterator, filter_hit_ratio, PlanningAlgo::Cost);
- print_result(res, children, op_hit_ratio, filter_hit_ratio, setup.num_docs);
+ print_result(res, children, op_hit_ratio, InFlow(setup.bcase.strict_context, filter_hit_ratio), setup.num_docs);
result.add(res);
}
}
@@ -681,23 +706,25 @@ run_benchmarks(const BenchmarkSetup& setup)
void
print_intermediate_blueprint_result_header(size_t children)
{
+ std::cout << "| in_flow";
// This matches the naming scheme in IntermediateBlueprintFactory.
char name = 'A';
for (size_t i = 0; i < children; ++i) {
- std::cout << "| " << name++ << ".ratio ";
+ std::cout << " | " << name++ << ".ratio";
}
- std::cout << "| flow.cost | flow.scost | flow.est | ratio | hits | seeks | ms_per_cost | time_ms | algo | blueprint |" << std::endl;
+ std::cout << " | flow.cost | flow.scost | flow.est | ratio | hits | seeks | ms_per_cost | time_ms | algo | blueprint |" << std::endl;
}
void
-print_intermediate_blueprint_result(const BenchmarkResult& res, const std::vector<double>& children_ratios, PlanningAlgo algo, uint32_t num_docs)
+print_intermediate_blueprint_result(const BenchmarkResult& res, const std::vector<double>& children_ratios, PlanningAlgo algo, InFlow in_flow, uint32_t num_docs)
{
- std::cout << std::fixed << std::setprecision(5);
+ std::cout << std::fixed << std::setprecision(5)
+ << "| " << in_flow;
for (auto ratio : children_ratios) {
- std::cout << "| " << std::setw(7) << ratio << " ";
+ std::cout << " | " << std::setw(7) << ratio;
}
std::cout << std::setprecision(5)
- << "| " << std::setw(10) << res.flow.cost
+ << " | " << std::setw(10) << res.flow.cost
<< " | " << std::setw(10) << res.flow.strict_cost
<< " | " << std::setw(8) << res.flow.estimate
<< " | " << std::setw(7) << ((double) res.hits / (double) num_docs)
@@ -745,9 +772,8 @@ struct BlueprintFactorySetup {
BlueprintFactorySetup::~BlueprintFactorySetup() = default;
-template <typename IntermediateBlueprintFactoryType>
void
-run_intermediate_blueprint_benchmark(const BlueprintFactorySetup& a, const BlueprintFactorySetup& b, size_t num_docs)
+run_intermediate_blueprint_benchmark(auto factory_factory, std::vector<InFlow> in_flows, const BlueprintFactorySetup& a, const BlueprintFactorySetup& b, size_t num_docs)
{
print_intermediate_blueprint_result_header(2);
double max_speedup = 0.0;
@@ -755,26 +781,28 @@ run_intermediate_blueprint_benchmark(const BlueprintFactorySetup& a, const Bluep
for (double b_hit_ratio: b.op_hit_ratios) {
auto b_factory = b.make_factory_shared(num_docs, b_hit_ratio);
for (double a_hit_ratio : a.op_hit_ratios) {
- IntermediateBlueprintFactoryType factory;
- factory.add_child(a.make_factory(num_docs, a_hit_ratio));
- factory.add_child(b_factory);
+ auto factory = factory_factory();
+ factory->add_child(a.make_factory(num_docs, a_hit_ratio));
+ factory->add_child(b_factory);
double time_ms_esti = 0.0;
- for (auto algo: {PlanningAlgo::Order, PlanningAlgo::Estimate, PlanningAlgo::Cost,
- PlanningAlgo::CostForceStrict}) {
- auto res = benchmark_search(factory, num_docs + 1, true, false, false, 1.0, algo);
- print_intermediate_blueprint_result(res, {a_hit_ratio, b_hit_ratio}, algo, num_docs);
- if (algo == PlanningAlgo::Estimate) {
- time_ms_esti = res.time_ms;
- }
- if (algo == PlanningAlgo::CostForceStrict) {
- double speedup = time_ms_esti / res.time_ms;
- if (speedup > max_speedup) {
- max_speedup = speedup;
+ for (InFlow in_flow: in_flows) {
+ for (auto algo: {PlanningAlgo::Order, PlanningAlgo::Estimate, PlanningAlgo::Cost,
+ PlanningAlgo::CostForceStrict}) {
+ auto res = benchmark_search(*factory, num_docs + 1, in_flow.strict(), false, false, in_flow.rate(), algo);
+ print_intermediate_blueprint_result(res, {a_hit_ratio, b_hit_ratio}, algo, in_flow, num_docs);
+ if (algo == PlanningAlgo::Estimate) {
+ time_ms_esti = res.time_ms;
}
- if (speedup < min_speedup) {
- min_speedup = speedup;
+ if (algo == PlanningAlgo::CostForceStrict) {
+ double speedup = time_ms_esti / res.time_ms;
+ if (speedup > max_speedup) {
+ max_speedup = speedup;
+ }
+ if (speedup < min_speedup) {
+ min_speedup = speedup;
+ }
+ std::cout << "speedup (esti/forc)=" << std::setprecision(4) << speedup << std::endl;
}
- std::cout << "speedup (esti/forc)=" << std::setprecision(4) << speedup << std::endl;
}
}
}
@@ -786,7 +814,19 @@ void
run_and_benchmark(const BlueprintFactorySetup& a, const BlueprintFactorySetup& b, size_t num_docs)
{
std::cout << "AND[A={" << a.to_string() << "},B={" << b.to_string() << "}]" << std::endl;
- run_intermediate_blueprint_benchmark<AndBlueprintFactory>(a, b, num_docs);
+ run_intermediate_blueprint_benchmark([](){ return std::make_unique<AndBlueprintFactory>(); }, {true}, a, b, num_docs);
+}
+
+void
+run_source_blender_benchmark(const BlueprintFactorySetup& a, const BlueprintFactorySetup& b, size_t num_docs)
+{
+ std::cout << "SB[A={" << a.to_string() << "},B={" << b.to_string() << "}]" << std::endl;
+ auto factory_factory = [&](){
+ auto factory = std::make_unique<SourceBlenderBlueprintFactory>();
+ factory->init_selector([](uint32_t i){ return (i%10 == 0) ? 1 : 2; }, num_docs + 1);
+ return factory;
+ };
+ run_intermediate_blueprint_benchmark(factory_factory, {true, 0.75, 0.5, 0.25, 0.1, 0.01, 0.001}, a, b, num_docs);
}
//-------------------------------------------------------------------------------------
@@ -970,16 +1010,40 @@ TEST(IteratorBenchmark, analyze_AND_bitvector_vs_IN)
}
}
+TEST(IteratorBenchmark, analyze_strict_SOURCEBLENDER_memory_and_disk)
+{
+ for (double small_ratio: {0.001, 0.005, 0.01, 0.05}) {
+ run_source_blender_benchmark({str_fs, QueryOperator::Term, {small_ratio}},
+ {str_index, QueryOperator::Term, {small_ratio * 10}},
+ num_docs);
+ }
+}
+
TEST(IteratorBenchmark, analyze_OR_non_strict_fs)
{
for (auto or_hit_ratio : {0.01, 0.1, 0.5}) {
BenchmarkSetup setup(num_docs, {int32_fs}, {QueryOperator::Or}, {false}, {or_hit_ratio},
{2, 4, 6, 8, 10, 100, 1000});
+ //setup.force_strict = true;
setup.filter_hit_ratios = gen_ratios(or_hit_ratio, 10.0, 13);
run_benchmarks(setup);
}
}
+TEST(IteratorBenchmark, analyze_OR_non_strict_fs_child_est_adjust)
+{
+ for (auto or_hit_ratio : {0.01, 0.1, 0.5}) {
+ for (uint32_t children : {2, 4, 6, 8, 10, 100, 1000}) {
+ double child_est = or_hit_ratio / children;
+ BenchmarkSetup setup(num_docs, {int32_fs}, {QueryOperator::Or}, {false}, {or_hit_ratio},
+ {children});
+ //setup.force_strict = true;
+ setup.filter_hit_ratios = gen_ratios(child_est, 10.0, 13);
+ run_benchmarks(setup);
+ }
+ }
+}
+
TEST(IteratorBenchmark, analyze_OR_non_strict_non_fs)
{
BenchmarkSetup setup(num_docs, {int32}, {QueryOperator::Or}, {false}, {0.1}, {2, 4, 6, 8, 10});
@@ -1008,6 +1072,22 @@ TEST(IteratorBenchmark, analyze_btree_vs_bitvector_iterators_strict)
run_benchmarks(setup);
}
+TEST(IteratorBenchmark, btree_vs_array_nonstrict_crossover) {
+ for (double hit_ratio: { 0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009,
+ 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09,
+ 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9,
+ 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.0})
+ {
+ auto btree = make_blueprint_factory(int32_array_fs, QueryOperator::Term, num_docs, 0, hit_ratio, 1, false);
+ auto array = make_blueprint_factory( int32_array, QueryOperator::Term, num_docs, 0, hit_ratio, 1, false);
+ auto time_ms = [&](auto &bpf, double in_flow) {
+ return Sample(benchmark_search(bpf, num_docs + 1, false, false, false, in_flow, PlanningAlgo::Cost).time_ms);
+ };
+ auto calculate_at = [&](double in_flow) { return std::make_pair(time_ms(*btree, in_flow), time_ms(*array, in_flow)); };
+ fprintf(stderr, "btree/array crossover@%5.3f: %8.6f\n", hit_ratio, find_crossover("TIME", "btree", "array", calculate_at, 0.0001));
+ }
+}
+
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
int res = RUN_ALL_TESTS();
diff --git a/searchlib/src/tests/queryeval/parallel_weak_and/parallel_weak_and_test.cpp b/searchlib/src/tests/queryeval/parallel_weak_and/parallel_weak_and_test.cpp
index 2bd560637d2..1cec376b01c 100644
--- a/searchlib/src/tests/queryeval/parallel_weak_and/parallel_weak_and_test.cpp
+++ b/searchlib/src/tests/queryeval/parallel_weak_and/parallel_weak_and_test.cpp
@@ -68,8 +68,8 @@ struct TestHeap : public WeakAndHeap
{
ScoresHistory history;
- TestHeap(uint32_t scoresToTrack_) : WeakAndHeap(scoresToTrack_), history() {}
- virtual void adjust(score_t *begin, score_t *end) override {
+ explicit TestHeap(uint32_t scoresToTrack_) : WeakAndHeap(scoresToTrack_), history() {}
+ void adjust(score_t *begin, score_t *end) override {
Scores scores;
for (score_t *itr = begin; itr != end; ++itr) {
scores.add(*itr);
@@ -87,8 +87,8 @@ struct WandTestSpec : public WandSpec
TermFieldMatchData rootMatchData;
MatchParams matchParams;
- WandTestSpec(uint32_t scoresToTrack, uint32_t scoresAdjustFrequency = 1,
- score_t scoreThreshold = 0, double thresholdBoostFactor = 1);
+ explicit WandTestSpec(uint32_t scoresToTrack, uint32_t scoresAdjustFrequency = 1,
+ score_t scoreThreshold = 0, double thresholdBoostFactor = 1);
~WandTestSpec();
SearchIterator::UP create() {
MatchData::UP childrenMatchData = createMatchData();
@@ -114,7 +114,7 @@ WandTestSpec<HeapType>::WandTestSpec(uint32_t scoresToTrack, uint32_t scoresAdju
{}
template <typename HeapType>
-WandTestSpec<HeapType>::~WandTestSpec() {}
+WandTestSpec<HeapType>::~WandTestSpec() = default;
using WandSpecWithTestHeap = WandTestSpec<TestHeap>;
using WandSpecWithRealHeap = WandTestSpec<SharedWeakAndPriorityQueue>;
@@ -137,8 +137,8 @@ SimpleResult
asSimpleResult(const FakeResult &result)
{
SimpleResult retval;
- for (size_t i = 0; i < result.inspect().size(); ++i) {
- retval.addHit(result.inspect()[i].docId);
+ for (const auto & doc : result.inspect()) {
+ retval.addHit(doc.docId);
}
return retval;
}
@@ -152,26 +152,26 @@ struct WandBlueprintSpec
FakeRequestContext requestContext;
WandBlueprintSpec &add(const std::string &token, int32_t weight) {
- tokens.push_back(std::make_pair(token, weight));
+ tokens.emplace_back(token, weight);
return *this;
}
Node::UP createNode(uint32_t scoresToTrack = 100,
score_t scoreThreshold = 0,
double thresholdBoostFactor = 1) const {
- SimpleWandTerm *node = new SimpleWandTerm(tokens.size(), "view", 0, Weight(0),
- scoresToTrack, scoreThreshold, thresholdBoostFactor);
- for (size_t i = 0; i < tokens.size(); ++i) {
- node->addTerm(tokens[i].first, Weight(tokens[i].second));
+ auto node = std::make_unique<SimpleWandTerm>(tokens.size(), "view", 0, Weight(0),
+ scoresToTrack, scoreThreshold, thresholdBoostFactor);
+ for (const auto & token : tokens) {
+ node->addTerm(token.first, Weight(token.second));
}
- return Node::UP(node);
+ return node;
}
Blueprint::UP blueprint(Searchable &searchable, const std::string &field, const search::query::Node &term) const {
FieldSpecList fields;
fields.add(FieldSpec(field, fieldId, handle));
Blueprint::UP bp = searchable.createBlueprint(requestContext, fields, term);
- EXPECT_TRUE(dynamic_cast<ParallelWeakAndBlueprint*>(bp.get()) != 0);
+ EXPECT_TRUE(dynamic_cast<ParallelWeakAndBlueprint*>(bp.get()) != nullptr);
return bp;
}
@@ -182,7 +182,7 @@ struct WandBlueprintSpec
bp->basic_plan(true, docIdLimit);
bp->fetchPostings(ExecuteInfo::FULL);
SearchIterator::UP sb = bp->createSearch(*md);
- EXPECT_TRUE(dynamic_cast<ParallelWeakAndSearch*>(sb.get()) != 0);
+ EXPECT_TRUE(dynamic_cast<ParallelWeakAndSearch*>(sb.get()) != nullptr);
return sb;
}
@@ -197,7 +197,7 @@ struct WandBlueprintSpec
bp->basic_plan(true, docIdLimit);
bp->fetchPostings(ExecuteInfo::FULL);
SearchIterator::UP sb = bp->createSearch(*md);
- EXPECT_TRUE(dynamic_cast<ParallelWeakAndSearch*>(sb.get()) != 0);
+ EXPECT_TRUE(dynamic_cast<ParallelWeakAndSearch*>(sb.get()) != nullptr);
return doSearch(*sb, *md->resolveTermField(handle));
}
};
@@ -258,7 +258,7 @@ struct AlgoSameScoreFixture : public FixtureBase
struct AlgoScoreThresholdFixture : public FixtureBase
{
- AlgoScoreThresholdFixture(score_t scoreThreshold) : FixtureBase(3, 1, scoreThreshold) {
+ explicit AlgoScoreThresholdFixture(score_t scoreThreshold) : FixtureBase(3, 1, scoreThreshold) {
spec.leaf(LeafSpec("A", 1).doc(1, 10).doc(2, 30));
spec.leaf(LeafSpec("B", 2).doc(1, 20).doc(3, 40));
prepare();
@@ -267,7 +267,7 @@ struct AlgoScoreThresholdFixture : public FixtureBase
struct AlgoLargeScoresFixture : public FixtureBase
{
- AlgoLargeScoresFixture(score_t scoreThreshold) : FixtureBase(3, 1, scoreThreshold) {
+ explicit AlgoLargeScoresFixture(score_t scoreThreshold) : FixtureBase(3, 1, scoreThreshold) {
spec.leaf(LeafSpec("A", 60000).doc(1, 60000).doc(2, 70000));
spec.leaf(LeafSpec("B", 70000).doc(1, 80000).doc(3, 90000));
prepare();
@@ -276,7 +276,7 @@ struct AlgoLargeScoresFixture : public FixtureBase
struct AlgoExhaustPastFixture : public FixtureBase
{
- AlgoExhaustPastFixture(score_t scoreThreshold) : FixtureBase(3, 1, scoreThreshold) {
+ explicit AlgoExhaustPastFixture(score_t scoreThreshold) : FixtureBase(3, 1, scoreThreshold) {
spec.leaf(LeafSpec("A", 1).doc(1, 20).doc(3, 40).doc(5, 10));
spec.leaf(LeafSpec("B", 1).doc(5, 10));
spec.leaf(LeafSpec("C", 1).doc(5, 10));
@@ -449,11 +449,11 @@ struct BlueprintFixtureBase
};
BlueprintFixtureBase::BlueprintFixtureBase() : spec(), searchable() {}
-BlueprintFixtureBase::~BlueprintFixtureBase() {}
+BlueprintFixtureBase::~BlueprintFixtureBase() = default;
struct BlueprintHitsFixture : public BlueprintFixtureBase
{
- FakeResult createResult(size_t hits) {
+ static FakeResult createResult(size_t hits) {
FakeResult result;
for (size_t i = 0; i < hits; ++i) {
result.doc(i + 1);
@@ -479,7 +479,7 @@ struct BlueprintHitsFixture : public BlueprintFixtureBase
struct ThresholdBoostFixture : public FixtureBase
{
FakeResult result;
- ThresholdBoostFixture(double boost) : FixtureBase(1, 1, 800, boost) {
+ explicit ThresholdBoostFixture(double boost) : FixtureBase(1, 1, 800, boost) {
spec.leaf(LeafSpec("A").doc(1, 10));
spec.leaf(LeafSpec("B").doc(2, 20));
spec.leaf(LeafSpec("C").doc(3, 30));
@@ -532,7 +532,7 @@ TEST(ParallelWeakAndTest, require_that_blueprint_picks_up_docid_limit)
BlueprintFixture f;
Node::UP term = f.spec.createNode(57, 67, 77.7);
Blueprint::UP bp = f.blueprint(*term);
- const ParallelWeakAndBlueprint * pbp = dynamic_cast<const ParallelWeakAndBlueprint *>(bp.get());
+ const auto * pbp = dynamic_cast<const ParallelWeakAndBlueprint *>(bp.get());
EXPECT_EQ(0u, pbp->get_docid_limit());
bp->setDocIdLimit(1000);
EXPECT_EQ(1000u, pbp->get_docid_limit());
@@ -543,7 +543,7 @@ TEST(ParallelWeakAndTest, require_that_scores_to_track_score_threshold_and_thres
BlueprintFixture f;
Node::UP term = f.spec.createNode(57, 67, 77.7);
Blueprint::UP bp = f.blueprint(*term);
- const ParallelWeakAndBlueprint * pbp = dynamic_cast<const ParallelWeakAndBlueprint *>(bp.get());
+ const auto * pbp = dynamic_cast<const ParallelWeakAndBlueprint *>(bp.get());
EXPECT_EQ(57u, pbp->getScores().getScoresToTrack());
EXPECT_EQ(67u, pbp->getScoreThreshold());
EXPECT_EQ(77.7, pbp->getThresholdBoostFactor());
@@ -635,6 +635,7 @@ TEST(ParallelWeakAndTest, require_that_asString_on_blueprint_works)
" strict_cost: 0\n"
" sourceId: 4294967295\n"
" docid_limit: 0\n"
+ " id: 0\n"
" strict: false\n"
" _weights: std::vector {\n"
" [0]: 5\n"
@@ -661,6 +662,7 @@ TEST(ParallelWeakAndTest, require_that_asString_on_blueprint_works)
" strict_cost: 0\n"
" sourceId: 4294967295\n"
" docid_limit: 0\n"
+ " id: 0\n"
" strict: false\n"
" }\n"
" }\n"
@@ -708,7 +710,7 @@ SearchIterator::UP create_wand(bool use_dww,
class Verifier : public search::test::DwwIteratorChildrenVerifier {
public:
- Verifier(bool use_dww) : _use_dww(use_dww) { }
+ explicit Verifier(bool use_dww) : _use_dww(use_dww) { }
private:
SearchIterator::UP create(bool strict) const override {
MatchParams match_params(_dummy_heap, _dummy_heap.getMinScore(), 1.0, 1);
diff --git a/searchlib/src/tests/queryeval/sourceblender/sourceblender_test.cpp b/searchlib/src/tests/queryeval/sourceblender/sourceblender_test.cpp
index b84cb02a357..b2a1f6a645a 100644
--- a/searchlib/src/tests/queryeval/sourceblender/sourceblender_test.cpp
+++ b/searchlib/src/tests/queryeval/sourceblender/sourceblender_test.cpp
@@ -7,15 +7,14 @@
#include <vespa/searchlib/queryeval/leaf_blueprints.h>
#define ENABLE_GTEST_MIGRATION
#include <vespa/searchlib/test/searchiteratorverifier.h>
-#include <vespa/searchlib/common/bitvectoriterator.h>
#include <vespa/searchlib/attribute/fixedsourceselector.h>
#include <vespa/searchlib/fef/matchdata.h>
#include <vespa/vespalib/gtest/gtest.h>
using namespace search::queryeval;
-using namespace search::fef;
using namespace search;
using std::make_unique;
+using search::fef::MatchData;
/**
* Proxy search used to verify unpack pattern
@@ -27,24 +26,24 @@ private:
SimpleResult _unpacked;
protected:
- virtual void doSeek(uint32_t docid) override {
+ void doSeek(uint32_t docid) override {
_search->seek(docid);
setDocId(_search->getDocId());
}
- virtual void doUnpack(uint32_t docid) override {
+ void doUnpack(uint32_t docid) override {
_unpacked.addHit(docid);
_search->unpack(docid);
}
public:
- UnpackChecker(SearchIterator *search) : _search(search), _unpacked() {}
+ explicit UnpackChecker(SearchIterator *search) : _search(search), _unpacked() {}
const SimpleResult &getUnpacked() const { return _unpacked; }
};
class MySelector : public search::FixedSourceSelector
{
public:
- MySelector(int defaultSource) : search::FixedSourceSelector(defaultSource, "fs") { }
+ explicit MySelector(int defaultSource) : search::FixedSourceSelector(defaultSource, "fs") { }
MySelector & set(Source s, uint32_t docId) {
setSource(s, docId);
return *this;
@@ -65,12 +64,12 @@ TEST(SourceBlenderTest, test_strictness)
a.addHit(2).addHit(5).addHit(6).addHit(8);
b.addHit(3).addHit(5).addHit(6).addHit(7);
- MySelector *sel = new MySelector(5);
+ auto *sel = new MySelector(5);
sel->set(2, 1).set(3, 2).set(5, 2).set(7, 1);
- SourceBlenderBlueprint *blend_b = new SourceBlenderBlueprint(*sel);
- Blueprint::UP a_b(new SimpleBlueprint(a));
- Blueprint::UP b_b(new SimpleBlueprint(b));
+ auto *blend_b = new SourceBlenderBlueprint(*sel);
+ auto a_b = std::make_unique<SimpleBlueprint>(a);
+ auto b_b = std::make_unique<SimpleBlueprint>(b);
a_b->setSourceId(1);
b_b->setSourceId(2);
blend_b->addChild(std::move(a_b));
@@ -111,16 +110,16 @@ TEST(SourceBlenderTest, test_full_sourceblender_search)
c.addHit(4).addHit(11).addHit(21).addHit(32);
// these are all handed over to the blender
- UnpackChecker *ua = new UnpackChecker(new SimpleSearch(a));
- UnpackChecker *ub = new UnpackChecker(new SimpleSearch(b));
- UnpackChecker *uc = new UnpackChecker(new SimpleSearch(c));
+ auto *ua = new UnpackChecker(new SimpleSearch(a));
+ auto *ub = new UnpackChecker(new SimpleSearch(b));
+ auto *uc = new UnpackChecker(new SimpleSearch(c));
auto sel = make_unique<MySelector>(5);
sel->set(2, 1).set(3, 2).set(11, 2).set(21, 3).set(34, 1);
SourceBlenderSearch::Children abc;
- abc.push_back(SourceBlenderSearch::Child(ua, 1));
- abc.push_back(SourceBlenderSearch::Child(ub, 2));
- abc.push_back(SourceBlenderSearch::Child(uc, 3));
+ abc.emplace_back(ua, 1);
+ abc.emplace_back(ub, 2);
+ abc.emplace_back(uc, 3);
SearchIterator::UP blend(SourceBlenderSearch::create(sel->createIterator(), abc, true));
SimpleResult result;
@@ -149,7 +148,7 @@ using search::test::SearchIteratorVerifier;
class Verifier : public SearchIteratorVerifier {
public:
Verifier();
- ~Verifier();
+ ~Verifier() override;
SearchIterator::UP create(bool strict) const override {
return SearchIterator::UP(SourceBlenderSearch::create(_selector.createIterator(),
createChildren(strict),
@@ -178,7 +177,7 @@ Verifier::Verifier() :
_indexes[indexId].push_back(docId);
}
}
-Verifier::~Verifier() {}
+Verifier::~Verifier() = default;
TEST(SourceBlenderTest, test_that_source_blender_iterator_adheres_to_search_terator_requirements)
{
diff --git a/searchlib/src/tests/queryeval/sparse_vector_benchmark/sparse_vector_benchmark_test.cpp b/searchlib/src/tests/queryeval/sparse_vector_benchmark/sparse_vector_benchmark_test.cpp
index 94ecd8fa539..a7516226daf 100644
--- a/searchlib/src/tests/queryeval/sparse_vector_benchmark/sparse_vector_benchmark_test.cpp
+++ b/searchlib/src/tests/queryeval/sparse_vector_benchmark/sparse_vector_benchmark_test.cpp
@@ -13,6 +13,7 @@
#include <vespa/searchlib/queryeval/simpleresult.h>
#include <vespa/searchlib/queryeval/wand/weak_and_search.h>
#include <vespa/searchlib/queryeval/weighted_set_term_search.h>
+#include <vespa/searchlib/queryeval/wand/weak_and_heap.h>
#include <vespa/vespalib/util/box.h>
#include <vespa/vespalib/util/stringfmt.h>
@@ -135,7 +136,7 @@ constexpr vespalib::duration max_time = 1000s;
//-----------------------------------------------------------------------------
struct ChildFactory {
- ChildFactory() {}
+ ChildFactory() = default;
virtual std::string name() const = 0;
virtual SearchIterator::UP createChild(uint32_t idx, uint32_t limit) const = 0;
virtual ~ChildFactory() = default;
@@ -190,8 +191,9 @@ struct ModSearchFactory : ChildFactory {
//-----------------------------------------------------------------------------
struct VespaWandFactory : SparseVectorFactory {
+ mutable SharedWeakAndPriorityQueue _scores;
uint32_t n;
- explicit VespaWandFactory(uint32_t n_in) noexcept : n(n_in) {}
+ explicit VespaWandFactory(uint32_t n_in) : _scores(n_in), n(n_in) {}
std::string name() const override {
return vespalib::make_string("VespaWand(%u)", n);
}
@@ -200,7 +202,7 @@ struct VespaWandFactory : SparseVectorFactory {
for (size_t i = 0; i < childCnt; ++i) {
terms.emplace_back(childFactory.createChild(i, limit), default_weight, limit / (i + 1));
}
- return WeakAndSearch::create(terms, n, true);
+ return WeakAndSearch::create(terms, wand::MatchParams(_scores), n, true);
}
};
diff --git a/searchlib/src/tests/queryeval/termwise_eval/termwise_eval_test.cpp b/searchlib/src/tests/queryeval/termwise_eval/termwise_eval_test.cpp
index 310c6d628e3..4d84dabf834 100644
--- a/searchlib/src/tests/queryeval/termwise_eval/termwise_eval_test.cpp
+++ b/searchlib/src/tests/queryeval/termwise_eval/termwise_eval_test.cpp
@@ -465,7 +465,7 @@ TEST(TermwiseEvalTest, require_that_termwise_evaluation_can_be_multi_level_but_n
child->addChild(UP(new MyBlueprint({3}, true, 3)));
my_or.addChild(std::move(child));
for (bool strict: {true, false}) {
- my_or.basic_plan(strict, 100);
+ my_or.null_plan(strict, 100);
EXPECT_EQ(my_or.createSearch(*md)->asString(),
make_termwise(OR({ TERM({1}, strict),
ORz({ TERM({2}, strict), TERM({3}, strict) }, strict) },
diff --git a/searchlib/src/tests/queryeval/weak_and/wand_bench_setup.hpp b/searchlib/src/tests/queryeval/weak_and/wand_bench_setup.hpp
index 5e056eb6c0e..457f7133dc1 100644
--- a/searchlib/src/tests/queryeval/weak_and/wand_bench_setup.hpp
+++ b/searchlib/src/tests/queryeval/weak_and/wand_bench_setup.hpp
@@ -29,20 +29,20 @@ struct Stats {
size_t unpackCnt;
size_t skippedDocs;
size_t skippedHits;
- Stats() : hitCnt(0), seekCnt(0), unpackCnt(0),
+ Stats() noexcept : hitCnt(0), seekCnt(0), unpackCnt(0),
skippedDocs(0), skippedHits(0) {}
- void hit() {
+ void hit() noexcept {
++hitCnt;
}
- void seek(size_t docs, size_t hits) {
+ void seek(size_t docs, size_t hits) noexcept {
++seekCnt;
skippedDocs += docs;
skippedHits += hits;
}
- void unpack() {
+ void unpack() noexcept {
++unpackCnt;
}
- void print() {
+ void print() const {
fprintf(stderr, "Stats: hits=%zu, seeks=%zu, unpacks=%zu, skippedDocs=%zu, skippedHits=%zu\n",
hitCnt, seekCnt, unpackCnt, skippedDocs, skippedHits);
}
@@ -77,7 +77,7 @@ struct ModSearch : SearchIterator {
}
}
void doUnpack(uint32_t docid) override {
- if (tfmd != NULL) {
+ if (tfmd != nullptr) {
tfmd->reset(docid);
search::fef::TermFieldMatchDataPosition pos;
pos.setElementWeight(info.getMaxWeight());
@@ -96,40 +96,52 @@ ModSearch::~ModSearch() = default;
struct WandFactory {
virtual std::string name() const = 0;
virtual SearchIterator::UP create(const wand::Terms &terms) = 0;
- virtual ~WandFactory() {}
+ virtual ~WandFactory() = default;
};
struct VespaWandFactory : WandFactory {
+ mutable SharedWeakAndPriorityQueue _scores;
uint32_t n;
- VespaWandFactory(uint32_t n_in) : n(n_in) {}
+ explicit VespaWandFactory(uint32_t n_in) noexcept
+ : _scores(n_in),
+ n(n_in)
+ {}
~VespaWandFactory() override;
- virtual std::string name() const override { return make_string("VESPA WAND (n=%u)", n); }
- virtual SearchIterator::UP create(const wand::Terms &terms) override {
- return SearchIterator::UP(WeakAndSearch::create(terms, n, true));
+ std::string name() const override { return make_string("VESPA WAND (n=%u)", n); }
+ SearchIterator::UP create(const wand::Terms &terms) override {
+ return WeakAndSearch::create(terms, wand::MatchParams(_scores, 1, 1), n, true);
}
};
VespaWandFactory::~VespaWandFactory() = default;
struct VespaArrayWandFactory : WandFactory {
+ mutable SharedWeakAndPriorityQueue _scores;
uint32_t n;
- VespaArrayWandFactory(uint32_t n_in) : n(n_in) {}
+ explicit VespaArrayWandFactory(uint32_t n_in)
+ : _scores(n_in),
+ n(n_in)
+ {}
~VespaArrayWandFactory() override;
- virtual std::string name() const override { return make_string("VESPA ARRAY WAND (n=%u)", n); }
- virtual SearchIterator::UP create(const wand::Terms &terms) override {
- return SearchIterator::UP(WeakAndSearch::createArrayWand(terms, n, true));
+ std::string name() const override { return make_string("VESPA ARRAY WAND (n=%u)", n); }
+ SearchIterator::UP create(const wand::Terms &terms) override {
+ return WeakAndSearch::createArrayWand(terms, wand::MatchParams(_scores, 1, 1), wand::TermFrequencyScorer(), n, true);
}
};
VespaArrayWandFactory::~VespaArrayWandFactory() = default;
struct VespaHeapWandFactory : WandFactory {
+ mutable SharedWeakAndPriorityQueue _scores;
uint32_t n;
- VespaHeapWandFactory(uint32_t n_in) : n(n_in) {}
+ explicit VespaHeapWandFactory(uint32_t n_in)
+ : _scores(n_in),
+ n(n_in)
+ {}
~VespaHeapWandFactory() override;
- virtual std::string name() const override { return make_string("VESPA HEAP WAND (n=%u)", n); }
- virtual SearchIterator::UP create(const wand::Terms &terms) override {
- return SearchIterator::UP(WeakAndSearch::createHeapWand(terms, n, true));
+ std::string name() const override { return make_string("VESPA HEAP WAND (n=%u)", n); }
+ SearchIterator::UP create(const wand::Terms &terms) override {
+ return WeakAndSearch::createHeapWand(terms, wand::MatchParams(_scores, 1, 1), wand::TermFrequencyScorer(), n, true);
}
};
@@ -138,39 +150,39 @@ VespaHeapWandFactory::~VespaHeapWandFactory() = default;
struct VespaParallelWandFactory : public WandFactory {
SharedWeakAndPriorityQueue scores;
TermFieldMatchData rootMatchData;
- VespaParallelWandFactory(uint32_t n) : scores(n), rootMatchData() {}
+ explicit VespaParallelWandFactory(uint32_t n) noexcept : scores(n), rootMatchData() {}
~VespaParallelWandFactory() override;
- virtual std::string name() const override { return make_string("VESPA PWAND (n=%u)", scores.getScoresToTrack()); }
- virtual SearchIterator::UP create(const wand::Terms &terms) override {
- return SearchIterator::UP(ParallelWeakAndSearch::create(terms,
+ std::string name() const override { return make_string("VESPA PWAND (n=%u)", scores.getScoresToTrack()); }
+ SearchIterator::UP create(const wand::Terms &terms) override {
+ return ParallelWeakAndSearch::create(terms,
PWMatchParams(scores, 0, 1, 1),
- PWRankParams(rootMatchData, MatchData::UP()), true));
+ PWRankParams(rootMatchData, {}), true);
}
};
VespaParallelWandFactory::~VespaParallelWandFactory() = default;
struct VespaParallelArrayWandFactory : public VespaParallelWandFactory {
- VespaParallelArrayWandFactory(uint32_t n) : VespaParallelWandFactory(n) {}
+ explicit VespaParallelArrayWandFactory(uint32_t n) noexcept : VespaParallelWandFactory(n) {}
~VespaParallelArrayWandFactory() override;
- virtual std::string name() const override { return make_string("VESPA ARRAY PWAND (n=%u)", scores.getScoresToTrack()); }
- virtual SearchIterator::UP create(const wand::Terms &terms) override {
- return SearchIterator::UP(ParallelWeakAndSearch::createArrayWand(terms,
+ std::string name() const override { return make_string("VESPA ARRAY PWAND (n=%u)", scores.getScoresToTrack()); }
+ SearchIterator::UP create(const wand::Terms &terms) override {
+ return ParallelWeakAndSearch::createArrayWand(terms,
PWMatchParams(scores, 0, 1, 1),
- PWRankParams(rootMatchData, MatchData::UP()), true));
+ PWRankParams(rootMatchData, {}), true);
}
};
VespaParallelArrayWandFactory::~VespaParallelArrayWandFactory() = default;
struct VespaParallelHeapWandFactory : public VespaParallelWandFactory {
- VespaParallelHeapWandFactory(uint32_t n) : VespaParallelWandFactory(n) {}
+ explicit VespaParallelHeapWandFactory(uint32_t n) noexcept : VespaParallelWandFactory(n) {}
~VespaParallelHeapWandFactory() override;
- virtual std::string name() const override { return make_string("VESPA HEAP PWAND (n=%u)", scores.getScoresToTrack()); }
- virtual SearchIterator::UP create(const wand::Terms &terms) override {
- return SearchIterator::UP(ParallelWeakAndSearch::createHeapWand(terms,
+ std::string name() const override { return make_string("VESPA HEAP PWAND (n=%u)", scores.getScoresToTrack()); }
+ SearchIterator::UP create(const wand::Terms &terms) override {
+ return ParallelWeakAndSearch::createHeapWand(terms,
PWMatchParams(scores, 0, 1, 1),
- PWRankParams(rootMatchData, MatchData::UP()), true));
+ PWRankParams(rootMatchData, {}), true);
}
};
@@ -178,11 +190,11 @@ VespaParallelHeapWandFactory::~VespaParallelHeapWandFactory() = default;
struct TermFrequencyRiseWandFactory : WandFactory {
uint32_t n;
- TermFrequencyRiseWandFactory(uint32_t n_in) : n(n_in) {}
+ explicit TermFrequencyRiseWandFactory(uint32_t n_in) noexcept : n(n_in) {}
~TermFrequencyRiseWandFactory() override;
- virtual std::string name() const override { return make_string("RISE WAND TF (n=%u)", n); }
- virtual SearchIterator::UP create(const wand::Terms &terms) override {
- return SearchIterator::UP(new rise::TermFrequencyRiseWand(terms, n));
+ std::string name() const override { return make_string("RISE WAND TF (n=%u)", n); }
+ SearchIterator::UP create(const wand::Terms &terms) override {
+ return std::make_unique<rise::TermFrequencyRiseWand>(terms, n);
}
};
@@ -190,11 +202,11 @@ TermFrequencyRiseWandFactory::~TermFrequencyRiseWandFactory() = default;
struct DotProductRiseWandFactory : WandFactory {
uint32_t n;
- DotProductRiseWandFactory(uint32_t n_in) : n(n_in) {}
+ explicit DotProductRiseWandFactory(uint32_t n_in) noexcept : n(n_in) {}
~DotProductRiseWandFactory() override;
- virtual std::string name() const override { return make_string("RISE WAND DP (n=%u)", n); }
- virtual SearchIterator::UP create(const wand::Terms &terms) override {
- return SearchIterator::UP(new rise::DotProductRiseWand(terms, n));
+ std::string name() const override { return make_string("RISE WAND DP (n=%u)", n); }
+ SearchIterator::UP create(const wand::Terms &terms) override {
+ return std::make_unique<rise::DotProductRiseWand>(terms, n);
}
};
@@ -204,13 +216,13 @@ struct FilterFactory : WandFactory {
WandFactory &factory;
Stats stats;
uint32_t n;
- FilterFactory(WandFactory &f, uint32_t n_in) : factory(f), n(n_in) {}
+ FilterFactory(WandFactory &f, uint32_t n_in) noexcept : factory(f), n(n_in) {}
~FilterFactory() override;
- virtual std::string name() const override { return make_string("Filter (mod=%u) [%s]", n, factory.name().c_str()); }
- virtual SearchIterator::UP create(const wand::Terms &terms) override {
+ std::string name() const override { return make_string("Filter (mod=%u) [%s]", n, factory.name().c_str()); }
+ SearchIterator::UP create(const wand::Terms &terms) override {
AndNotSearch::Children children;
children.push_back(factory.create(terms));
- children.emplace_back(new ModSearch(stats, n, search::endDocId, n, NULL));
+ children.emplace_back(new ModSearch(stats, n, search::endDocId, n, nullptr));
return AndNotSearch::create(std::move(children), true);
}
};
@@ -220,8 +232,8 @@ FilterFactory::~FilterFactory() = default;
struct Setup {
Stats stats;
vespalib::duration minTime;
- Setup() : stats(), minTime(10000s) {}
- virtual ~Setup() {}
+ Setup() noexcept : stats(), minTime(10000s) {}
+ virtual ~Setup() = default;
virtual std::string name() const = 0;
virtual SearchIterator::UP create() = 0;
void perform() {
@@ -256,10 +268,10 @@ struct WandSetup : Setup {
MatchData::UP matchData;
WandSetup(WandFactory &f, uint32_t c, uint32_t l) : Setup(), factory(f), childCnt(c), limit(l), weight(100), matchData() {}
~WandSetup() override;
- virtual std::string name() const override {
+ std::string name() const override {
return make_string("Wand Setup (terms=%u,docs=%u) [%s]", childCnt, limit, factory.name().c_str());
}
- virtual SearchIterator::UP create() override {
+ SearchIterator::UP create() override {
MatchDataLayout layout;
std::vector<TermFieldHandle> handles;
for (size_t i = 0; i < childCnt; ++i) {
diff --git a/searchlib/src/tests/queryeval/weak_and/weak_and_test.cpp b/searchlib/src/tests/queryeval/weak_and/weak_and_test.cpp
index 689f9f085d0..4aab66f3cc9 100644
--- a/searchlib/src/tests/queryeval/weak_and/weak_and_test.cpp
+++ b/searchlib/src/tests/queryeval/weak_and/weak_and_test.cpp
@@ -1,8 +1,7 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/searchlib/queryeval/fake_search.h>
#include <vespa/searchlib/queryeval/wand/weak_and_search.h>
+#include <vespa/searchlib/queryeval/wand/weak_and_heap.h>
#include <vespa/searchlib/queryeval/simpleresult.h>
-#include <vespa/searchlib/queryeval/simplesearch.h>
#include <vespa/searchlib/queryeval/test/eagerchild.h>
#include <vespa/searchlib/queryeval/test/leafspec.h>
#include <vespa/searchlib/queryeval/test/wandspec.h>
@@ -20,11 +19,13 @@ namespace {
struct MyWandSpec : public WandSpec
{
+ SharedWeakAndPriorityQueue scores;
uint32_t n;
- MyWandSpec(uint32_t n_) : WandSpec(), n(n_) {}
+ explicit MyWandSpec(uint32_t n_in) : WandSpec(), scores(n_in), n(n_in) {}
SearchIterator *create() {
- return new TrackedSearch("WAND", getHistory(), WeakAndSearch::create(getTerms(), n, true));
+ return new TrackedSearch("WAND", getHistory(),
+ WeakAndSearch::create(getTerms(), wand::MatchParams(scores, 1, 1), n, true));
}
};
@@ -104,7 +105,8 @@ TEST(WeakAndTest, require_that_initial_docid_for_subsearches_are_taken_into_acco
wand::Terms terms;
terms.push_back(wand::Term(new TrackedSearch("foo", history, new EagerChild(search::endDocId)), 100, 1));
terms.push_back(wand::Term(new TrackedSearch("bar", history, new EagerChild(10)), 100, 2));
- SearchIterator::UP search(new TrackedSearch("WAND", history, WeakAndSearch::create(terms, 2, true)));
+ SharedWeakAndPriorityQueue scores(2);
+ auto search = std::make_unique<TrackedSearch>("WAND", history, WeakAndSearch::create(terms, wand::MatchParams(scores), 2, true));
SimpleResult hits;
hits.search(*search);
EXPECT_EQ(SimpleResult().addHit(10), hits);
@@ -114,17 +116,26 @@ TEST(WeakAndTest, require_that_initial_docid_for_subsearches_are_taken_into_acco
}
class IteratorChildrenVerifier : public search::test::IteratorChildrenVerifier {
+public:
+ IteratorChildrenVerifier();
+ ~IteratorChildrenVerifier() override;
private:
+ mutable std::vector<std::unique_ptr<SharedWeakAndPriorityQueue>> _scores;
SearchIterator::UP create(bool strict) const override {
wand::Terms terms;
for (size_t i = 0; i < _num_children; ++i) {
terms.emplace_back(createIterator(_split_lists[i], strict).release(),
100, _split_lists[i].size());
}
- return SearchIterator::UP(WeakAndSearch::create(terms, -1, strict));
+ static constexpr size_t LARGE_ENOUGH_HEAP_FOR_ALL = 10000;
+ _scores.push_back(std::make_unique<SharedWeakAndPriorityQueue>(LARGE_ENOUGH_HEAP_FOR_ALL));
+ return WeakAndSearch::create(terms, wand::MatchParams(*_scores.back(), 1, 1), -1, strict);
}
};
+IteratorChildrenVerifier::IteratorChildrenVerifier() : _scores() {}
+IteratorChildrenVerifier::~IteratorChildrenVerifier() = default;
+
TEST(WeakAndTest, verify_search_iterator_conformance)
{
IteratorChildrenVerifier verifier;
diff --git a/searchlib/src/tests/queryeval/weak_and/weak_and_test_expensive.cpp b/searchlib/src/tests/queryeval/weak_and/weak_and_test_expensive.cpp
index 54bf1e92037..0573404a3b4 100644
--- a/searchlib/src/tests/queryeval/weak_and/weak_and_test_expensive.cpp
+++ b/searchlib/src/tests/queryeval/weak_and/weak_and_test_expensive.cpp
@@ -16,15 +16,16 @@ void checkWandHits(WandFactory &vespa, WandFactory &rise, uint32_t step, uint32_
s1->initFullRange();
SearchIterator::UP s2 = riseSetup.create();
s2->initFullRange();
- ASSERT_TRUE(dynamic_cast<WeakAndType*>(s1.get()) != 0);
- ASSERT_TRUE(dynamic_cast<WeakAndType*>(s2.get()) == 0);
- ASSERT_TRUE(dynamic_cast<RiseType*>(s2.get()) != 0);
- ASSERT_TRUE(dynamic_cast<RiseType*>(s1.get()) == 0);
+ ASSERT_TRUE(dynamic_cast<WeakAndType*>(s1.get()) != nullptr);
+ ASSERT_TRUE(dynamic_cast<WeakAndType*>(s2.get()) == nullptr);
+ ASSERT_TRUE(dynamic_cast<RiseType*>(s2.get()) != nullptr);
+ ASSERT_TRUE(dynamic_cast<RiseType*>(s1.get()) == nullptr);
s1->seek(1);
s2->seek(1);
while (!s1->isAtEnd() &&
!s2->isAtEnd())
{
+ if (s1->getDocId() != s2->getDocId()) assert(true);
ASSERT_EQUAL(s1->getDocId(), s2->getDocId());
if ((filter == 0) || ((s1->getDocId() % filter) != 0)) {
s1->unpack(s1->getDocId());
diff --git a/searchlib/src/tests/queryeval/weak_and_scorers/weak_and_scorers_test.cpp b/searchlib/src/tests/queryeval/weak_and_scorers/weak_and_scorers_test.cpp
index e1f3f0805d9..8a0bc28f4dd 100644
--- a/searchlib/src/tests/queryeval/weak_and_scorers/weak_and_scorers_test.cpp
+++ b/searchlib/src/tests/queryeval/weak_and_scorers/weak_and_scorers_test.cpp
@@ -63,4 +63,27 @@ TEST("require that DotProductScorer calculates term score")
EXPECT_EQUAL(11u, itr->_unpackDocId);
}
+TEST("test bm25 idf scorer for wand")
+{
+ wand::Bm25TermFrequencyScorer scorer(1000000, 1.0);
+ EXPECT_EQUAL(13410046, scorer.calculateMaxScore(1, 1));
+ EXPECT_EQUAL(11464136, scorer.calculateMaxScore(10, 1));
+ EXPECT_EQUAL(6907256, scorer.calculateMaxScore(1000, 1));
+ EXPECT_EQUAL(4605121, scorer.calculateMaxScore(10000, 1));
+ EXPECT_EQUAL(2302581, scorer.calculateMaxScore(100000, 1));
+ EXPECT_EQUAL(693147, scorer.calculateMaxScore(500000, 1));
+ EXPECT_EQUAL(105360, scorer.calculateMaxScore(900000, 1));
+ EXPECT_EQUAL(10050, scorer.calculateMaxScore(990000, 1));
+}
+
+TEST("test limited range of bm25 idf scorer for wand")
+{
+ wand::Bm25TermFrequencyScorer scorer08(1000000, 0.8);
+ wand::Bm25TermFrequencyScorer scorer10(1000000, 1.0);
+ EXPECT_EQUAL(8207814, scorer08.calculateMaxScore(1000, 1));
+ EXPECT_EQUAL(2690049, scorer08.calculateMaxScore(990000, 1));
+ EXPECT_EQUAL(6907256, scorer10.calculateMaxScore(1000, 1));
+ EXPECT_EQUAL(10050, scorer10.calculateMaxScore(990000, 1));
+}
+
TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/searchlib/src/tests/ranksetup/CMakeLists.txt b/searchlib/src/tests/ranksetup/CMakeLists.txt
index d5eb349a6c7..8dc0ea98835 100644
--- a/searchlib/src/tests/ranksetup/CMakeLists.txt
+++ b/searchlib/src/tests/ranksetup/CMakeLists.txt
@@ -4,5 +4,6 @@ vespa_add_executable(searchlib_ranksetup_test_app TEST
ranksetup_test.cpp
DEPENDS
searchlib
+ GTest::gtest
)
vespa_add_test(NAME searchlib_ranksetup_test_app COMMAND searchlib_ranksetup_test_app)
diff --git a/searchlib/src/tests/ranksetup/ranksetup_test.cpp b/searchlib/src/tests/ranksetup/ranksetup_test.cpp
index 53224425a04..a5e7fed5685 100644
--- a/searchlib/src/tests/ranksetup/ranksetup_test.cpp
+++ b/searchlib/src/tests/ranksetup/ranksetup_test.cpp
@@ -1,7 +1,5 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/vespalib/testkit/testapp.h>
-#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/searchlib/common/feature.h>
#include <vespa/searchlib/attribute/attributeguard.h>
@@ -26,6 +24,7 @@
#include <vespa/searchlib/fef/test/rankresult.h>
#include <vespa/searchlib/features/rankingexpressionfeature.h>
+#include <vespa/searchlib/features/second_phase_feature.h>
#include <vespa/searchlib/features/setup.h>
#include <vespa/searchlib/features/valuefeature.h>
#include <vespa/searchlib/fef/test/plugin/chain.h>
@@ -35,6 +34,8 @@
#include <vespa/searchlib/fef/test/plugin/sum.h>
#include <vespa/searchlib/fef/test/plugin/cfgvalue.h>
#include <vespa/searchlib/fef/test/dummy_dependency_handler.h>
+#include <vespa/vespalib/gtest/gtest.h>
+#include <vespa/vespalib/util/stringfmt.h>
#include <iostream>
using namespace search::fef;
@@ -219,9 +220,9 @@ FeatureDumper::dump()
//-----------------------------------------------------------------------------
// RankSetupTest
//-----------------------------------------------------------------------------
-class RankSetupTest : public vespalib::TestApp
+class RankSetupTest : public ::testing::Test
{
-private:
+protected:
BlueprintFactory _factory;
search::AttributeManager _manager;
IndexEnvironment _indexEnv;
@@ -229,14 +230,6 @@ private:
RankEnvironment _rankEnv;
DumpFeatureVisitor _visitor;
- void testValueBlueprint();
- void testDoubleBlueprint();
- void testSumBlueprint();
- void testStaticRankBlueprint();
- void testChainBlueprint();
- void testCfgValueBlueprint();
- void testCompilation();
- void testRankSetup();
bool testExecution(const vespalib::string & initRank, feature_t initScore,
const vespalib::string & finalRank = "", feature_t finalScore = 0.0f, uint32_t docId = 1);
bool testExecution(const RankEnvironment &rankEnv,
@@ -248,15 +241,52 @@ private:
void checkFeatures(std::map<vespalib::string, feature_t> &exp, std::map<vespalib::string, feature_t> &actual);
void testFeatureNormalization();
-public:
RankSetupTest();
- ~RankSetupTest();
- int Main() override;
+ ~RankSetupTest() override;
};
+RankSetupTest::RankSetupTest()
+ : _factory(),
+ _manager(),
+ _indexEnv(),
+ _queryEnv(),
+ _rankEnv(_factory, _indexEnv, _queryEnv),
+ _visitor()
+{
+ // register blueprints
+ setup_fef_test_plugin(_factory);
+ _factory.addPrototype(Blueprint::SP(new ValueBlueprint()));
+ _factory.addPrototype(Blueprint::SP(new RankingExpressionBlueprint()));
+ _factory.addPrototype(std::make_shared<SecondPhaseBlueprint>());
-void
-RankSetupTest::testValueBlueprint()
+ // setup an original attribute manager with two attributes
+ search::attribute::Config cfg(search::attribute::BasicType::INT32,
+ search::attribute::CollectionType::SINGLE);
+ search::AttributeVector::SP av1 =
+ search::AttributeFactory::createAttribute("staticrank1", cfg);
+ search::AttributeVector::SP av2 =
+ search::AttributeFactory::createAttribute("staticrank2", cfg);
+ av1->addDocs(5);
+ av2->addDocs(5);
+ for (uint32_t i = 0; i < 5; ++i) {
+ (static_cast<search::IntegerAttribute *>(av1.get()))->update(i, i + 100);
+ (static_cast<search::IntegerAttribute *>(av2.get()))->update(i, i + 200);
+ }
+ av1->commit();
+ av2->commit();
+ _manager.add(av1);
+ _manager.add(av2);
+
+ // set the index environment
+ _queryEnv.setIndexEnv(&_indexEnv);
+
+ // set the manager
+ _queryEnv.overrideAttributeManager(&_manager);
+}
+
+RankSetupTest::~RankSetupTest() = default;
+
+TEST_F(RankSetupTest, value_blueprint)
{
ValueBlueprint prototype;
prototype.visitDumpFeatures(_indexEnv, _visitor);
@@ -264,22 +294,22 @@ RankSetupTest::testValueBlueprint()
Blueprint::UP bp = prototype.createInstance();
DummyDependencyHandler deps(*bp);
bp->setName("value");
- EXPECT_EQUAL(bp->getName(), "value");
+ EXPECT_EQ(bp->getName(), "value");
std::vector<vespalib::string> params;
params.push_back("5.5");
params.push_back("10.5");
EXPECT_TRUE(bp->setup(_indexEnv, params));
- EXPECT_EQUAL(deps.input.size(), 0u);
- EXPECT_EQUAL(deps.output.size(), 2u);
- EXPECT_EQUAL(deps.output[0], "0");
- EXPECT_EQUAL(deps.output[1], "1");
+ EXPECT_EQ(deps.input.size(), 0u);
+ EXPECT_EQ(deps.output.size(), 2u);
+ EXPECT_EQ(deps.output[0], "0");
+ EXPECT_EQ(deps.output[1], "1");
vespalib::Stash stash;
FeatureExecutor &fe = bp->createExecutor(_queryEnv, stash);
ValueExecutor * vfe = static_cast<ValueExecutor *>(&fe);
- EXPECT_EQUAL(vfe->getValues().size(), 2u);
- EXPECT_EQUAL(vfe->getValues()[0], 5.5f);
- EXPECT_EQUAL(vfe->getValues()[1], 10.5f);
+ EXPECT_EQ(vfe->getValues().size(), 2u);
+ EXPECT_EQ(vfe->getValues()[0], 5.5f);
+ EXPECT_EQ(vfe->getValues()[1], 10.5f);
}
{ // invalid params
Blueprint::UP bp = prototype.createInstance();
@@ -289,8 +319,7 @@ RankSetupTest::testValueBlueprint()
}
}
-void
-RankSetupTest::testDoubleBlueprint()
+TEST_F(RankSetupTest, double_blueprint)
{
DoubleBlueprint prototype;
prototype.visitDumpFeatures(_indexEnv, _visitor);
@@ -301,17 +330,16 @@ RankSetupTest::testDoubleBlueprint()
params.push_back("value(5.5).0");
params.push_back("value(10.5).0");
EXPECT_TRUE(bp->setup(_indexEnv, params));
- EXPECT_EQUAL(deps.input.size(), 2u);
- EXPECT_EQUAL(deps.input[0], "value(5.5).0");
- EXPECT_EQUAL(deps.input[1], "value(10.5).0");
- EXPECT_EQUAL(deps.output.size(), 2u);
- EXPECT_EQUAL(deps.output[0], "0");
- EXPECT_EQUAL(deps.output[1], "1");
+ EXPECT_EQ(deps.input.size(), 2u);
+ EXPECT_EQ(deps.input[0], "value(5.5).0");
+ EXPECT_EQ(deps.input[1], "value(10.5).0");
+ EXPECT_EQ(deps.output.size(), 2u);
+ EXPECT_EQ(deps.output[0], "0");
+ EXPECT_EQ(deps.output[1], "1");
}
}
-void
-RankSetupTest::testSumBlueprint()
+TEST_F(RankSetupTest, sum_blueprint)
{
SumBlueprint prototype;
prototype.visitDumpFeatures(_indexEnv, _visitor);
@@ -322,16 +350,15 @@ RankSetupTest::testSumBlueprint()
params.push_back("value(5.5, 10.5).0");
params.push_back("value(5.5, 10.5).1");
EXPECT_TRUE(bp->setup(_indexEnv, params));
- EXPECT_EQUAL(deps.input.size(), 2u);
- EXPECT_EQUAL(deps.input[0], "value(5.5, 10.5).0");
- EXPECT_EQUAL(deps.input[1], "value(5.5, 10.5).1");
- EXPECT_EQUAL(deps.output.size(), 1u);
- EXPECT_EQUAL(deps.output[0], "out");
+ EXPECT_EQ(deps.input.size(), 2u);
+ EXPECT_EQ(deps.input[0], "value(5.5, 10.5).0");
+ EXPECT_EQ(deps.input[1], "value(5.5, 10.5).1");
+ EXPECT_EQ(deps.output.size(), 1u);
+ EXPECT_EQ(deps.output[0], "out");
}
}
-void
-RankSetupTest::testStaticRankBlueprint()
+TEST_F(RankSetupTest, static_rank_blueprint)
{
StaticRankBlueprint prototype;
{ // basic test
@@ -340,9 +367,9 @@ RankSetupTest::testStaticRankBlueprint()
std::vector<vespalib::string> params;
params.push_back("sr1");
EXPECT_TRUE(bp->setup(_indexEnv, params));
- EXPECT_EQUAL(deps.input.size(), 0u);
- EXPECT_EQUAL(deps.output.size(), 1u);
- EXPECT_EQUAL(deps.output[0], "out");
+ EXPECT_EQ(deps.input.size(), 0u);
+ EXPECT_EQ(deps.output.size(), 1u);
+ EXPECT_EQ(deps.output[0], "out");
}
{ // invalid params
Blueprint::UP bp = prototype.createInstance();
@@ -355,8 +382,7 @@ RankSetupTest::testStaticRankBlueprint()
}
}
-void
-RankSetupTest::testChainBlueprint()
+TEST_F(RankSetupTest, chain_blueprint)
{
ChainBlueprint prototype;
{ // chaining
@@ -367,8 +393,8 @@ RankSetupTest::testChainBlueprint()
params.push_back("2");
params.push_back("4");
EXPECT_TRUE(bp->setup(_indexEnv, params));
- EXPECT_EQUAL(deps.input.size(), 1u);
- EXPECT_EQUAL(deps.input[0], "chain(basic,1,4)");
+ EXPECT_EQ(deps.input.size(), 1u);
+ EXPECT_EQ(deps.input[0], "chain(basic,1,4)");
}
{ // leaf node
Blueprint::UP bp = prototype.createInstance();
@@ -378,8 +404,8 @@ RankSetupTest::testChainBlueprint()
params.push_back("1");
params.push_back("4");
EXPECT_TRUE(bp->setup(_indexEnv, params));
- EXPECT_EQUAL(deps.input.size(), 1u);
- EXPECT_EQUAL(deps.input[0], "value(4)");
+ EXPECT_EQ(deps.input.size(), 1u);
+ EXPECT_EQ(deps.input[0], "value(4)");
}
{ // cycle
Blueprint::UP bp = prototype.createInstance();
@@ -389,8 +415,8 @@ RankSetupTest::testChainBlueprint()
params.push_back("1");
params.push_back("4");
EXPECT_TRUE(bp->setup(_indexEnv, params));
- EXPECT_EQUAL(deps.input.size(), 1u);
- EXPECT_EQUAL(deps.input[0], "chain(cycle,4,4)");
+ EXPECT_EQ(deps.input.size(), 1u);
+ EXPECT_EQ(deps.input[0], "chain(cycle,4,4)");
}
{ // invalid params
Blueprint::UP bp = prototype.createInstance();
@@ -404,8 +430,7 @@ RankSetupTest::testChainBlueprint()
}
}
-void
-RankSetupTest::testCfgValueBlueprint()
+TEST_F(RankSetupTest, cfg_value_blueprint)
{
CfgValueBlueprint prototype;
IndexEnvironment indexEnv;
@@ -421,25 +446,23 @@ RankSetupTest::testCfgValueBlueprint()
params.push_back("foo");
EXPECT_TRUE(bp->setup(indexEnv, params));
- EXPECT_EQUAL(deps.input.size(), 0u);
- EXPECT_EQUAL(deps.output.size(), 3u);
- EXPECT_EQUAL(deps.output[0], "0");
- EXPECT_EQUAL(deps.output[1], "1");
- EXPECT_EQUAL(deps.output[2], "2");
+ EXPECT_EQ(deps.input.size(), 0u);
+ EXPECT_EQ(deps.output.size(), 3u);
+ EXPECT_EQ(deps.output[0], "0");
+ EXPECT_EQ(deps.output[1], "1");
+ EXPECT_EQ(deps.output[2], "2");
vespalib::Stash stash;
FeatureExecutor &fe = bp->createExecutor(_queryEnv, stash);
ValueExecutor *vfe = static_cast<ValueExecutor *>(&fe);
- EXPECT_EQUAL(vfe->getValues().size(), 3u);
- EXPECT_EQUAL(vfe->getValues()[0], 1.0f);
- EXPECT_EQUAL(vfe->getValues()[1], 2.0f);
- EXPECT_EQUAL(vfe->getValues()[2], 3.0f);
+ EXPECT_EQ(vfe->getValues().size(), 3u);
+ EXPECT_EQ(vfe->getValues()[0], 1.0f);
+ EXPECT_EQ(vfe->getValues()[1], 2.0f);
+ EXPECT_EQ(vfe->getValues()[2], 3.0f);
}
}
-
-void
-RankSetupTest::testCompilation()
+TEST_F(RankSetupTest, compilation)
{
{ // unknown blueprint
RankSetup rs(_factory, _indexEnv);
@@ -498,7 +521,7 @@ RankSetupTest::testCompilation()
}
}
-void RankSetupTest::testRankSetup()
+TEST_F(RankSetupTest, rank_setup)
{
using namespace search::fef::indexproperties;
IndexEnvironment env;
@@ -524,7 +547,8 @@ void RankSetupTest::testRankSetup()
env.getProperties().add(hitcollector::ArraySize::NAME, "60");
env.getProperties().add(hitcollector::EstimatePoint::NAME, "70");
env.getProperties().add(hitcollector::EstimateLimit::NAME, "80");
- env.getProperties().add(hitcollector::RankScoreDropLimit::NAME, "90.5");
+ env.getProperties().add(hitcollector::FirstPhaseRankScoreDropLimit::NAME, "90.5");
+ env.getProperties().add(hitcollector::SecondPhaseRankScoreDropLimit::NAME, "91.5");
env.getProperties().add(mutate::on_match::Attribute::NAME, "a");
env.getProperties().add(mutate::on_match::Operation::NAME, "+=3");
env.getProperties().add(mutate::on_first_phase::Attribute::NAME, "b");
@@ -541,44 +565,45 @@ void RankSetupTest::testRankSetup()
RankSetup rs(_factory, env);
EXPECT_FALSE(rs.has_match_features());
rs.configure();
- EXPECT_EQUAL(rs.getFirstPhaseRank(), vespalib::string("firstphase"));
- EXPECT_EQUAL(rs.getSecondPhaseRank(), vespalib::string("secondphase"));
+ EXPECT_EQ(rs.getFirstPhaseRank(), vespalib::string("firstphase"));
+ EXPECT_EQ(rs.getSecondPhaseRank(), vespalib::string("secondphase"));
EXPECT_TRUE(rs.has_match_features());
ASSERT_TRUE(rs.get_match_features().size() == 2);
- EXPECT_EQUAL(rs.get_match_features()[0], vespalib::string("match_foo"));
- EXPECT_EQUAL(rs.get_match_features()[1], vespalib::string("match_bar"));
+ EXPECT_EQ(rs.get_match_features()[0], vespalib::string("match_foo"));
+ EXPECT_EQ(rs.get_match_features()[1], vespalib::string("match_bar"));
ASSERT_TRUE(rs.getDumpFeatures().size() == 2);
- EXPECT_EQUAL(rs.getDumpFeatures()[0], vespalib::string("foo"));
- EXPECT_EQUAL(rs.getDumpFeatures()[1], vespalib::string("bar"));
- EXPECT_EQUAL(rs.getNumThreadsPerSearch(), 3u);
- EXPECT_EQUAL(rs.getMinHitsPerThread(), 8u);
- EXPECT_EQUAL(rs.getDegradationAttribute(), "mystaticrankattr");
- EXPECT_EQUAL(rs.isDegradationOrderAscending(), true);
- EXPECT_EQUAL(rs.getDegradationMaxHits(), 12345u);
- EXPECT_EQUAL(rs.getDegradationSamplePercentage(), 0.9);
- EXPECT_EQUAL(rs.getDegradationMaxFilterCoverage(), 0.19);
- EXPECT_EQUAL(rs.getDegradationPostFilterMultiplier(), 0.7);
- EXPECT_EQUAL(rs.getDiversityAttribute(), "mycategoryattr");
- EXPECT_EQUAL(rs.getDiversityMinGroups(), 37u);
- EXPECT_EQUAL(rs.getDiversityCutoffFactor(), 7.1);
- EXPECT_EQUAL(rs.getDiversityCutoffStrategy(), "strict");
- EXPECT_EQUAL(rs.getHeapSize(), 50u);
- EXPECT_EQUAL(rs.getArraySize(), 60u);
- EXPECT_EQUAL(rs.getEstimatePoint(), 70u);
- EXPECT_EQUAL(rs.getEstimateLimit(), 80u);
- EXPECT_EQUAL(rs.getRankScoreDropLimit(), 90.5);
- EXPECT_EQUAL(rs.getMutateOnMatch()._attribute, "a");
- EXPECT_EQUAL(rs.getMutateOnMatch()._operation, "+=3");
- EXPECT_EQUAL(rs.getMutateOnFirstPhase()._attribute, "b");
- EXPECT_EQUAL(rs.getMutateOnFirstPhase()._operation, "=3");
- EXPECT_EQUAL(rs.getMutateOnSecondPhase()._attribute, "b");
- EXPECT_EQUAL(rs.getMutateOnSecondPhase()._operation, "=7");
- EXPECT_EQUAL(rs.getMutateOnSummary()._attribute, "c");
- EXPECT_EQUAL(rs.getMutateOnSummary()._operation, "-=2");
- EXPECT_EQUAL(rs.get_global_filter_lower_limit(), 0.3);
- EXPECT_EQUAL(rs.get_global_filter_upper_limit(), 0.7);
- EXPECT_EQUAL(rs.get_target_hits_max_adjustment_factor(), 5.0);
- EXPECT_EQUAL(rs.get_fuzzy_matching_algorithm(), vespalib::FuzzyMatchingAlgorithm::DfaImplicit);
+ EXPECT_EQ(rs.getDumpFeatures()[0], vespalib::string("foo"));
+ EXPECT_EQ(rs.getDumpFeatures()[1], vespalib::string("bar"));
+ EXPECT_EQ(rs.getNumThreadsPerSearch(), 3u);
+ EXPECT_EQ(rs.getMinHitsPerThread(), 8u);
+ EXPECT_EQ(rs.getDegradationAttribute(), "mystaticrankattr");
+ EXPECT_EQ(rs.isDegradationOrderAscending(), true);
+ EXPECT_EQ(rs.getDegradationMaxHits(), 12345u);
+ EXPECT_EQ(rs.getDegradationSamplePercentage(), 0.9);
+ EXPECT_EQ(rs.getDegradationMaxFilterCoverage(), 0.19);
+ EXPECT_EQ(rs.getDegradationPostFilterMultiplier(), 0.7);
+ EXPECT_EQ(rs.getDiversityAttribute(), "mycategoryattr");
+ EXPECT_EQ(rs.getDiversityMinGroups(), 37u);
+ EXPECT_EQ(rs.getDiversityCutoffFactor(), 7.1);
+ EXPECT_EQ(rs.getDiversityCutoffStrategy(), "strict");
+ EXPECT_EQ(rs.getHeapSize(), 50u);
+ EXPECT_EQ(rs.getArraySize(), 60u);
+ EXPECT_EQ(rs.getEstimatePoint(), 70u);
+ EXPECT_EQ(rs.getEstimateLimit(), 80u);
+ EXPECT_EQ(std::optional<feature_t>(90.5), rs.get_first_phase_rank_score_drop_limit());
+ EXPECT_EQ(std::optional<feature_t>(91.5), rs.get_second_phase_rank_score_drop_limit());
+ EXPECT_EQ(rs.getMutateOnMatch()._attribute, "a");
+ EXPECT_EQ(rs.getMutateOnMatch()._operation, "+=3");
+ EXPECT_EQ(rs.getMutateOnFirstPhase()._attribute, "b");
+ EXPECT_EQ(rs.getMutateOnFirstPhase()._operation, "=3");
+ EXPECT_EQ(rs.getMutateOnSecondPhase()._attribute, "b");
+ EXPECT_EQ(rs.getMutateOnSecondPhase()._operation, "=7");
+ EXPECT_EQ(rs.getMutateOnSummary()._attribute, "c");
+ EXPECT_EQ(rs.getMutateOnSummary()._operation, "-=2");
+ EXPECT_EQ(rs.get_global_filter_lower_limit(), 0.3);
+ EXPECT_EQ(rs.get_global_filter_upper_limit(), 0.7);
+ EXPECT_EQ(rs.get_target_hits_max_adjustment_factor(), 5.0);
+ EXPECT_EQ(rs.get_fuzzy_matching_algorithm(), vespalib::FuzzyMatchingAlgorithm::DfaImplicit);
}
bool
@@ -603,12 +628,11 @@ RankSetupTest::testExecution(const RankEnvironment &rankEnv, const vespalib::str
}
RankResult rs = re.execute(docId);
ok = ok && (exp == rs);
- EXPECT_EQUAL(exp, rs);
+ EXPECT_EQ(exp, rs);
return ok;
}
-void
-RankSetupTest::testExecution()
+TEST_F(RankSetupTest, execution)
{
{ // value executor
vespalib::string v = FNB().baseName("value").parameter("5.5").parameter("10.5").buildName();
@@ -698,8 +722,7 @@ RankSetupTest::testExecution()
}
}
-void
-RankSetupTest::testFeatureDump()
+TEST_F(RankSetupTest, feature_dump)
{
{
FeatureDumper dumper(_rankEnv);
@@ -721,7 +744,7 @@ RankSetupTest::testFeatureDump()
parameter(FNB().baseName("double").parameter("value(8)").buildName()).
parameter(FNB().baseName("double").parameter("value(32)").buildName()).
buildName(), 80.0f);
- EXPECT_EQUAL(exp, dumper.dump());
+ EXPECT_EQ(exp, dumper.dump());
}
{
FeatureDumper dumper(_rankEnv);
@@ -731,7 +754,7 @@ RankSetupTest::testFeatureDump()
RankResult exp;
exp.addScore("value(50)", 50.0f);
exp.addScore("value(100)", 100.0f);
- EXPECT_EQUAL(exp, dumper.dump());
+ EXPECT_EQ(exp, dumper.dump());
}
{
FeatureDumper dumper(_rankEnv);
@@ -739,7 +762,7 @@ RankSetupTest::testFeatureDump()
EXPECT_TRUE(dumper.setup());
RankResult exp;
exp.addScore(FNB().baseName("rankingExpression").parameter("if(4<2,3,4)").buildName(), 4.0f);
- EXPECT_EQUAL(exp, dumper.dump());
+ EXPECT_EQ(exp, dumper.dump());
}
{
@@ -748,7 +771,7 @@ RankSetupTest::testFeatureDump()
EXPECT_TRUE(dumper.setup());
RankResult exp;
exp.addScore(FNB().baseName("rankingExpression").parameter("if(mysum(value(12),value(10))>2,3,4)").buildName(), 3.0f);
- EXPECT_EQUAL(exp, dumper.dump());
+ EXPECT_EQ(exp, dumper.dump());
}
{ // dump features indicated by visitation
IndexEnvironment indexEnv;
@@ -766,7 +789,7 @@ RankSetupTest::testFeatureDump()
RankResult exp;
exp.addScore("test_cfgvalue(foo)", 1.0);
exp.addScore("test_cfgvalue(bar)", 5.0);
- EXPECT_EQUAL(exp, dumper.dump());
+ EXPECT_EQ(exp, dumper.dump());
}
{ // ignore features indicated by visitation
IndexEnvironment indexEnv;
@@ -785,7 +808,20 @@ RankSetupTest::testFeatureDump()
EXPECT_TRUE(dumper.setup());
RankResult exp;
exp.addScore("test_cfgvalue(foo)", 1.0);
- EXPECT_EQUAL(exp, dumper.dump());
+ EXPECT_EQ(exp, dumper.dump());
+ }
+ { // Dump secondPhase feature
+ IndexEnvironment indexEnv;
+ indexEnv.getProperties().add(indexproperties::rank::FirstPhase::NAME, "value(2)");
+ indexEnv.getProperties().add(indexproperties::rank::SecondPhase::NAME, "value(4)");
+ RankEnvironment rankEnv(_factory, indexEnv, _queryEnv);
+ FeatureDumper dumper(rankEnv);
+ dumper.configure();
+ dumper.addDumpFeature("secondPhase");
+ EXPECT_TRUE(dumper.setup());
+ RankResult exp;
+ exp.addScore("secondPhase", 4.0);
+ EXPECT_EQ(exp, dumper.dump());
}
}
@@ -793,22 +829,19 @@ void
RankSetupTest::checkFeatures(std::map<vespalib::string, feature_t> &exp, std::map<vespalib::string, feature_t> &actual)
{
using ITR = std::map<vespalib::string, feature_t>::const_iterator;
- if (!EXPECT_EQUAL(exp.size(), actual.size())) {
- return;
- }
+ ASSERT_EQ(exp.size(), actual.size());
ITR exp_itr = exp.begin();
ITR exp_end = exp.end();
ITR actual_itr = actual.begin();
ITR actual_end = actual.end();
for (; exp_itr != exp_end && actual_itr != actual_end; ++exp_itr, ++actual_itr) {
- EXPECT_EQUAL(exp_itr->first, actual_itr->first);
- EXPECT_APPROX(exp_itr->second, actual_itr->second, 0.001);
+ EXPECT_EQ(exp_itr->first, actual_itr->first);
+ EXPECT_NEAR(exp_itr->second, actual_itr->second, 0.001);
}
- EXPECT_EQUAL(exp_itr == exp_end, actual_itr == actual_end);
+ EXPECT_EQ(exp_itr == exp_end, actual_itr == actual_end);
}
-void
-RankSetupTest::testFeatureNormalization()
+TEST_F(RankSetupTest, feature_normalization)
{
BlueprintFactory factory;
factory.addPrototype(Blueprint::SP(new ValueBlueprint()));
@@ -841,35 +874,39 @@ RankSetupTest::testFeatureNormalization()
match_program->setup(*match_data, queryEnv);
summaryProgram->setup(*match_data, queryEnv);
- EXPECT_APPROX(2.0, Utils::getScoreFeature(*firstPhaseProgram, 1), 0.001);
- EXPECT_APPROX(4.0, Utils::getScoreFeature(*secondPhaseProgram, 1), 0.001);
+ EXPECT_NEAR(2.0, Utils::getScoreFeature(*firstPhaseProgram, 1), 0.001);
+ EXPECT_NEAR(4.0, Utils::getScoreFeature(*secondPhaseProgram, 1), 0.001);
- { // rank seed features
+ {
+ SCOPED_TRACE("rank seed features");
std::map<vespalib::string, feature_t> actual = Utils::getSeedFeatures(*summaryProgram, 1);
std::map<vespalib::string, feature_t> exp;
exp["mysum(value(5),value(5))"] = 10.0;
exp["mysum(\"value( 5 )\",\"value( 5 )\")"] = 10.0;
- TEST_DO(checkFeatures(exp, actual));
+ checkFeatures(exp, actual);
}
- { // all rank features (1. phase)
+ {
+ SCOPED_TRACE("all rank features (1. phase)");
std::map<vespalib::string, feature_t> actual = Utils::getAllFeatures(*firstPhaseProgram, 1);
std::map<vespalib::string, feature_t> exp;
exp["value(1)"] = 1.0;
exp["value(1).0"] = 1.0;
exp["mysum(value(1),value(1))"] = 2.0;
exp["mysum(value(1),value(1)).out"] = 2.0;
- TEST_DO(checkFeatures(exp, actual));
+ checkFeatures(exp, actual);
}
- { // all rank features (2. phase)
+ {
+ SCOPED_TRACE("all rank features (2. phase)");
std::map<vespalib::string, feature_t> actual = Utils::getAllFeatures(*secondPhaseProgram, 1);
std::map<vespalib::string, feature_t> exp;
exp["value(2)"] = 2.0;
exp["value(2).0"] = 2.0;
exp["mysum(value(2),value(2))"] = 4.0;
exp["mysum(value(2),value(2)).out"] = 4.0;
- TEST_DO(checkFeatures(exp, actual));
+ checkFeatures(exp, actual);
}
- { // all match features
+ {
+ SCOPED_TRACE("all match features");
std::map<vespalib::string, feature_t> actual = Utils::getAllFeatures(*match_program, 1);
std::map<vespalib::string, feature_t> exp;
exp["value(3)"] = 3.0;
@@ -878,9 +915,10 @@ RankSetupTest::testFeatureNormalization()
exp["mysum(value(3),value(3)).out"] = 6.0;
exp["mysum(\"value( 3 )\",\"value( 3 )\")"] = 6.0;
exp["mysum(\"value( 3 )\",\"value( 3 )\").out"] = 6.0;
- TEST_DO(checkFeatures(exp, actual));
+ checkFeatures(exp, actual);
}
- { // all rank features (summary)
+ {
+ SCOPED_TRACE("all rank features (summary)");
std::map<vespalib::string, feature_t> actual = Utils::getAllFeatures(*summaryProgram, 1);
std::map<vespalib::string, feature_t> exp;
exp["value(5)"] = 5.0;
@@ -889,7 +927,7 @@ RankSetupTest::testFeatureNormalization()
exp["mysum(value(5),value(5)).out"] = 10.0;
exp["mysum(\"value( 5 )\",\"value( 5 )\")"] = 10.0;
exp["mysum(\"value( 5 )\",\"value( 5 )\").out"] = 10.0;
- TEST_DO(checkFeatures(exp, actual));
+ checkFeatures(exp, actual);
}
}
@@ -900,15 +938,17 @@ RankSetupTest::testFeatureNormalization()
RankProgram::UP rankProgram = rankSetup.create_dump_program();
rankProgram->setup(*match_data, queryEnv);
- { // dump seed features
+ {
+ SCOPED_TRACE("dump seed features");
std::map<vespalib::string, feature_t> actual = Utils::getSeedFeatures(*rankProgram, 1);
std::map<vespalib::string, feature_t> exp;
exp["mysum(value(10),value(10))"] = 20.0;
exp["mysum(\"value( 10 )\",\"value( 10 )\")"] = 20.0;
- TEST_DO(checkFeatures(exp, actual));
+ checkFeatures(exp, actual);
}
- { // all dump features
+ {
+ SCOPED_TRACE("all dump features");
std::map<vespalib::string, feature_t> actual = Utils::getAllFeatures(*rankProgram, 1);
std::map<vespalib::string, feature_t> exp;
@@ -921,71 +961,9 @@ RankSetupTest::testFeatureNormalization()
exp["mysum(\"value( 10 )\",\"value( 10 )\")"] = 20.0;
exp["mysum(\"value( 10 )\",\"value( 10 )\").out"] = 20.0;
- TEST_DO(checkFeatures(exp, actual));
+ checkFeatures(exp, actual);
}
}
}
-
-RankSetupTest::RankSetupTest() :
- _factory(),
- _manager(),
- _indexEnv(),
- _queryEnv(),
- _rankEnv(_factory, _indexEnv, _queryEnv),
- _visitor()
-{
- // register blueprints
- setup_fef_test_plugin(_factory);
- _factory.addPrototype(Blueprint::SP(new ValueBlueprint()));
- _factory.addPrototype(Blueprint::SP(new RankingExpressionBlueprint()));
-
- // setup an original attribute manager with two attributes
- search::attribute::Config cfg(search::attribute::BasicType::INT32,
- search::attribute::CollectionType::SINGLE);
- search::AttributeVector::SP av1 =
- search::AttributeFactory::createAttribute("staticrank1", cfg);
- search::AttributeVector::SP av2 =
- search::AttributeFactory::createAttribute("staticrank2", cfg);
- av1->addDocs(5);
- av2->addDocs(5);
- for (uint32_t i = 0; i < 5; ++i) {
- (static_cast<search::IntegerAttribute *>(av1.get()))->update(i, i + 100);
- (static_cast<search::IntegerAttribute *>(av2.get()))->update(i, i + 200);
- }
- av1->commit();
- av2->commit();
- _manager.add(av1);
- _manager.add(av2);
-
- // set the index environment
- _queryEnv.setIndexEnv(&_indexEnv);
-
- // set the manager
- _queryEnv.overrideAttributeManager(&_manager);
-}
-
-RankSetupTest::~RankSetupTest() {}
-
-int
-RankSetupTest::Main()
-{
- TEST_INIT("ranksetup_test");
-
- testValueBlueprint();
- testDoubleBlueprint();
- testSumBlueprint();
- testStaticRankBlueprint();
- testChainBlueprint();
- testCfgValueBlueprint();
-
- testCompilation();
- testRankSetup();
- testExecution();
- testFeatureDump();
- testFeatureNormalization();
-
- TEST_DONE();
-}
-
-TEST_APPHOOK(RankSetupTest);
+GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/searchlib/src/tests/sort/CMakeLists.txt b/searchlib/src/tests/sort/CMakeLists.txt
index 44ecff7c1a4..9c7b781c232 100644
--- a/searchlib/src/tests/sort/CMakeLists.txt
+++ b/searchlib/src/tests/sort/CMakeLists.txt
@@ -21,5 +21,6 @@ vespa_add_executable(searchlib_uca_stress_app
uca.cpp
DEPENDS
searchlib
+ GTest::gtest
)
vespa_add_test(NAME searchlib_uca_stress_app COMMAND searchlib_uca_stress_app BENCHMARK)
diff --git a/searchlib/src/tests/sort/uca.cpp b/searchlib/src/tests/sort/uca.cpp
index d11d230142b..41f6b927990 100644
--- a/searchlib/src/tests/sort/uca.cpp
+++ b/searchlib/src/tests/sort/uca.cpp
@@ -1,27 +1,17 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/vespalib/testkit/testapp.h>
+
#include <vespa/searchlib/common/sort.h>
#include <vespa/searchlib/common/sortspec.h>
+#include <vespa/vespalib/gtest/gtest.h>
#include <vespa/vespalib/util/array.h>
#include <unicode/ustring.h>
#include <unicode/coll.h>
#include <fcntl.h>
#include <unistd.h>
-#include <vespa/log/log.h>
-LOG_SETUP("uca_stress");
-
using icu::Collator;
-class Test : public vespalib::TestApp
-{
-public:
- int Main() override;
- void testFromDat();
-};
-
-
-void Test::testFromDat()
+TEST(UcaStressTest, from_dat)
{
size_t badnesses = 0;
@@ -40,8 +30,6 @@ void Test::testFromDat()
int fd = open("sort-blobs.dat", O_RDONLY);
char sbuf[4];
- int num=0;
-
uint32_t atleast = 0;
while (read(fd, sbuf, 4) == 4) {
@@ -49,20 +37,20 @@ void Test::testFromDat()
uint32_t len = 0;
int r = read(fd, &len, 4);
- EXPECT_EQUAL(4, r);
+ EXPECT_EQ(4, r);
r = read(fd, sbuf, 4);
- EXPECT_EQUAL(4, r);
- EXPECT_EQUAL(midMark, sbuf);
+ EXPECT_EQ(4, r);
+ EXPECT_EQ(midMark, sbuf);
if (u16buffer.size() < len) {
u16buffer.resize(len);
}
r = read(fd, &u16buffer[0], len*2);
- EXPECT_EQUAL((int)len*2, r);
+ EXPECT_EQ((int)len*2, r);
r = read(fd, sbuf, 4);
- EXPECT_EQUAL(4, r);
- EXPECT_EQUAL(endMark, sbuf);
+ EXPECT_EQ(4, r);
+ EXPECT_EQ(endMark, sbuf);
uint32_t wanted = coll->getSortKey(&u16buffer[0], len, NULL, 0);
@@ -77,7 +65,7 @@ void Test::testFromDat()
for (uint32_t pretend = 1; pretend < wanted+8; ++pretend) {
memset(&u8buffer[0], 0x99, u8buffer.size());
uint32_t got = coll->getSortKey(&u16buffer[0], len, &u8buffer[0], pretend);
- EXPECT_EQUAL(wanted, got);
+ EXPECT_EQ(wanted, got);
if (u8buffer[pretend+1] != 0x99) {
printf("wrote 2 bytes too far: wanted space %d, pretend allocated %d, last good=%02x, bad=%02x %02x\n",
@@ -95,24 +83,13 @@ void Test::testFromDat()
memset(&u8buffer[0], 0x99, u8buffer.size());
uint32_t got = coll->getSortKey(&u16buffer[0], len, &u8buffer[0], u8buffer.size());
- EXPECT_EQUAL(wanted, got);
+ EXPECT_EQ(wanted, got);
- EXPECT_EQUAL('\0', u8buffer[got-1]);
- EXPECT_EQUAL((uint8_t)0x99, u8buffer[got]);
- }
- if (++num >= 10000) {
- TEST_FLUSH();
- num=0;
+ EXPECT_EQ('\0', u8buffer[got-1]);
+ EXPECT_EQ((uint8_t)0x99, u8buffer[got]);
}
}
- EXPECT_EQUAL(0u, badnesses);
+ EXPECT_EQ(0u, badnesses);
}
-TEST_APPHOOK(Test);
-
-int Test::Main()
-{
- TEST_INIT("uca_stress");
- testFromDat();
- TEST_DONE();
-}
+GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/searchlib/src/tests/tensor/distance_calculator/distance_calculator_test.cpp b/searchlib/src/tests/tensor/distance_calculator/distance_calculator_test.cpp
index 4ffc1fe366e..136878f0ea5 100644
--- a/searchlib/src/tests/tensor/distance_calculator/distance_calculator_test.cpp
+++ b/searchlib/src/tests/tensor/distance_calculator/distance_calculator_test.cpp
@@ -9,7 +9,6 @@
#include <vespa/searchlib/test/attribute_builder.h>
#include <vespa/vespalib/gtest/gtest.h>
#include <vespa/vespalib/util/exceptions.h>
-#include <iostream>
using namespace search::attribute::test;
using namespace search::attribute;
diff --git a/searchlib/src/tests/tensor/distance_functions/CMakeLists.txt b/searchlib/src/tests/tensor/distance_functions/CMakeLists.txt
index e1a54f7883a..92ad9ae2648 100644
--- a/searchlib/src/tests/tensor/distance_functions/CMakeLists.txt
+++ b/searchlib/src/tests/tensor/distance_functions/CMakeLists.txt
@@ -7,3 +7,10 @@ vespa_add_executable(searchlib_distance_functions_test_app TEST
GTest::GTest
)
vespa_add_test(NAME searchlib_distance_functions_test_app COMMAND searchlib_distance_functions_test_app)
+
+vespa_add_executable(searchlib_distance_functions_benchmark_app TEST
+ SOURCES
+ distance_functions_benchmark.cpp
+ DEPENDS
+ searchlib
+)
diff --git a/searchlib/src/tests/tensor/distance_functions/distance_functions_benchmark.cpp b/searchlib/src/tests/tensor/distance_functions/distance_functions_benchmark.cpp
new file mode 100644
index 00000000000..0cb75075f5e
--- /dev/null
+++ b/searchlib/src/tests/tensor/distance_functions/distance_functions_benchmark.cpp
@@ -0,0 +1,133 @@
+// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/eval/eval/typed_cells.h>
+#include <vespa/searchlib/common/geo_gcd.h>
+#include <vespa/searchlib/tensor/distance_functions.h>
+#include <vespa/searchlib/tensor/distance_function_factory.h>
+#include <vespa/searchlib/tensor/mips_distance_transform.h>
+#include <vespa/vespalib/util/benchmark_timer.h>
+#include <vespa/vespalib/util/classname.h>
+
+using namespace search::tensor;
+using vespalib::eval::Int8Float;
+using vespalib::BFloat16;
+using vespalib::eval::TypedCells;
+using search::attribute::DistanceMetric;
+
+size_t npos = std::string::npos;
+
+double run_calc(size_t iterations, TypedCells b, const BoundDistanceFunction & df) __attribute__((noinline));
+double run_calc_with_limit(size_t iterations, TypedCells b, const BoundDistanceFunction & df) __attribute__((noinline));
+
+double
+run_calc(size_t iterations, TypedCells b, const BoundDistanceFunction & df) {
+ vespalib::BenchmarkTimer timer(1.0);
+ double min_result = std::numeric_limits<double>::max();
+ while (timer.has_budget()) {
+ timer.before();
+ for (size_t i(0); i < iterations; i++) {
+ min_result = std::min(df.calc(b), min_result);
+ }
+ timer.after();
+ }
+ printf("%s::calc: Time used = %1.3f, min_result=%3.3f\n",
+ vespalib::getClassName(df).c_str(), timer.min_time(), min_result);
+ return min_result;
+}
+
+double
+run_calc_with_limit(size_t iterations, TypedCells b, const BoundDistanceFunction & df) {
+ vespalib::BenchmarkTimer timer(1.0);
+ double min_result = std::numeric_limits<double>::max();
+ while (timer.has_budget()) {
+ timer.before();
+ for (size_t i(0); i < iterations; i++) {
+ min_result = std::min(df.calc_with_limit(b, std::numeric_limits<double>::max()), min_result);
+ }
+ timer.after();
+ }
+
+ printf("%s::calc_with_limit: Time used = %1.3f, min_result=%3.3f\n",
+ vespalib::getClassName(df).c_str(), timer.min_time(), min_result);
+ return min_result;
+}
+
+template<typename T>
+void benchmark(size_t iterations, size_t elems) __attribute__((noinline));
+
+template<typename T>
+void benchmark(size_t iterations, size_t elems, const DistanceFunctionFactory & df) {
+ std::vector<T> av, bv;
+ srandom(7);
+ av.reserve(elems);
+ bv.reserve(elems);
+ for (size_t i(0); i < elems; i++) {
+ av.push_back(random()%128);
+ bv.push_back(random()%128);
+ }
+ TypedCells a_cells(av), b_cells(bv);
+
+ double calc_result = run_calc(iterations, b_cells, *df.for_query_vector(a_cells));
+ double calc_with_limit_result = run_calc_with_limit(iterations, b_cells, *df.for_query_vector(a_cells));
+ assert(calc_result == calc_with_limit_result);
+}
+
+template<typename T>
+void benchmark(size_t iterations, size_t elems, const std::string & dist_functions) {
+ if (dist_functions.find("euclid") != npos) {
+ if constexpr ( ! std::is_same<T, BFloat16>()) {
+ benchmark<T>(iterations, elems, EuclideanDistanceFunctionFactory<T>());
+ } else {
+ benchmark<BFloat16>(iterations, elems, EuclideanDistanceFunctionFactory<float>());
+ }
+ }
+ if (dist_functions.find("angular") != npos) {
+ if constexpr ( ! std::is_same<T, BFloat16>()) {
+ benchmark<T>(iterations, elems, AngularDistanceFunctionFactory<T>());
+ }
+ }
+ if (dist_functions.find("prenorm") != npos) {
+ if constexpr ( ! std::is_same<T, BFloat16>()) {
+ benchmark<T>(iterations, elems, PrenormalizedAngularDistanceFunctionFactory<T>());
+ }
+ }
+ if (dist_functions.find("mips") != npos) {
+ if constexpr ( !std::is_same<T, BFloat16>()) {
+ benchmark<T>(iterations, elems, MipsDistanceFunctionFactory<T>());
+ }
+ }
+}
+
+void
+benchmark(size_t iterations, size_t elems, const std::string & dist_functions, const std::string & data_types) {
+ if (data_types.find("double") != npos) {
+ benchmark<double>(iterations, elems, dist_functions);
+ }
+ if (data_types.find("float32") != npos) {
+ benchmark<float>(iterations, elems, dist_functions);
+ }
+ if (data_types.find("bfloat16") != npos) {
+ benchmark<BFloat16>(iterations, elems, dist_functions);
+ }
+ if (data_types.find("float8") != npos) {
+ benchmark<Int8Float>(iterations, elems, dist_functions);
+ }
+}
+
+int
+main(int argc, char *argv[]) {
+ size_t num_iterations = 10000000;
+ size_t num_elems = 1024;
+ std::string dist_functions = "angular euclid prenorm mips";
+ std::string data_types = "double float32 bfloat16 float8";
+ if (argc > 1) { num_iterations = atol(argv[1]); }
+ if (argc > 2) { num_elems = atol(argv[2]); }
+ if (argc > 3) { dist_functions = argv[3]; }
+ if (argc > 4) { data_types = argv[4]; }
+
+ printf("Benchmarking %ld iterations with vector length %ld with distance functions '%s' for data types '%s'\n",
+ num_iterations, num_elems, dist_functions.c_str(), data_types.c_str());
+ benchmark(num_iterations, num_elems, dist_functions, data_types);
+
+ return 0;
+}
diff --git a/searchlib/src/tests/tensor/distance_functions/distance_functions_test.cpp b/searchlib/src/tests/tensor/distance_functions/distance_functions_test.cpp
index eeae12e1695..c0296548b5a 100644
--- a/searchlib/src/tests/tensor/distance_functions/distance_functions_test.cpp
+++ b/searchlib/src/tests/tensor/distance_functions/distance_functions_test.cpp
@@ -13,9 +13,11 @@
LOG_SETUP("distance_function_test");
using namespace search::tensor;
+using search::attribute::DistanceMetric;
+using vespalib::BFloat16;
+using vespalib::eval::CellType;
using vespalib::eval::Int8Float;
using vespalib::eval::TypedCells;
-using search::attribute::DistanceMetric;
template <typename T>
TypedCells t(const std::vector<T> &v) { return TypedCells(v); }
@@ -716,6 +718,73 @@ TEST(DistanceFunctionsTest, transformed_mips_growing_norm)
EXPECT_GT(-29900.0, f->calc(t(p9d)));
}
+template <typename FloatType>
+void
+expect_reference_insertion_vector(FloatType exp_dist, DistanceMetric metric, CellType cell_type)
+{
+ std::vector<FloatType> lhs{0.0, 1.0};
+ std::vector<FloatType> rhs{0.0, 1.0};
+ auto factory = make_distance_function_factory(metric, cell_type);
+ auto func = factory->for_insertion_vector(t(lhs));
+ // Updating the insertion vector should be reflected in the calculation.
+ lhs[0] = 1.0;
+ lhs[1] = 0.0;
+ EXPECT_EQ(exp_dist, func->calc(t(rhs)));
+}
+
+template <typename FloatType>
+void
+expect_not_reference_insertion_vector(FloatType exp_dist, DistanceMetric metric, CellType cell_type)
+{
+ std::vector<FloatType> lhs{1.0, 0.0};
+ std::vector<FloatType> rhs{0.0, 1.0};
+ auto factory = make_distance_function_factory(metric, cell_type);
+ auto func = factory->for_insertion_vector(t(lhs));
+ // Updating the insertion vector should NOT be reflected in the calculation, as a copy has been created.
+ lhs[0] = 0.0;
+ lhs[1] = 1.0;
+ EXPECT_EQ(exp_dist, func->calc(t(rhs)));
+}
+
+TEST(DistanceFunctionsTest, angular_can_reference_insertion_vector)
+{
+ expect_reference_insertion_vector<float>(1.0, DistanceMetric::Angular, CellType::FLOAT);
+ expect_reference_insertion_vector<double>(1.0, DistanceMetric::Angular, CellType::DOUBLE);
+ expect_reference_insertion_vector<Int8Float>(1.0, DistanceMetric::Angular, CellType::INT8);
+ expect_not_reference_insertion_vector<BFloat16>(1.0, DistanceMetric::Angular, CellType::BFLOAT16);
+}
+
+TEST(DistanceFunctionsTest, prenormalized_angular_can_reference_insertion_vector)
+{
+ expect_reference_insertion_vector<float>(1.0, DistanceMetric::PrenormalizedAngular, CellType::FLOAT);
+ expect_reference_insertion_vector<double>(1.0, DistanceMetric::PrenormalizedAngular, CellType::DOUBLE);
+ expect_reference_insertion_vector<Int8Float>(1.0, DistanceMetric::PrenormalizedAngular, CellType::INT8);
+ expect_not_reference_insertion_vector<BFloat16>(1.0, DistanceMetric::PrenormalizedAngular, CellType::BFLOAT16);
+}
+
+TEST(DistanceFunctionsTest, euclidean_can_reference_insertion_vector)
+{
+ expect_reference_insertion_vector<float>(2.0, DistanceMetric::Euclidean, CellType::FLOAT);
+ expect_reference_insertion_vector<double>(2.0, DistanceMetric::Euclidean, CellType::DOUBLE);
+ expect_reference_insertion_vector<Int8Float>(2.0, DistanceMetric::Euclidean, CellType::INT8);
+ expect_not_reference_insertion_vector<BFloat16>(2.0, DistanceMetric::Euclidean, CellType::BFLOAT16);
+}
+
+TEST(DistanceFunctionsTest, dotproduct_can_reference_insertion_vector)
+{
+ expect_reference_insertion_vector<float>(0.0, DistanceMetric::Dotproduct, CellType::FLOAT);
+ expect_reference_insertion_vector<double>(0.0, DistanceMetric::Dotproduct, CellType::DOUBLE);
+ expect_reference_insertion_vector<Int8Float>(0.0, DistanceMetric::Dotproduct, CellType::INT8);
+ expect_not_reference_insertion_vector<BFloat16>(0.0, DistanceMetric::Dotproduct, CellType::BFLOAT16);
+}
+
+TEST(DistanceFunctionsTest, hamming_can_reference_insertion_vector)
+{
+ expect_reference_insertion_vector<float>(2.0, DistanceMetric::Hamming, CellType::FLOAT);
+ expect_reference_insertion_vector<double>(2.0, DistanceMetric::Hamming, CellType::DOUBLE);
+ expect_reference_insertion_vector<Int8Float>(2.0, DistanceMetric::Hamming, CellType::INT8);
+ expect_not_reference_insertion_vector<BFloat16>(2.0, DistanceMetric::Hamming, CellType::BFLOAT16);
+}
GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/searchlib/src/tests/tensor/hnsw_index/hnsw_index_test.cpp b/searchlib/src/tests/tensor/hnsw_index/hnsw_index_test.cpp
index d50677314df..97b88bc787a 100644
--- a/searchlib/src/tests/tensor/hnsw_index/hnsw_index_test.cpp
+++ b/searchlib/src/tests/tensor/hnsw_index/hnsw_index_test.cpp
@@ -111,7 +111,7 @@ class MyBoundDistanceFunction : public BoundDistanceFunction {
std::unique_ptr<BoundDistanceFunction> _real;
public:
- MyBoundDistanceFunction(std::unique_ptr<BoundDistanceFunction> real)
+ explicit MyBoundDistanceFunction(std::unique_ptr<BoundDistanceFunction> real)
: _real(std::move(real))
{
}
@@ -147,19 +147,19 @@ class MyDistanceFunctionFactory : public DistanceFunctionFactory
{
std::unique_ptr<DistanceFunctionFactory> _real;
public:
- MyDistanceFunctionFactory(std::unique_ptr<DistanceFunctionFactory> real)
+ explicit MyDistanceFunctionFactory(std::unique_ptr<DistanceFunctionFactory> real)
: _real(std::move(real))
{
}
~MyDistanceFunctionFactory() override;
- std::unique_ptr<BoundDistanceFunction> for_query_vector(TypedCells lhs) override {
+ std::unique_ptr<BoundDistanceFunction> for_query_vector(TypedCells lhs) const override {
EXPECT_FALSE(lhs.non_existing_attribute_value());
return std::make_unique<MyBoundDistanceFunction>(_real->for_query_vector(lhs));
}
- std::unique_ptr<BoundDistanceFunction> for_insertion_vector(TypedCells lhs) override {
+ std::unique_ptr<BoundDistanceFunction> for_insertion_vector(TypedCells lhs) const override {
EXPECT_FALSE(lhs.non_existing_attribute_value());
return std::make_unique<MyBoundDistanceFunction>(_real->for_insertion_vector(lhs));
}
@@ -936,6 +936,36 @@ TYPED_TEST(HnswIndexTest, search_during_remove)
this->expect_top_3_by_docid("{0, 0}", {0, 0}, {7});
}
+TYPED_TEST(HnswIndexTest, inconsistent_index)
+{
+ this->init(false);
+ this->vectors.clear();
+ this->vectors.set(1, {1, 3}).set(2, {7, 1}).set(3, {6, 5}).set(4, {8, 3}).set(5, {10, 3});
+ this->add_document(1);
+ this->add_document(2);
+ this->add_document(3);
+ this->add_document(4);
+ this->add_document(5);
+ this->expect_entry_point(1, 0);
+ this->expect_level_0(1, {2, 3});
+ this->expect_level_0(2, {1, 3, 4, 5});
+ this->expect_level_0(3, {1, 2, 4});
+ this->expect_level_0(4, {2, 3, 5});
+ this->expect_level_0(5, {2, 4});
+ EXPECT_EQ(0, this->index->check_consistency(6));
+ // Remove vector for docid 5 but don't update index.
+ this->vectors.clear(5);
+ EXPECT_EQ(1, this->index->check_consistency(6));
+ /*
+ * Removing document 2 causes mutual reconnect for nodes [1, 3, 4, 5]
+ * where nodes 1 and 5 are not previously connected. Distance from
+ * node 1 to node 5 cannot be calculated due to missing vector.
+ */
+ this->remove_document(2);
+ // No reconnect for node without vector
+ this->expect_level_0(5, {4});
+}
+
using HnswMultiIndexTest = HnswIndexTest<HnswIndex<HnswIndexType::MULTI>>;
namespace {
diff --git a/searchlib/src/tests/util/token_extractor/token_extractor_test.cpp b/searchlib/src/tests/util/token_extractor/token_extractor_test.cpp
index e6944e257e9..5eb42bb8ac4 100644
--- a/searchlib/src/tests/util/token_extractor/token_extractor_test.cpp
+++ b/searchlib/src/tests/util/token_extractor/token_extractor_test.cpp
@@ -118,7 +118,7 @@ TEST_F(TokenExtractorTest, empty_string)
TEST_F(TokenExtractorTest, plain_string)
{
- EXPECT_EQ((Words{"Plain string"}), process(StringFieldValue("Plain string")));
+ EXPECT_EQ((Words{}), process(StringFieldValue("Plain string")));
}
TEST_F(TokenExtractorTest, normal_string)