mirror of
https://github.com/typesense/typesense.git
synced 2025-05-21 22:33:27 +08:00
Support id !=
This commit is contained in:
parent
91dd04add2
commit
efac704f1b
@ -19,7 +19,7 @@ struct filter {
|
||||
std::string field_name;
|
||||
std::vector<std::string> values;
|
||||
std::vector<NUM_COMPARATOR> comparators;
|
||||
// Would be set when `field: != ...` is encountered with a string field or `field: != [ ... ]` is encountered in the
|
||||
// Would be set when `field: != ...` is encountered with id/string field or `field: != [ ... ]` is encountered in the
|
||||
// case of int and float fields. During filtering, all the results of matching the field against the values are
|
||||
// aggregated and then this flag is checked if negation on the aggregated result is required.
|
||||
bool apply_not_equals = false;
|
||||
|
@ -422,7 +422,10 @@ Option<bool> toFilter(const std::string expression,
|
||||
id_comparator = EQUALS;
|
||||
while (++filter_value_index < raw_value.size() && raw_value[filter_value_index] == ' ');
|
||||
} else if (raw_value.size() >= 2 && raw_value[0] == '!' && raw_value[1] == '=') {
|
||||
return Option<bool>(400, "Not equals filtering is not supported on the `id` field.");
|
||||
id_comparator = NOT_EQUALS;
|
||||
filter_exp.apply_not_equals = true;
|
||||
filter_value_index++;
|
||||
while (++filter_value_index < raw_value.size() && raw_value[filter_value_index] == ' ');
|
||||
}
|
||||
if (filter_value_index != 0) {
|
||||
raw_value = raw_value.substr(filter_value_index);
|
||||
|
@ -620,11 +620,6 @@ void filter_result_iterator_t::init() {
|
||||
}
|
||||
|
||||
if (a_filter.field_name == "id") {
|
||||
if (a_filter.values.empty()) {
|
||||
is_valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// we handle `ids` separately
|
||||
std::vector<uint32_t> result_ids;
|
||||
for (const auto& id_str : a_filter.values) {
|
||||
@ -637,6 +632,16 @@ void filter_result_iterator_t::init() {
|
||||
filter_result.docs = new uint32_t[result_ids.size()];
|
||||
std::copy(result_ids.begin(), result_ids.end(), filter_result.docs);
|
||||
|
||||
if (a_filter.apply_not_equals) {
|
||||
apply_not_equals(index->seq_ids->uncompress(), index->seq_ids->num_ids(),
|
||||
filter_result.docs, filter_result.count);
|
||||
}
|
||||
|
||||
if (filter_result.count == 0) {
|
||||
is_valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
seq_id = filter_result.docs[result_index];
|
||||
is_filter_result_initialized = true;
|
||||
approx_filter_ids_length = filter_result.count;
|
||||
@ -1660,6 +1665,11 @@ void filter_result_iterator_t::compute_result() {
|
||||
apply_not_equals(index->seq_ids->uncompress(), index->seq_ids->num_ids(), filter_result.docs, filter_result.count);
|
||||
}
|
||||
|
||||
if (filter_result.count == 0) {
|
||||
is_valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
result_index = 0;
|
||||
seq_id = filter_result.docs[result_index];
|
||||
is_filter_result_initialized = true;
|
||||
|
@ -1231,6 +1231,16 @@ TEST_F(CollectionFilteringTest, FilteringViaDocumentIds) {
|
||||
ASSERT_EQ(1, results["hits"].size());
|
||||
ASSERT_STREQ("123", results["hits"][0]["document"]["id"].get<std::string>().c_str());
|
||||
|
||||
results = coll1->search("*",
|
||||
{}, "id: != 123",
|
||||
{}, sort_fields, {0}, 10, 1, FREQUENCY, {true}).get();
|
||||
|
||||
ASSERT_EQ(3, results["found"].get<size_t>());
|
||||
ASSERT_EQ(3, results["hits"].size());
|
||||
ASSERT_STREQ("125", results["hits"][0]["document"]["id"].get<std::string>().c_str());
|
||||
ASSERT_STREQ("127", results["hits"][1]["document"]["id"].get<std::string>().c_str());
|
||||
ASSERT_STREQ("129", results["hits"][2]["document"]["id"].get<std::string>().c_str());
|
||||
|
||||
// single ID with backtick
|
||||
|
||||
results = coll1->search("*",
|
||||
@ -1283,6 +1293,14 @@ TEST_F(CollectionFilteringTest, FilteringViaDocumentIds) {
|
||||
ASSERT_STREQ("125", results["hits"][1]["document"]["id"].get<std::string>().c_str());
|
||||
ASSERT_STREQ("127", results["hits"][2]["document"]["id"].get<std::string>().c_str());
|
||||
|
||||
results = coll1->search("*",
|
||||
{}, "id:!= [123,125] && num_employees: <300",
|
||||
{}, sort_fields, {0}, 10, 1, FREQUENCY, {true}).get();
|
||||
|
||||
ASSERT_EQ(1, results["found"].get<size_t>());
|
||||
ASSERT_EQ(1, results["hits"].size());
|
||||
ASSERT_STREQ("127", results["hits"][0]["document"]["id"].get<std::string>().c_str());
|
||||
|
||||
// empty id list not allowed
|
||||
auto res_op = coll1->search("*", {}, "id:=", {}, sort_fields, {0}, 10, 1, FREQUENCY, {true});
|
||||
ASSERT_FALSE(res_op.ok());
|
||||
@ -1296,13 +1314,6 @@ TEST_F(CollectionFilteringTest, FilteringViaDocumentIds) {
|
||||
ASSERT_FALSE(res_op.ok());
|
||||
ASSERT_EQ("Error with filter field `id`: Filter value cannot be empty.", res_op.error());
|
||||
|
||||
// not equals is not supported yet
|
||||
res_op = coll1->search("*",
|
||||
{}, "id:!= [123,125] && num_employees: <300",
|
||||
{}, sort_fields, {0}, 10, 1, FREQUENCY, {true});
|
||||
ASSERT_FALSE(res_op.ok());
|
||||
ASSERT_EQ("Not equals filtering is not supported on the `id` field.", res_op.error());
|
||||
|
||||
// when no IDs exist
|
||||
results = coll1->search("*",
|
||||
{}, "id: [1000] && num_employees: <300",
|
||||
@ -1397,9 +1408,10 @@ TEST_F(CollectionFilteringTest, NumericalFilteringWithArray) {
|
||||
TEST_F(CollectionFilteringTest, NegationOperatorBasics) {
|
||||
Collection *coll1;
|
||||
|
||||
std::vector<field> fields = {field("title", field_types::STRING, false),
|
||||
field("artist", field_types::STRING, false),
|
||||
field("points", field_types::INT32, false),};
|
||||
std::vector<field> fields = {
|
||||
field("title", field_types::STRING, false),
|
||||
field("artist", field_types::STRING, false),
|
||||
field("points", field_types::INT32, false),};
|
||||
|
||||
coll1 = collectionManager.get_collection("coll1").get();
|
||||
if(coll1 == nullptr) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user