mirror of
https://github.com/typesense/typesense.git
synced 2025-05-21 06:02:26 +08:00
Allow override rule to have only tags w/o query or filter by.
This commit is contained in:
parent
16f7813e02
commit
9802ac1d5e
@ -187,7 +187,7 @@ private:
|
||||
std::set<uint32_t>& excluded_set,
|
||||
string& actual_query, const string& filter_query,
|
||||
bool already_segmented,
|
||||
const std::set<std::string>& tags,
|
||||
const bool tags_matched,
|
||||
const std::map<size_t, std::vector<std::string>>& pinned_hits,
|
||||
const std::vector<std::string>& hidden_hits,
|
||||
std::vector<std::pair<uint32_t, uint32_t>>& included_ids,
|
||||
|
@ -814,7 +814,7 @@ bool Collection::does_override_match(const override_t& override, std::string& qu
|
||||
std::set<uint32_t>& excluded_set,
|
||||
string& actual_query, const string& filter_query,
|
||||
bool already_segmented,
|
||||
const std::set<std::string>& tags,
|
||||
const bool tags_matched,
|
||||
const std::map<size_t, std::vector<std::string>>& pinned_hits,
|
||||
const std::vector<std::string>& hidden_hits,
|
||||
std::vector<std::pair<uint32_t, uint32_t>>& included_ids,
|
||||
@ -838,19 +838,23 @@ bool Collection::does_override_match(const override_t& override, std::string& qu
|
||||
filter_overrides.push_back(&override);
|
||||
}
|
||||
|
||||
bool filter_by_match = (override.rule.query.empty() && override.rule.match.empty() &&
|
||||
!override.rule.filter_by.empty() && override.rule.filter_by == filter_query);
|
||||
if(tags_matched && override.rule.query.empty() && override.rule.filter_by.empty()) {
|
||||
// allowed
|
||||
} else {
|
||||
bool filter_by_match = (override.rule.query.empty() && override.rule.match.empty() &&
|
||||
!override.rule.filter_by.empty() && override.rule.filter_by == filter_query);
|
||||
|
||||
bool query_match = (override.rule.match == override_t::MATCH_EXACT && override.rule.normalized_query == query) ||
|
||||
(override.rule.match == override_t::MATCH_CONTAINS &&
|
||||
StringUtils::contains_word(query, override.rule.normalized_query));
|
||||
bool query_match = (override.rule.match == override_t::MATCH_EXACT && override.rule.normalized_query == query) ||
|
||||
(override.rule.match == override_t::MATCH_CONTAINS &&
|
||||
StringUtils::contains_word(query, override.rule.normalized_query));
|
||||
|
||||
if(!filter_by_match && !query_match) {
|
||||
return false;
|
||||
}
|
||||
if(!filter_by_match && !query_match) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!override.rule.filter_by.empty() && override.rule.filter_by != filter_query) {
|
||||
return false;
|
||||
if(!override.rule.filter_by.empty() && override.rule.filter_by != filter_query) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// have to ensure that dropped hits take precedence over added hits
|
||||
@ -953,7 +957,7 @@ void Collection::curate_results(string& actual_query, const string& filter_query
|
||||
|
||||
if(override.rule.tags == tags) {
|
||||
bool match_found = does_override_match(override, query, excluded_set, actual_query,
|
||||
filter_query, already_segmented, tags,
|
||||
filter_query, already_segmented, true,
|
||||
pinned_hits, hidden_hits, included_ids,
|
||||
excluded_ids, filter_overrides, filter_curated_hits,
|
||||
curated_sort_by, override_metadata);
|
||||
@ -1000,7 +1004,7 @@ void Collection::curate_results(string& actual_query, const string& filter_query
|
||||
}
|
||||
|
||||
bool match_found = does_override_match(override, query, excluded_set, actual_query,
|
||||
filter_query, already_segmented, tags,
|
||||
filter_query, already_segmented, true,
|
||||
pinned_hits, hidden_hits, included_ids,
|
||||
excluded_ids, filter_overrides, filter_curated_hits,
|
||||
curated_sort_by, override_metadata);
|
||||
@ -1018,7 +1022,7 @@ void Collection::curate_results(string& actual_query, const string& filter_query
|
||||
for(const auto& override_kv: overrides) {
|
||||
const auto& override = override_kv.second;
|
||||
bool match_found = does_override_match(override, query, excluded_set, actual_query, filter_query,
|
||||
already_segmented, tags, pinned_hits, hidden_hits, included_ids,
|
||||
already_segmented, false, pinned_hits, hidden_hits, included_ids,
|
||||
excluded_ids, filter_overrides, filter_curated_hits,
|
||||
curated_sort_by, override_metadata);
|
||||
if(match_found && override.stop_processing) {
|
||||
|
@ -2010,8 +2010,11 @@ bool Index::static_filter_query_eval(const override_t* override,
|
||||
std::vector<std::string>& tokens,
|
||||
filter_node_t*& filter_tree_root) const {
|
||||
std::string query = StringUtils::join(tokens, " ");
|
||||
bool tag_matched = (!override->rule.tags.empty() && override->rule.filter_by.empty() &&
|
||||
override->rule.query.empty());
|
||||
|
||||
if ((override->rule.match == override_t::MATCH_EXACT && override->rule.normalized_query == query) ||
|
||||
if (tag_matched ||
|
||||
(override->rule.match == override_t::MATCH_EXACT && override->rule.normalized_query == query) ||
|
||||
(override->rule.match == override_t::MATCH_CONTAINS &&
|
||||
StringUtils::contains_word(query, override->rule.normalized_query))) {
|
||||
filter_node_t* new_filter_tree_root = nullptr;
|
||||
|
@ -15,7 +15,7 @@ Option<bool> override_t::parse(const nlohmann::json& override_json, const std::s
|
||||
return Option<bool>(400, "Missing `rule` definition.");
|
||||
}
|
||||
|
||||
if (override_json["rule"].count("filter_by") == 0 &&
|
||||
if (override_json["rule"].count("filter_by") == 0 && override_json["rule"].count("tags") == 0 &&
|
||||
(override_json["rule"].count("query") == 0 || override_json["rule"].count("match") == 0)) {
|
||||
return Option<bool>(400, "The `rule` definition must contain a `query` and `match`.");
|
||||
}
|
||||
|
@ -3627,6 +3627,89 @@ TEST_F(CollectionOverrideTest, OverrideWithTagsWithoutStopProcessing) {
|
||||
collectionManager.drop_collection("coll1");
|
||||
}
|
||||
|
||||
TEST_F(CollectionOverrideTest, TagsOnlyRule) {
|
||||
Collection* coll1;
|
||||
|
||||
std::vector<field> fields = {field("name", field_types::STRING, false),
|
||||
field("category", field_types::STRING_ARRAY, true),};
|
||||
|
||||
coll1 = collectionManager.get_collection("coll1").get();
|
||||
if (coll1 == nullptr) {
|
||||
coll1 = collectionManager.create_collection("coll1", 1, fields, "").get();
|
||||
}
|
||||
|
||||
nlohmann::json doc1;
|
||||
doc1["id"] = "0";
|
||||
doc1["name"] = "queryA";
|
||||
doc1["category"] = {"kids"};
|
||||
|
||||
nlohmann::json doc2;
|
||||
doc2["id"] = "1";
|
||||
doc2["name"] = "queryA";
|
||||
doc2["category"] = {"kitchen"};
|
||||
|
||||
ASSERT_TRUE(coll1->add(doc1.dump()).ok());
|
||||
ASSERT_TRUE(coll1->add(doc2.dump()).ok());
|
||||
|
||||
std::vector<sort_by> sort_fields = {sort_by("_text_match", "DESC")};
|
||||
override_t override1;
|
||||
auto override_json1 = R"({
|
||||
"id": "ov-1",
|
||||
"rule": {
|
||||
"tags": ["listing"]
|
||||
},
|
||||
"filter_by": "category: kids"
|
||||
})"_json;
|
||||
|
||||
auto op = override_t::parse(override_json1, "ov-1", override1);
|
||||
ASSERT_TRUE(op.ok());
|
||||
coll1->add_override(override1);
|
||||
|
||||
auto results = coll1->search("queryA", {"name"}, "",
|
||||
{}, sort_fields, {2}, 10, 1, FREQUENCY,
|
||||
{false}, Index::DROP_TOKENS_THRESHOLD,
|
||||
spp::sparse_hash_set<std::string>(),
|
||||
spp::sparse_hash_set<std::string>(), 10, "", 30, 4, "title", 20, {}, {}, {}, 0,
|
||||
"<mark>", "</mark>", {}, 1000, true, false, true, "", false, 10000,
|
||||
4, 7, fallback, 4, {off}, 100, 100, 2, 2, false, "", true, 0, max_score, 100, 0,
|
||||
0, HASH, 30000, 2, "", {}, {}, "right_to_left",
|
||||
true, true, false, -1, "", "listing").get();
|
||||
|
||||
ASSERT_EQ(1, results["hits"].size());
|
||||
ASSERT_EQ("0", results["hits"][0]["document"]["id"].get<std::string>());
|
||||
|
||||
// with include rule
|
||||
override_t override2;
|
||||
auto override_json2 = R"({
|
||||
"id": "ov-2",
|
||||
"rule": {
|
||||
"tags": ["listing2"]
|
||||
},
|
||||
"includes": [
|
||||
{"id": "1", "position": 1}
|
||||
]
|
||||
})"_json;
|
||||
|
||||
op = override_t::parse(override_json2, "ov-2", override2);
|
||||
ASSERT_TRUE(op.ok());
|
||||
coll1->add_override(override2);
|
||||
|
||||
results = coll1->search("foobar", {"name"}, "",
|
||||
{}, sort_fields, {2}, 10, 1, FREQUENCY,
|
||||
{false}, Index::DROP_TOKENS_THRESHOLD,
|
||||
spp::sparse_hash_set<std::string>(),
|
||||
spp::sparse_hash_set<std::string>(), 10, "", 30, 4, "title", 20, {}, {}, {}, 0,
|
||||
"<mark>", "</mark>", {}, 1000, true, false, true, "", false, 10000,
|
||||
4, 7, fallback, 4, {off}, 100, 100, 2, 2, false, "", true, 0, max_score, 100, 0,
|
||||
0, HASH, 30000, 2, "", {}, {}, "right_to_left",
|
||||
true, true, false, -1, "", "listing2").get();
|
||||
|
||||
ASSERT_EQ(1, results["hits"].size());
|
||||
ASSERT_EQ("1", results["hits"][0]["document"]["id"].get<std::string>());
|
||||
|
||||
collectionManager.drop_collection("coll1");
|
||||
}
|
||||
|
||||
TEST_F(CollectionOverrideTest, MetadataValidation) {
|
||||
Collection* coll1;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user