mirror of
https://github.com/typesense/typesense.git
synced 2025-05-22 14:55:26 +08:00
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:
parent
5f034f8b3b
commit
37d3d6b256
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user