diff --git a/include/field.h b/include/field.h
index 18a1d4b7..7eee5c79 100644
--- a/include/field.h
+++ b/include/field.h
@@ -513,7 +513,7 @@ struct filter {
bool apply_not_equals = false;
// Would store `Foo` in case of a filter expression like `$Foo(bar := baz)`
- std::string referenced_collection_name;
+ std::string referenced_collection_name = "";
static const std::string RANGE_OPERATOR() {
return "..";
diff --git a/test/collection_specific_more_test.cpp b/test/collection_specific_more_test.cpp
index 070b0580..8afdaf84 100644
--- a/test/collection_specific_more_test.cpp
+++ b/test/collection_specific_more_test.cpp
@@ -1973,3 +1973,209 @@ TEST_F(CollectionSpecificMoreTest, CrossFieldTypoAndPrefixWithWeights) {
"", "", {2, 3}).get();
ASSERT_EQ(1, res["hits"].size());
}
+
+TEST_F(CollectionSpecificMoreTest, RearrangingFilterTree) {
+ nlohmann::json schema =
+ R"({
+ "name": "Collection",
+ "fields": [
+ {"name": "name", "type": "string"},
+ {"name": "age", "type": "int32"},
+ {"name": "years", "type": "int32[]"},
+ {"name": "rating", "type": "float"}
+ ]
+ })"_json;
+
+ Collection* coll = collectionManager.create_collection(schema).get();
+
+ std::ifstream infile(std::string(ROOT_DIR)+"test/numeric_array_documents.jsonl");
+ std::string json_line;
+ while (std::getline(infile, json_line)) {
+ auto add_op = coll->add(json_line);
+ ASSERT_TRUE(add_op.ok());
+ }
+ infile.close();
+
+ const std::string doc_id_prefix = std::to_string(coll->get_collection_id()) + "_" + Collection::DOC_ID_PREFIX + "_";
+ filter_node_t* filter_tree_root = nullptr;
+ Option filter_op = filter::parse_filter_query("years:>2000 && ((age:<30 && rating:>5) || (age:>50 && rating:<5))",
+ coll->get_schema(), store, doc_id_prefix, filter_tree_root);
+ ASSERT_TRUE(filter_op.ok());
+ std::unique_ptr filter_tree_root_guard(filter_tree_root);
+
+ // &&
+ // / \
+ // years>2000 ||
+ // 4 / \
+ // / &&
+ // && / \
+ // / \ age>50 rating<5
+ // / \ 1 2
+ // / \
+ // age<30 rating>5
+ // 2 3
+ ASSERT_TRUE(filter_tree_root != nullptr);
+ ASSERT_TRUE(filter_tree_root->isOperator);
+ ASSERT_EQ(filter_tree_root->filter_operator, AND);
+
+ auto root = filter_tree_root->left;
+ ASSERT_TRUE(root != nullptr);
+ ASSERT_FALSE(root->isOperator);
+ ASSERT_EQ(root->filter_exp.field_name, "years");
+ ASSERT_TRUE(root->left == nullptr);
+ ASSERT_TRUE(root->right == nullptr);
+
+ root = filter_tree_root->right;
+ ASSERT_TRUE(root != nullptr);
+ ASSERT_TRUE(root->isOperator);
+ ASSERT_EQ(root->filter_operator, OR);
+
+ root = filter_tree_root->right->left;
+ ASSERT_TRUE(root != nullptr);
+ ASSERT_TRUE(root->isOperator);
+ ASSERT_EQ(root->filter_operator, AND);
+
+ root = filter_tree_root->right->left->left;
+ ASSERT_TRUE(root != nullptr);
+ ASSERT_FALSE(root->isOperator);
+ ASSERT_EQ(root->filter_exp.field_name, "age");
+ ASSERT_EQ(root->filter_exp.comparators.front(), LESS_THAN);
+ ASSERT_EQ(root->filter_exp.values.front(), "30");
+ ASSERT_TRUE(root->left == nullptr);
+ ASSERT_TRUE(root->right == nullptr);
+
+ root = filter_tree_root->right->left->right;
+ ASSERT_TRUE(root != nullptr);
+ ASSERT_FALSE(root->isOperator);
+ ASSERT_EQ(root->filter_exp.field_name, "rating");
+ ASSERT_EQ(root->filter_exp.comparators.front(), GREATER_THAN);
+ ASSERT_EQ(root->filter_exp.values.front(), "5");
+ ASSERT_TRUE(root->left == nullptr);
+ ASSERT_TRUE(root->right == nullptr);
+
+ root = filter_tree_root->right->right;
+ ASSERT_TRUE(root != nullptr);
+ ASSERT_TRUE(root->isOperator);
+ ASSERT_EQ(root->filter_operator, AND);
+
+ root = filter_tree_root->right->right->left;
+ ASSERT_TRUE(root != nullptr);
+ ASSERT_FALSE(root->isOperator);
+ ASSERT_EQ(root->filter_exp.field_name, "age");
+ ASSERT_EQ(root->filter_exp.comparators.front(), GREATER_THAN);
+ ASSERT_EQ(root->filter_exp.values.front(), "50");
+ ASSERT_TRUE(root->left == nullptr);
+ ASSERT_TRUE(root->right == nullptr);
+
+ root = filter_tree_root->right->right->right;
+ ASSERT_TRUE(root != nullptr);
+ ASSERT_FALSE(root->isOperator);
+ ASSERT_EQ(root->filter_exp.field_name, "rating");
+ ASSERT_EQ(root->filter_exp.comparators.front(), LESS_THAN);
+ ASSERT_EQ(root->filter_exp.values.front(), "5");
+ ASSERT_TRUE(root->left == nullptr);
+ ASSERT_TRUE(root->right == nullptr);
+
+ filter_result_t result;
+ // Internally calls rearranging_recursive_filter
+ coll->_get_index()->do_filtering_with_lock(filter_tree_root, result);
+
+ // &&
+ // / \
+ // || years>2000
+ // / \
+ // && \
+ // / \ \
+ // age>50 rating<5 &&
+ // / \
+ // age<30 rating>5
+ ASSERT_TRUE(filter_tree_root != nullptr);
+ ASSERT_TRUE(filter_tree_root->isOperator);
+ ASSERT_EQ(filter_tree_root->filter_operator, AND);
+
+ root = filter_tree_root->left;
+ ASSERT_TRUE(root != nullptr);
+ ASSERT_TRUE(root->isOperator);
+ ASSERT_EQ(root->filter_operator, OR);
+
+ root = filter_tree_root->left->left;
+ ASSERT_TRUE(root != nullptr);
+ ASSERT_TRUE(root->isOperator);
+ ASSERT_EQ(root->filter_operator, AND);
+
+ root = filter_tree_root->left->left->left;
+ ASSERT_TRUE(root != nullptr);
+ ASSERT_FALSE(root->isOperator);
+ ASSERT_EQ(root->filter_exp.field_name, "age");
+ ASSERT_EQ(root->filter_exp.comparators.front(), GREATER_THAN);
+ ASSERT_EQ(root->filter_exp.values.front(), "50");
+ ASSERT_TRUE(root->left == nullptr);
+ ASSERT_TRUE(root->right == nullptr);
+
+ root = filter_tree_root->left->left->right;
+ ASSERT_TRUE(root != nullptr);
+ ASSERT_FALSE(root->isOperator);
+ ASSERT_EQ(root->filter_exp.field_name, "rating");
+ ASSERT_EQ(root->filter_exp.comparators.front(), LESS_THAN);
+ ASSERT_EQ(root->filter_exp.values.front(), "5");
+ ASSERT_TRUE(root->left == nullptr);
+ ASSERT_TRUE(root->right == nullptr);
+
+ root = filter_tree_root->left->right;
+ ASSERT_TRUE(root != nullptr);
+ ASSERT_TRUE(root->isOperator);
+ ASSERT_EQ(root->filter_operator, AND);
+
+ root = filter_tree_root->left->right->left;
+ ASSERT_TRUE(root != nullptr);
+ ASSERT_FALSE(root->isOperator);
+ ASSERT_EQ(root->filter_exp.field_name, "age");
+ ASSERT_EQ(root->filter_exp.comparators.front(), LESS_THAN);
+ ASSERT_EQ(root->filter_exp.values.front(), "30");
+ ASSERT_TRUE(root->left == nullptr);
+ ASSERT_TRUE(root->right == nullptr);
+
+ root = filter_tree_root->left->right->right;
+ ASSERT_TRUE(root != nullptr);
+ ASSERT_FALSE(root->isOperator);
+ ASSERT_EQ(root->filter_exp.field_name, "rating");
+ ASSERT_EQ(root->filter_exp.comparators.front(), GREATER_THAN);
+ ASSERT_EQ(root->filter_exp.values.front(), "5");
+ ASSERT_TRUE(root->left == nullptr);
+ ASSERT_TRUE(root->right == nullptr);
+
+ root = filter_tree_root->right;
+ ASSERT_TRUE(root != nullptr);
+ ASSERT_FALSE(root->isOperator);
+ ASSERT_EQ(root->filter_exp.field_name, "years");
+ ASSERT_TRUE(root->left == nullptr);
+ ASSERT_TRUE(root->right == nullptr);
+}
+
+TEST_F(CollectionSpecificMoreTest, ApproxFilterMatchCount) {
+ nlohmann::json schema =
+ R"({
+ "name": "Collection",
+ "fields": [
+ {"name": "name", "type": "string"},
+ {"name": "age", "type": "int32"},
+ {"name": "years", "type": "int32[]"},
+ {"name": "rating", "type": "float"}
+ ]
+ })"_json;
+
+ Collection *coll = collectionManager.create_collection(schema).get();
+
+ std::ifstream infile(std::string(ROOT_DIR) + "test/numeric_array_documents.jsonl");
+ std::string json_line;
+ while (std::getline(infile, json_line)) {
+ auto add_op = coll->add(json_line);
+ ASSERT_TRUE(add_op.ok());
+ }
+ infile.close();
+
+ uint32_t approx_count;
+ coll->get_approximate_reference_filter_ids("years:>2000 && ((age:<30 && rating:>5) || (age:>50 && rating:<5))",
+ approx_count);
+ ASSERT_EQ(approx_count, 3);
+}
\ No newline at end of file