Support wildcard facet_by. (#850)

* Support wildcard `facet_by`.

* Only trim `*` from wildcard `facet_by`.

* Add test for nested wildcard faceting.

* Nested fields also match `company*`.
This commit is contained in:
Harpreet Sangar 2023-01-09 12:45:59 +05:30 committed by GitHub
parent 5f034f8b3b
commit 37d3d6b256
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 74 additions and 6 deletions

View File

@ -4270,7 +4270,18 @@ Option<bool> Collection::parse_facet(const std::string& facet_field, std::vector
a_facet.is_range_query = true;
facets.emplace_back(std::move(a_facet));
} else {//normal facet
} else if (facet_field.find('*') != std::string::npos) { // Wildcard
// Trim * from the end.
auto prefix = facet_field.substr(0, facet_field.size() - 1);
auto pair = search_schema.equal_prefix_range(prefix);
// Collect the fields that match the prefix and are marked as facet.
for (auto field = pair.first; field != pair.second; field++) {
if (field->facet) {
facets.emplace_back(facet(field->name));
}
}
} else {//normal facet
facets.emplace_back(facet(facet_field));
}

View File

@ -946,7 +946,8 @@ TEST_F(CollectionFacetingTest, FacetByNestedIntField) {
"enable_nested_fields": true,
"fields": [
{"name": "details", "type": "object", "optional": false },
{"name": "company.num_employees", "type": "int32", "optional": false, "facet": true }
{"name": "company.num_employees", "type": "int32", "optional": false, "facet": true },
{"name": "companyRank", "type": "int32", "optional": false, "facet": true }
]
})"_json;
@ -956,12 +957,14 @@ TEST_F(CollectionFacetingTest, FacetByNestedIntField) {
auto doc1 = R"({
"details": {"count": 1000},
"company": {"num_employees": 2000}
"company": {"num_employees": 2000},
"companyRank": 100
})"_json;
auto doc2 = R"({
"details": {"count": 2000},
"company": {"num_employees": 2000}
"company": {"num_employees": 2000},
"companyRank": 101
})"_json;
ASSERT_TRUE(coll1->add(doc1.dump(), CREATE).ok());
@ -979,6 +982,20 @@ TEST_F(CollectionFacetingTest, FacetByNestedIntField) {
ASSERT_EQ(1, results["facet_counts"][0]["counts"].size());
ASSERT_EQ(2, results["facet_counts"][0]["counts"][0]["count"].get<size_t>());
ASSERT_EQ("2000", results["facet_counts"][0]["counts"][0]["value"].get<std::string>());
// Nested wildcard faceting
std::vector<facet> wildcard_facets;
coll1->parse_facet("company.*", wildcard_facets);
ASSERT_EQ(1, wildcard_facets.size());
ASSERT_EQ("company.num_employees", wildcard_facets[0].field_name);
wildcard_facets.clear();
coll1->parse_facet("company*", wildcard_facets);
ASSERT_EQ(2, wildcard_facets.size());
ASSERT_EQ("company.num_employees", wildcard_facets[0].field_name);
ASSERT_EQ("companyRank", wildcard_facets[1].field_name);
}
TEST_F(CollectionFacetingTest, FacetParseTest){
@ -986,6 +1003,8 @@ TEST_F(CollectionFacetingTest, FacetParseTest){
field("score", field_types::INT32, true),
field("grade", field_types::INT32, true),
field("rank", field_types::INT32, true),
field("range", field_types::INT32, true),
field("scale", field_types::INT32, false),
};
Collection* coll1 = collectionManager.create_collection("coll1", 1, fields).get();
@ -1021,16 +1040,53 @@ TEST_F(CollectionFacetingTest, FacetParseTest){
ASSERT_STREQ("score", normal_facets[0].field_name.c_str());
ASSERT_STREQ("grade", normal_facets[1].field_name.c_str());
std::vector<std::string> wildcard_facet_fields {
"ran*",
"sc*",
};
std::vector<facet> wildcard_facets;
for(const std::string & facet_field: wildcard_facet_fields) {
coll1->parse_facet(facet_field, wildcard_facets);
}
ASSERT_EQ(3, wildcard_facets.size());
ASSERT_EQ("rank", wildcard_facets[0].field_name);
ASSERT_EQ("range", wildcard_facets[1].field_name);
ASSERT_EQ("score", wildcard_facets[2].field_name);
wildcard_facets.clear();
coll1->parse_facet("*", wildcard_facets);
// Last field is not a facet.
ASSERT_EQ(fields.size() - 1, wildcard_facets.size());
std::vector<std::string> expected;
expected.resize(fields.size() - 1);
std::transform(fields.begin(), fields.end() - 1, expected.begin(), [] (const field& f) -> string {
return f.name;
});
std::sort(expected.begin(), expected.end());
std::vector<std::string> result;
result.resize(wildcard_facets.size());
std::transform(wildcard_facets.begin(), wildcard_facets.end(), result.begin(), [] (const facet& f) -> string {
return f.field_name;
});
std::sort(result.begin(), result.end());
for (size_t i = 0; i < wildcard_facets.size(); i++) {
ASSERT_EQ(expected[i], result[i]);
}
std::vector<std::string> mixed_facet_fields {
"score",
"grade(A:[80, 100], B:[60, 80], C:[40, 60])",
"rank"
"ra*",
};
std::vector<facet> mixed_facets;
for(const std::string & facet_field: mixed_facet_fields) {
coll1->parse_facet(facet_field, mixed_facets);
}
ASSERT_EQ(3, mixed_facets.size());
ASSERT_EQ(4, mixed_facets.size());
ASSERT_STREQ("score", mixed_facets[0].field_name.c_str());
@ -1039,6 +1095,7 @@ TEST_F(CollectionFacetingTest, FacetParseTest){
ASSERT_GT(mixed_facets[1].facet_range_map.size(), 0);
ASSERT_STREQ("rank", mixed_facets[2].field_name.c_str());
ASSERT_EQ("range", mixed_facets[3].field_name);
}
TEST_F(CollectionFacetingTest, RangeFacetTest) {