Allow override to be active within specific time window.

This commit is contained in:
Kishore Nallan 2022-08-04 17:09:55 +05:30
parent 6f38ee4270
commit 743abd461c
3 changed files with 102 additions and 1 deletions

View File

@ -112,6 +112,10 @@ struct override_t {
std::string sort_by;
std::string replace_query;
// epoch seconds
int64_t window_start_ts = -1;
int64_t window_end_ts = -1;
override_t() = default;
static Option<bool> parse(const nlohmann::json& override_json, const std::string& id, override_t& override) {
@ -265,6 +269,14 @@ struct override_t {
override.stop_processing = override_json["stop_processing"].get<bool>();
}
if(override_json.count("window_start_ts") != 0) {
override.window_start_ts = override_json["window_start_ts"].get<int64_t>();
}
if(override_json.count("window_end_ts") != 0) {
override.window_end_ts = override_json["window_end_ts"].get<int64_t>();
}
// we have to also detect if it is a dynamic query rule
size_t i = 0;
while(i < override.rule.query.size()) {
@ -321,6 +333,14 @@ struct override_t {
override["replace_query"] = replace_query;
}
if(window_start_ts != -1) {
override["window_start_ts"] = window_start_ts;
}
if(window_end_ts != -1) {
override["window_end_ts"] = window_end_ts;
}
override["remove_matched_tokens"] = remove_matched_tokens;
override["filter_curated_hits"] = filter_curated_hits;
override["stop_processing"] = stop_processing;

View File

@ -451,6 +451,15 @@ void Collection::curate_results(string& actual_query, bool enable_overrides, boo
for(const auto& override_kv: overrides) {
const auto& override = override_kv.second;
auto now_epoch = int64_t(std::time(0));
if(override.window_start_ts != -1 && now_epoch < override.window_start_ts) {
continue;
}
if(override.window_end_ts != -1 && now_epoch > override.window_end_ts) {
continue;
}
// ID-based overrides are applied first as they take precedence over filter-based overrides
if(!override.filter_by.empty()) {
filter_overrides.push_back(&override);

View File

@ -271,7 +271,7 @@ TEST_F(CollectionOverrideTest, OverrideJSONValidation) {
parse_op = override_t::parse(include_json2, "", override2);
ASSERT_FALSE(parse_op.ok());
ASSERT_STREQ("Must contain one of: `includes`, `excludes`, `filter_by`, `sort_by`, `remove_matched_tokens`.",
ASSERT_STREQ("Must contain one of: `includes`, `excludes`, `filter_by`, `sort_by`, `remove_matched_tokens`, `replace_query`.",
parse_op.error().c_str());
include_json2["includes"] = nlohmann::json::array();
@ -841,6 +841,78 @@ TEST_F(CollectionOverrideTest, ReplaceQuery) {
ASSERT_EQ("Only one of `replace_query` or `remove_matched_tokens` can be specified.", op.error());
}
TEST_F(CollectionOverrideTest, WindowForRule) {
Collection *coll1;
std::vector<field> fields = {field("name", field_types::STRING, false),
field("points", field_types::INT32, false)};
coll1 = collectionManager.get_collection("coll1").get();
if(coll1 == nullptr) {
coll1 = collectionManager.create_collection("coll1", 1, fields, "points").get();
}
nlohmann::json doc1;
doc1["id"] = "0";
doc1["name"] = "Amazing Shoes";
doc1["points"] = 30;
ASSERT_TRUE(coll1->add(doc1.dump()).ok());
std::vector<sort_by> sort_fields = { sort_by("_text_match", "DESC"), sort_by("points", "DESC") };
nlohmann::json override_json = R"({
"id": "rule-1",
"rule": {
"query": "boots",
"match": "exact"
},
"replace_query": "shoes"
})"_json;
override_t override_rule;
auto op = override_t::parse(override_json, "rule-1", override_rule);
ASSERT_TRUE(op.ok());
coll1->add_override(override_rule);
auto results = coll1->search("boots", {"name"}, "",
{}, sort_fields, {2}, 10, 1, FREQUENCY, {true}, 0).get();
ASSERT_EQ(1, results["hits"].size());
ASSERT_EQ("0", results["hits"][0]["document"]["id"].get<std::string>());
// rule must not match when window_start is set into the future
override_json["window_start_ts"] = 35677971263; // year 3100, here we come! ;)
op = override_t::parse(override_json, "rule-1", override_rule);
ASSERT_TRUE(op.ok());
coll1->add_override(override_rule);
results = coll1->search("boots", {"name"}, "",
{}, sort_fields, {2}, 10, 1, FREQUENCY, {true}, 0).get();
ASSERT_EQ(0, results["hits"].size());
// rule must not match when window_end is set into the past
override_json["window_start_ts"] = -1;
override_json["window_end_ts"] = 965388863;
op = override_t::parse(override_json, "rule-1", override_rule);
ASSERT_TRUE(op.ok());
coll1->add_override(override_rule);
results = coll1->search("boots", {"name"}, "",
{}, sort_fields, {2}, 10, 1, FREQUENCY, {true}, 0).get();
ASSERT_EQ(0, results["hits"].size());
// resetting both should bring the override back in action
override_json["window_start_ts"] = 965388863;
override_json["window_end_ts"] = 35677971263;
op = override_t::parse(override_json, "rule-1", override_rule);
ASSERT_TRUE(op.ok());
coll1->add_override(override_rule);
results = coll1->search("boots", {"name"}, "",
{}, sort_fields, {2}, 10, 1, FREQUENCY, {true}, 0).get();
ASSERT_EQ(1, results["hits"].size());
}
TEST_F(CollectionOverrideTest, PinnedAndHiddenHits) {
auto pinned_hits = "13:1,4:2";