aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java8
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java1
-rw-r--r--searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp20
-rw-r--r--searchlib/src/tests/queryeval/flow/queryeval_flow_test.cpp58
-rw-r--r--searchlib/src/vespa/searchlib/attribute/CMakeLists.txt1
-rw-r--r--searchlib/src/vespa/searchlib/attribute/predicate_attribute.cpp37
-rw-r--r--searchlib/src/vespa/searchlib/attribute/predicate_attribute.h2
-rw-r--r--searchlib/src/vespa/searchlib/attribute/predicate_attribute_saver.cpp52
-rw-r--r--searchlib/src/vespa/searchlib/attribute/predicate_attribute_saver.h40
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/blueprint.cpp17
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/blueprint.h2
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/flow.h41
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp18
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.h4
14 files changed, 249 insertions, 52 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java
index 48c85aed640..36221d978a1 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java
@@ -732,6 +732,7 @@ public final class Node implements Nodelike {
private final State state;
private final NodeType type;
+ private String extraId;
private String parentHostname;
private String modelName;
private TenantName reservedTo;
@@ -758,6 +759,11 @@ public final class Node implements Nodelike {
this.type = type;
}
+ public Builder extraId(String extraId) {
+ this.extraId = extraId;
+ return this;
+ }
+
public Builder parentHostname(String parentHostname) {
this.parentHostname = parentHostname;
return this;
@@ -849,7 +855,7 @@ public final class Node implements Nodelike {
}
public Node build() {
- return new Node(id, Optional.empty(), Optional.ofNullable(ipConfig).orElse(IP.Config.EMPTY), hostname, Optional.ofNullable(parentHostname),
+ return new Node(id, Optional.ofNullable(extraId), Optional.ofNullable(ipConfig).orElse(IP.Config.EMPTY), hostname, Optional.ofNullable(parentHostname),
flavor, Optional.ofNullable(status).orElseGet(Status::initial), state, Optional.ofNullable(allocation),
Optional.ofNullable(history).orElseGet(History::empty), type, Optional.ofNullable(reports).orElseGet(Reports::new),
Optional.ofNullable(modelName), Optional.ofNullable(reservedTo), Optional.ofNullable(exclusiveToApplicationId),
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java
index 0b157e8635b..cef28045a8b 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java
@@ -302,6 +302,7 @@ public class NodesV2ApiHandler extends ThreadedHttpRequestHandler {
flavorFromSlime(inspector),
nodeTypeFromSlime(inspector.field("type")))
.cloudAccount(nodeRepository.zone().cloud().account());
+ optionalString(inspector.field("extraId")).ifPresent(builder::extraId);
optionalString(inspector.field("parentHostname")).ifPresent(builder::parentHostname);
optionalString(inspector.field("modelName")).ifPresent(builder::modelName);
optionalString(inspector.field("reservedTo")).map(TenantName::from).ifPresent(builder::reservedTo);
diff --git a/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp b/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp
index ee7c201f093..31db731a598 100644
--- a/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp
+++ b/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp
@@ -165,20 +165,30 @@ TEST("test Or propagates updated histestimate") {
bp->addChild(ap(MyLeafSpec(800).create<RememberExecuteInfo>()->setSourceId(2)));
bp->addChild(ap(MyLeafSpec(20).create<RememberExecuteInfo>()->setSourceId(2)));
bp->setDocIdLimit(5000);
- // sort OR as non-strict to get expected order. With strict OR,
- // the order would be irrelevant since we use the relative
- // estimate as strict_cost for leafs.
+ // NOTE: use non-strict OR ordering since strict OR ordering is non-deterministic
optimize(bp, false);
- bp->fetchPostings(ExecuteInfo::TRUE);
+ //--- execute info when non-strict:
+ bp->fetchPostings(ExecuteInfo::FALSE);
EXPECT_EQUAL(4u, bp->childCnt());
for (uint32_t i = 0; i < bp->childCnt(); i++) {
const auto & child = dynamic_cast<const RememberExecuteInfo &>(bp->getChild(i));
- EXPECT_TRUE(child.is_strict);
+ EXPECT_FALSE(child.is_strict);
}
EXPECT_EQUAL(1.0, dynamic_cast<const RememberExecuteInfo &>(bp->getChild(0)).hit_rate);
EXPECT_APPROX(0.5, dynamic_cast<const RememberExecuteInfo &>(bp->getChild(1)).hit_rate, 1e-6);
EXPECT_APPROX(0.5*3.0/5.0, dynamic_cast<const RememberExecuteInfo &>(bp->getChild(2)).hit_rate, 1e-6);
EXPECT_APPROX(0.5*3.0*42.0/(5.0*50.0), dynamic_cast<const RememberExecuteInfo &>(bp->getChild(3)).hit_rate, 1e-6);
+ //--- execute info when strict:
+ bp->fetchPostings(ExecuteInfo::TRUE);
+ EXPECT_EQUAL(4u, bp->childCnt());
+ for (uint32_t i = 0; i < bp->childCnt(); i++) {
+ const auto & child = dynamic_cast<const RememberExecuteInfo &>(bp->getChild(i));
+ EXPECT_TRUE(child.is_strict);
+ }
+ EXPECT_EQUAL(1.0, dynamic_cast<const RememberExecuteInfo &>(bp->getChild(0)).hit_rate);
+ EXPECT_EQUAL(1.0, dynamic_cast<const RememberExecuteInfo &>(bp->getChild(1)).hit_rate);
+ EXPECT_EQUAL(1.0, dynamic_cast<const RememberExecuteInfo &>(bp->getChild(2)).hit_rate);
+ EXPECT_EQUAL(1.0, dynamic_cast<const RememberExecuteInfo &>(bp->getChild(3)).hit_rate);
}
TEST("test And Blueprint") {
diff --git a/searchlib/src/tests/queryeval/flow/queryeval_flow_test.cpp b/searchlib/src/tests/queryeval/flow/queryeval_flow_test.cpp
index 7a3950dbf1c..5009a15e438 100644
--- a/searchlib/src/tests/queryeval/flow/queryeval_flow_test.cpp
+++ b/searchlib/src/tests/queryeval/flow/queryeval_flow_test.cpp
@@ -126,6 +126,14 @@ void verify_flow(auto flow, const std::vector<double> &est_list, const std::vect
}
}
+void verify_flow_calc(FlowCalc flow_calc, const std::vector<double> &est_list, const std::vector<double> &expect) {
+ ASSERT_EQ(est_list.size() + 1, expect.size());
+ for (size_t i = 0; i < est_list.size(); ++i) {
+ EXPECT_DOUBLE_EQ(flow_calc(est_list[i]), expect[i]);
+ }
+ EXPECT_DOUBLE_EQ(flow_calc(0.5), expect.back());
+}
+
TEST(FlowTest, full_and_flow) {
for (bool strict: {false, true}) {
verify_flow(AndFlow(strict), {0.4, 0.7, 0.2},
@@ -133,6 +141,8 @@ TEST(FlowTest, full_and_flow) {
{0.4, 0.4, false},
{0.4*0.7, 0.4*0.7, false},
{0.4*0.7*0.2, 0.4*0.7*0.2, false}});
+ verify_flow_calc(flow_calc<AndFlow>(strict, 1.0),
+ {0.4, 0.7, 0.2}, {1.0, 0.4, 0.4*0.7, 0.4*0.7*0.2});
}
}
@@ -143,6 +153,8 @@ TEST(FlowTest, partial_and_flow) {
{in*0.4, in*0.4, false},
{in*0.4*0.7, in*0.4*0.7, false},
{in*0.4*0.7*0.2, in*0.4*0.7*0.2, false}});
+ verify_flow_calc(flow_calc<AndFlow>(false, in),
+ {0.4, 0.7, 0.2}, {in*1.0, in*0.4, in*0.4*0.7, in*0.4*0.7*0.2});
}
}
@@ -152,11 +164,15 @@ TEST(FlowTest, full_or_flow) {
{0.6, 1.0-0.6, false},
{0.6*0.3, 1.0-0.6*0.3, false},
{0.6*0.3*0.8, 1.0-0.6*0.3*0.8, false}});
+ verify_flow_calc(flow_calc<OrFlow>(false, 1.0),
+ {0.4, 0.7, 0.2}, {1.0, 0.6, 0.6*0.3, 0.6*0.3*0.8});
verify_flow(OrFlow(true), {0.4, 0.7, 0.2},
{{1.0, 0.0, true},
{1.0, 1.0-0.6, true},
{1.0, 1.0-0.6*0.3, true},
{1.0, 1.0-0.6*0.3*0.8, true}});
+ verify_flow_calc(flow_calc<OrFlow>(true, 1.0),
+ {0.4, 0.7, 0.2}, {1.0, 1.0, 1.0, 1.0});
}
TEST(FlowTest, partial_or_flow) {
@@ -166,6 +182,8 @@ TEST(FlowTest, partial_or_flow) {
{in*0.6, 1.0-in*0.6, false},
{in*0.6*0.3, 1.0-in*0.6*0.3, false},
{in*0.6*0.3*0.8, 1.0-in*0.6*0.3*0.8, false}});
+ verify_flow_calc(flow_calc<OrFlow>(false, in),
+ {0.4, 0.7, 0.2}, {in, in*0.6, in*0.6*0.3, in*0.6*0.3*0.8});
}
}
@@ -176,6 +194,8 @@ TEST(FlowTest, full_and_not_flow) {
{0.4, 0.4, false},
{0.4*0.3, 0.4*0.3, false},
{0.4*0.3*0.8, 0.4*0.3*0.8, false}});
+ verify_flow_calc(flow_calc<AndNotFlow>(strict, 1.0),
+ {0.4, 0.7, 0.2}, {1.0, 0.4, 0.4*0.3, 0.4*0.3*0.8});
}
}
@@ -186,9 +206,47 @@ TEST(FlowTest, partial_and_not_flow) {
{in*0.4, in*0.4, false},
{in*0.4*0.3, in*0.4*0.3, false},
{in*0.4*0.3*0.8, in*0.4*0.3*0.8, false}});
+ verify_flow_calc(flow_calc<AndNotFlow>(false, in),
+ {0.4, 0.7, 0.2}, {in, in*0.4, in*0.4*0.3, in*0.4*0.3*0.8});
+ }
+}
+
+TEST(FlowTest, full_first_flow_calc) {
+ for (bool strict: {false, true}) {
+ verify_flow_calc(first_flow_calc(strict, 1.0),
+ {0.4, 0.7, 0.2}, {1.0, 0.4, 0.4, 0.4});
+ }
+}
+
+TEST(FlowTest, partial_first_flow_calc) {
+ for (double in: {1.0, 0.5, 0.25}) {
+ verify_flow_calc(first_flow_calc(false, in),
+ {0.4, 0.7, 0.2}, {in, in*0.4, in*0.4, in*0.4});
+ }
+}
+
+TEST(FlowTest, full_full_flow_calc) {
+ for (bool strict: {false, true}) {
+ verify_flow_calc(full_flow_calc(strict, 1.0),
+ {0.4, 0.7, 0.2}, {1.0, 1.0, 1.0, 1.0});
}
}
+TEST(FlowTest, partial_full_flow_calc) {
+ for (double in: {1.0, 0.5, 0.25}) {
+ verify_flow_calc(full_flow_calc(false, in),
+ {0.4, 0.7, 0.2}, {in, in, in, in});
+ }
+}
+
+TEST(FlowTest, flow_calc_strictness_overrides_rate) {
+ EXPECT_EQ(flow_calc<AndFlow>(true, 0.5)(0.5), 1.0);
+ EXPECT_EQ(flow_calc<OrFlow>(true, 0.5)(0.5), 1.0);
+ EXPECT_EQ(flow_calc<AndNotFlow>(true, 0.5)(0.5), 1.0);
+ EXPECT_EQ(first_flow_calc(true, 0.5)(0.5), 1.0);
+ EXPECT_EQ(full_flow_calc(true, 0.5)(0.5), 1.0);
+}
+
TEST(FlowTest, flow_cost) {
std::vector<FlowStats> data = {{0.4, 1.1, 0.6}, {0.7, 1.2, 0.5}, {0.2, 1.3, 0.4}};
EXPECT_DOUBLE_EQ(ordered_cost_of<AndFlow>(data, false), 1.1 + 0.4*1.2 + 0.4*0.7*1.3);
diff --git a/searchlib/src/vespa/searchlib/attribute/CMakeLists.txt b/searchlib/src/vespa/searchlib/attribute/CMakeLists.txt
index 96bd07bc5a3..4f886cf2dd4 100644
--- a/searchlib/src/vespa/searchlib/attribute/CMakeLists.txt
+++ b/searchlib/src/vespa/searchlib/attribute/CMakeLists.txt
@@ -111,6 +111,7 @@ vespa_add_library(searchlib_attribute OBJECT
postinglisttraits.cpp
postingstore.cpp
predicate_attribute.cpp
+ predicate_attribute_saver.cpp
raw_attribute.cpp
raw_buffer_store.cpp
raw_buffer_store_reader.cpp
diff --git a/searchlib/src/vespa/searchlib/attribute/predicate_attribute.cpp b/searchlib/src/vespa/searchlib/attribute/predicate_attribute.cpp
index 60898450e50..075616a9fe9 100644
--- a/searchlib/src/vespa/searchlib/attribute/predicate_attribute.cpp
+++ b/searchlib/src/vespa/searchlib/attribute/predicate_attribute.cpp
@@ -4,6 +4,7 @@
#include "attribute_header.h"
#include "iattributesavetarget.h"
#include "load_utils.h"
+#include "predicate_attribute_saver.h"
#include <vespa/document/fieldvalue/predicatefieldvalue.h>
#include <vespa/document/predicate/predicate.h>
#include <vespa/searchlib/predicate/i_saver.h>
@@ -143,29 +144,23 @@ PredicateAttribute::before_inc_generation(generation_t current_gen)
_index->assign_generation(current_gen);
}
-void
-PredicateAttribute::onSave(IAttributeSaveTarget &saveTarget) {
- LOG(info, "Saving predicate attribute version %d name '%s'", getVersion(), getName().c_str());
- IAttributeSaveTarget::Buffer buffer(saveTarget.datWriter().allocBuf(4_Ki));
- {
- DataBufferWriter writer(*buffer);
- auto saver = _index->make_saver();
- saver->save(writer);
- writer.flush();
- }
- uint32_t highest_doc_id = static_cast<uint32_t>(_min_feature.size() - 1);
- buffer->writeInt32(highest_doc_id);
- for (size_t i = 1; i <= highest_doc_id; ++i) {
- buffer->writeInt8(_min_feature[i]);
- }
- for (size_t i = 1; i <= highest_doc_id; ++i) {
- buffer->writeInt16(_interval_range_vector[i]);
- }
- buffer->writeInt16(_max_interval_range);
- saveTarget.datWriter().writeBuf(std::move(buffer));
+std::unique_ptr<AttributeSaver>
+PredicateAttribute::onInitSave(vespalib::stringref fileName)
+{
+ auto guard(getGenerationHandler().takeGuard());
+ auto header = this->createAttributeHeader(fileName);
+ auto min_feature_view = _min_feature.make_read_view(_min_feature.size());
+ auto interval_range_vector_view = _interval_range_vector.make_read_view(_interval_range_vector.size());
+ return std::make_unique<PredicateAttributeSaver>
+ (std::move(guard),
+ std::move(header),
+ getVersion(),
+ _index->make_saver(),
+ PredicateAttributeSaver::MinFeatureVector{ min_feature_view.begin(), min_feature_view.end() },
+ PredicateAttributeSaver::IntervalRangeVector{ interval_range_vector_view.begin(), interval_range_vector_view.end() },
+ _max_interval_range);
}
-
uint32_t
PredicateAttribute::getVersion() const {
return PREDICATE_ATTRIBUTE_VERSION;
diff --git a/searchlib/src/vespa/searchlib/attribute/predicate_attribute.h b/searchlib/src/vespa/searchlib/attribute/predicate_attribute.h
index acb4cbc5833..f188ac29941 100644
--- a/searchlib/src/vespa/searchlib/attribute/predicate_attribute.h
+++ b/searchlib/src/vespa/searchlib/attribute/predicate_attribute.h
@@ -45,7 +45,7 @@ public:
predicate::PredicateIndex &getIndex() { return *_index; }
- void onSave(IAttributeSaveTarget & saveTarget) override;
+ std::unique_ptr<AttributeSaver> onInitSave(vespalib::stringref fileName) override;
bool onLoad(vespalib::Executor *executor) override;
void onCommit() override;
void reclaim_memory(generation_t oldest_used_gen) override;
diff --git a/searchlib/src/vespa/searchlib/attribute/predicate_attribute_saver.cpp b/searchlib/src/vespa/searchlib/attribute/predicate_attribute_saver.cpp
new file mode 100644
index 00000000000..aa1c3ab45a6
--- /dev/null
+++ b/searchlib/src/vespa/searchlib/attribute/predicate_attribute_saver.cpp
@@ -0,0 +1,52 @@
+// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "predicate_attribute_saver.h"
+#include "iattributesavetarget.h"
+#include <vespa/searchlib/predicate/i_saver.h>
+#include <vespa/searchlib/predicate/nbo_write.h>
+#include <filesystem>
+
+#include <vespa/log/log.h>
+LOG_SETUP(".searchlib.attribute.predicate_attribute_saver");
+
+using search::predicate::nbo_write;
+
+namespace search {
+
+PredicateAttributeSaver::PredicateAttributeSaver(GenerationHandler::Guard &&guard,
+ const attribute::AttributeHeader &header,
+ uint32_t version,
+ std::unique_ptr<predicate::ISaver> index_saver,
+ MinFeatureVector min_feature,
+ IntervalRangeVector interval_range_vector,
+ uint16_t max_interval_range)
+ : AttributeSaver(std::move(guard), header),
+ _version(version),
+ _index_saver(std::move(index_saver)),
+ _min_feature(std::move(min_feature)),
+ _interval_range_vector(std::move(interval_range_vector)),
+ _max_interval_range(max_interval_range)
+{
+}
+
+PredicateAttributeSaver::~PredicateAttributeSaver() = default;
+
+bool
+PredicateAttributeSaver::onSave(IAttributeSaveTarget& save_target)
+{
+ auto name = std::filesystem::path(get_file_name()).filename().native();
+ LOG(info, "Saving predicate attribute version %u name '%s'", _version, name.c_str());
+ auto writer = save_target.datWriter().allocBufferWriter();
+ _index_saver->save(*writer);
+ uint32_t highest_doc_id = static_cast<uint32_t>(_min_feature.size() - 1);
+ nbo_write<uint32_t>(*writer, highest_doc_id);
+ writer->write(&_min_feature[1], highest_doc_id);
+ for (size_t i = 1; i <= highest_doc_id; ++i) {
+ nbo_write<uint16_t>(*writer, _interval_range_vector[i]);
+ }
+ nbo_write<uint16_t>(*writer, _max_interval_range);
+ writer->flush();
+ return true;
+}
+
+}
diff --git a/searchlib/src/vespa/searchlib/attribute/predicate_attribute_saver.h b/searchlib/src/vespa/searchlib/attribute/predicate_attribute_saver.h
new file mode 100644
index 00000000000..28e7094091f
--- /dev/null
+++ b/searchlib/src/vespa/searchlib/attribute/predicate_attribute_saver.h
@@ -0,0 +1,40 @@
+// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include "attributesaver.h"
+#include <vespa/vespalib/stllike/allocator.h>
+
+namespace search::predicate { class ISaver; }
+
+namespace search {
+
+/**
+ * Class for saving a predicate attribute.
+ */
+class PredicateAttributeSaver : public AttributeSaver
+{
+public:
+ using GenerationHandler = vespalib::GenerationHandler;
+ using MinFeatureVector = std::vector<uint8_t, vespalib::allocator_large<uint8_t>>;
+ using IntervalRangeVector = std::vector<uint16_t, vespalib::allocator_large<uint16_t>>;
+
+private:
+ uint32_t _version;
+ std::unique_ptr<predicate::ISaver> _index_saver;
+ MinFeatureVector _min_feature;
+ IntervalRangeVector _interval_range_vector;
+ uint16_t _max_interval_range;
+public:
+ PredicateAttributeSaver(GenerationHandler::Guard&& guard,
+ const attribute::AttributeHeader& header,
+ uint32_t version,
+ std::unique_ptr<predicate::ISaver> index_saver,
+ MinFeatureVector min_feature,
+ IntervalRangeVector interval_range_vector,
+ uint16_t max_interval_range);
+ ~PredicateAttributeSaver() override;
+ bool onSave(IAttributeSaveTarget& save_target) override;
+};
+
+}
diff --git a/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp b/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp
index 2f69c45d418..f3539c6989a 100644
--- a/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp
+++ b/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp
@@ -481,6 +481,12 @@ IntermediateBlueprint::count_termwise_nodes(const UnpackInfo &unpack) const
return termwise_nodes;
}
+FlowCalc
+IntermediateBlueprint::make_flow_calc(bool strict, double flow) const
+{
+ return full_flow_calc(strict, flow);
+}
+
IntermediateBlueprint::IndexList
IntermediateBlueprint::find(const IPredicate & pred) const
{
@@ -538,13 +544,6 @@ IntermediateBlueprint::calculateState() const
return state;
}
-double
-IntermediateBlueprint::computeNextHitRate(const Blueprint & child, double hit_rate) const
-{
- (void) child;
- return hit_rate;
-}
-
bool
IntermediateBlueprint::should_do_termwise_eval(const UnpackInfo &unpack, double match_limit) const
{
@@ -648,11 +647,11 @@ IntermediateBlueprint::visitMembers(vespalib::ObjectVisitor &visitor) const
void
IntermediateBlueprint::fetchPostings(const ExecuteInfo &execInfo)
{
- double nextHitRate = execInfo.hit_rate();
+ FlowCalc flow_calc = make_flow_calc(execInfo.is_strict(), execInfo.hit_rate());
for (size_t i = 0; i < _children.size(); ++i) {
Blueprint & child = *_children[i];
+ double nextHitRate = flow_calc(child.estimate());
child.fetchPostings(ExecuteInfo::create(execInfo.is_strict() && inheritStrict(i), nextHitRate, execInfo));
- nextHitRate = computeNextHitRate(child, nextHitRate);
}
}
diff --git a/searchlib/src/vespa/searchlib/queryeval/blueprint.h b/searchlib/src/vespa/searchlib/queryeval/blueprint.h
index 439eff680ec..395512d84cc 100644
--- a/searchlib/src/vespa/searchlib/queryeval/blueprint.h
+++ b/searchlib/src/vespa/searchlib/queryeval/blueprint.h
@@ -362,7 +362,7 @@ private:
bool infer_want_global_filter() const;
size_t count_termwise_nodes(const UnpackInfo &unpack) const;
- virtual double computeNextHitRate(const Blueprint & child, double hit_rate) const;
+ virtual FlowCalc make_flow_calc(bool strict, double flow) const;
protected:
// returns an empty collection if children have empty or
diff --git a/searchlib/src/vespa/searchlib/queryeval/flow.h b/searchlib/src/vespa/searchlib/queryeval/flow.h
index cfbb28b190f..4548baf7545 100644
--- a/searchlib/src/vespa/searchlib/queryeval/flow.h
+++ b/searchlib/src/vespa/searchlib/queryeval/flow.h
@@ -4,7 +4,7 @@
#include <vespa/vespalib/util/small_vector.h>
#include <cstddef>
#include <algorithm>
-#include <cmath>
+#include <functional>
// Model how boolean result decisions flow through intermediate nodes
// of different types based on relative estimates for sub-expressions
@@ -53,12 +53,11 @@ concept DirectAdaptable = requires(const T &t) {
auto make_adapter(const auto &children) {
using type = std::remove_cvref_t<decltype(children)>::value_type;
+ static_assert(DefaultAdaptable<type> || DirectAdaptable<type>, "unable to resolve children adapter");
if constexpr (DefaultAdaptable<type>) {
return DefaultAdapter();
- } else if constexpr (DirectAdaptable<type>) {
- return DirectAdapter();
} else {
- static_assert(false, "unable to resolve children adapter");
+ return DirectAdapter();
}
}
@@ -280,4 +279,38 @@ public:
}
};
+using FlowCalc = std::function<double(double)>;
+
+template <typename FLOW>
+FlowCalc flow_calc(bool strict, double non_strict_rate) {
+ FLOW flow = strict ? FLOW(true) : FLOW(non_strict_rate);
+ return [flow](double est) mutable noexcept {
+ double next_flow = flow.flow();
+ flow.add(est);
+ return next_flow;
+ };
+}
+
+inline FlowCalc first_flow_calc(bool strict, double flow) {
+ if (strict) {
+ flow = 1.0;
+ }
+ bool first = true;
+ return [flow,first](double est) mutable noexcept {
+ double next_flow = flow;
+ if (first) {
+ flow *= est;
+ first = false;
+ }
+ return next_flow;
+ };
+}
+
+inline FlowCalc full_flow_calc(bool strict, double flow) {
+ if (strict) {
+ flow = 1.0;
+ }
+ return [flow](double) noexcept { return flow; };
+}
+
}
diff --git a/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp b/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp
index 993639becf2..6faa4ddf147 100644
--- a/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp
+++ b/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp
@@ -300,14 +300,10 @@ AndBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) const
return create_and_filter(get_children(), strict, constraint);
}
-double
-AndBlueprint::computeNextHitRate(const Blueprint & child, double hit_rate) const {
- return hit_rate * child.estimate();
-}
-
-double
-OrBlueprint::computeNextHitRate(const Blueprint & child, double hit_rate) const {
- return hit_rate * (1.0 - child.estimate());
+FlowCalc
+AndBlueprint::make_flow_calc(bool strict, double flow) const
+{
+ return flow_calc<AndFlow>(strict, flow);
}
//-----------------------------------------------------------------------------
@@ -404,6 +400,12 @@ OrBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) const
return create_or_filter(get_children(), strict, constraint);
}
+FlowCalc
+OrBlueprint::make_flow_calc(bool strict, double flow) const
+{
+ return flow_calc<OrFlow>(strict, flow);
+}
+
uint8_t
OrBlueprint::calculate_cost_tier() const
{
diff --git a/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.h b/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.h
index 1da70b4fa70..25586022535 100644
--- a/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.h
+++ b/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.h
@@ -56,7 +56,7 @@ public:
SearchIterator::UP
createFilterSearch(bool strict, FilterConstraint constraint) const override;
private:
- double computeNextHitRate(const Blueprint & child, double hit_rate) const override;
+ virtual FlowCalc make_flow_calc(bool strict, double flow) const override;
};
//-----------------------------------------------------------------------------
@@ -81,7 +81,7 @@ public:
SearchIterator::UP
createFilterSearch(bool strict, FilterConstraint constraint) const override;
private:
- double computeNextHitRate(const Blueprint & child, double hit_rate) const override;
+ FlowCalc make_flow_calc(bool strict, double flow) const override;
uint8_t calculate_cost_tier() const override;
};