Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuri Gorshenin <y@maps.me>2017-02-21 12:45:10 +0300
committerYuri Gorshenin <y@maps.me>2017-02-21 12:45:10 +0300
commit8f2e48941c7937c03957ca7ef6f1bb669f59a0be (patch)
treeb440d026857ebddc1e8d86ac799a29f4927484e0
parent009388f72e98d9eee5a3a2d44e734fcec2f68a7d (diff)
[search] Added filtering by hotel type.
-rw-r--r--indexer/ftypes_matcher.cpp68
-rw-r--r--indexer/ftypes_matcher.hpp31
-rw-r--r--search/hotels_filter.cpp3
-rw-r--r--search/hotels_filter.hpp50
-rw-r--r--search/search_integration_tests/helpers.cpp7
-rw-r--r--search/search_integration_tests/helpers.hpp2
-rw-r--r--search/search_integration_tests/processor_test.cpp54
7 files changed, 182 insertions, 33 deletions
diff --git a/indexer/ftypes_matcher.cpp b/indexer/ftypes_matcher.cpp
index d3eefbbc7b..9f60ceba7e 100644
--- a/indexer/ftypes_matcher.cpp
+++ b/indexer/ftypes_matcher.cpp
@@ -1,8 +1,11 @@
#include "indexer/ftypes_matcher.hpp"
+#include "indexer/classificator.hpp"
#include "indexer/feature.hpp"
#include "indexer/feature_data.hpp"
-#include "indexer/classificator.hpp"
+
+#include "base/assert.hpp"
+#include "base/buffer_vector.hpp"
#include <algorithm>
#include <map>
@@ -373,8 +376,19 @@ IsBookingChecker const & IsBookingChecker::Instance()
IsHotelChecker::IsHotelChecker()
{
Classificator const & c = classif();
- for (auto const & tag : GetHotelTags())
- m_types.push_back(c.GetTypeByPath({"tourism", tag}));
+ for (size_t i = 0; i < static_cast<size_t>(Type::Count); ++i)
+ {
+ auto const hotelType = static_cast<Type>(i);
+ auto const * const tag = GetHotelTypeTag(hotelType);
+ auto const type = c.GetTypeByPath({"tourism", tag});
+
+ m_types.push_back(type);
+
+ m_sortedTypes[i].first = type;
+ m_sortedTypes[i].second = hotelType;
+ }
+
+ sort(m_sortedTypes.begin(), m_sortedTypes.end());
}
IsHotelChecker const & IsHotelChecker::Instance()
@@ -383,11 +397,51 @@ IsHotelChecker const & IsHotelChecker::Instance()
return inst;
}
-vector<string> const & IsHotelChecker::GetHotelTags()
+unsigned IsHotelChecker::GetHotelTypesMask(FeatureType const & ft) const
+{
+ feature::TypesHolder types(ft);
+ buffer_vector<uint32_t, feature::kMaxTypesCount> sortedTypes(types.begin(), types.end());
+ sort(sortedTypes.begin(), sortedTypes.end());
+
+ unsigned mask = 0;
+ size_t i = 0;
+ size_t j = 0;
+ while (i < sortedTypes.size() && j < m_sortedTypes.size())
+ {
+ if (sortedTypes[i] < m_sortedTypes[j].first)
+ {
+ ++i;
+ }
+ else if (sortedTypes[i] > m_sortedTypes[j].first)
+ {
+ ++j;
+ }
+ else
+ {
+ mask |= 1U << static_cast<unsigned>(m_sortedTypes[j].second);
+ ++i;
+ ++j;
+ }
+ }
+
+ return mask;
+}
+
+// static
+char const * const IsHotelChecker::GetHotelTypeTag(Type type)
{
- static vector<string> hotelTags = {"hotel", "apartment", "camp_site", "chalet",
- "guest_house", "hostel", "motel", "resort"};
- return hotelTags;
+ switch (type)
+ {
+ case Type::Hotel: return "hotel";
+ case Type::Apartment: return "apartment";
+ case Type::CampSite: return "camp_site";
+ case Type::Chalet: return "chalet";
+ case Type::GuestHouse: return "guest_house";
+ case Type::Hostel: return "hostel";
+ case Type::Motel: return "motel";
+ case Type::Resort: return "resort";
+ case Type::Count: CHECK(false, ("Can't get hotel type tag")); return "";
+ }
}
IsWifiChecker::IsWifiChecker()
diff --git a/indexer/ftypes_matcher.hpp b/indexer/ftypes_matcher.hpp
index 760d391120..dc0da449a7 100644
--- a/indexer/ftypes_matcher.hpp
+++ b/indexer/ftypes_matcher.hpp
@@ -3,7 +3,9 @@
#include "base/base.hpp"
#include "std/algorithm.hpp"
+#include "std/array.hpp"
#include "std/initializer_list.hpp"
+#include "std/limits.hpp"
#include "std/string.hpp"
#include "std/utility.hpp"
#include "std/vector.hpp"
@@ -160,11 +162,34 @@ public:
class IsHotelChecker : public BaseChecker
{
- IsHotelChecker();
-
public:
+ enum class Type
+ {
+ Hotel,
+ Apartment,
+ CampSite,
+ Chalet,
+ GuestHouse,
+ Hostel,
+ Motel,
+ Resort,
+
+ Count
+ };
+
+ static_assert(static_cast<size_t>(Type::Count) <= CHAR_BIT * sizeof(unsigned),
+ "Too many types of hotels");
+
static IsHotelChecker const & Instance();
- static vector<string> const & GetHotelTags();
+
+ static char const * const GetHotelTypeTag(Type type);
+
+ unsigned GetHotelTypesMask(FeatureType const & ft) const;
+
+private:
+ IsHotelChecker();
+
+ array<pair<uint32_t, Type>, static_cast<size_t>(Type::Count)> m_sortedTypes;
};
// WiFi is a type in classificator.txt,
diff --git a/search/hotels_filter.cpp b/search/hotels_filter.cpp
index 9a64085449..b3fd8b9785 100644
--- a/search/hotels_filter.cpp
+++ b/search/hotels_filter.cpp
@@ -2,6 +2,7 @@
#include "indexer/feature.hpp"
#include "indexer/feature_meta.hpp"
+#include "indexer/ftypes_matcher.hpp"
#include "base/assert.hpp"
@@ -40,6 +41,8 @@ void Description::FromFeature(FeatureType & ft)
if (strings::to_int(priceRate, pr))
m_priceRate = pr;
}
+
+ m_types = ftypes::IsHotelChecker::Instance().GetHotelTypesMask(ft);
}
// Rule --------------------------------------------------------------------------------------------
diff --git a/search/hotels_filter.hpp b/search/hotels_filter.hpp
index 86f63e01ad..4adbc23877 100644
--- a/search/hotels_filter.hpp
+++ b/search/hotels_filter.hpp
@@ -4,10 +4,12 @@
#include "search/cbv.hpp"
#include "search/mwm_context.hpp"
+#include "indexer/ftypes_matcher.hpp"
#include "indexer/mwm_set.hpp"
#include "std/map.hpp"
#include "std/shared_ptr.hpp"
+#include "std/sstream.hpp"
#include "std/string.hpp"
#include "std/unique_ptr.hpp"
#include "std/utility.hpp"
@@ -63,6 +65,7 @@ struct Description
Rating::Value m_rating = Rating::kDefault;
PriceRate::Value m_priceRate = PriceRate::kDefault;
+ unsigned m_types = 0;
};
struct Rule
@@ -83,7 +86,7 @@ struct EqRule final : public Rule
{
using Value = typename Field::Value;
- EqRule(Value value) : m_value(value) {}
+ explicit EqRule(Value value) : m_value(value) {}
// Rule overrides:
bool Matches(Description const & d) const override
@@ -112,7 +115,7 @@ struct LtRule final : public Rule
{
using Value = typename Field::Value;
- LtRule(Value value) : m_value(value) {}
+ explicit LtRule(Value value) : m_value(value) {}
// Rule overrides:
bool Matches(Description const & d) const override
@@ -141,7 +144,7 @@ struct LeRule final : public Rule
{
using Value = typename Field::Value;
- LeRule(Value value) : m_value(value) {}
+ explicit LeRule(Value value) : m_value(value) {}
// Rule overrides:
bool Matches(Description const & d) const override
@@ -171,7 +174,7 @@ struct GtRule final : public Rule
{
using Value = typename Field::Value;
- GtRule(Value value) : m_value(value) {}
+ explicit GtRule(Value value) : m_value(value) {}
// Rule overrides:
bool Matches(Description const & d) const override
@@ -200,7 +203,7 @@ struct GeRule final : public Rule
{
using Value = typename Field::Value;
- GeRule(Value value) : m_value(value) {}
+ explicit GeRule(Value value) : m_value(value) {}
// Rule overrides:
bool Matches(Description const & d) const override
@@ -297,6 +300,35 @@ struct OrRule final : public Rule
shared_ptr<Rule> m_rhs;
};
+struct OneOfRule final : public Rule
+{
+ explicit OneOfRule(unsigned types) : m_types(types) {}
+
+ // Rule overrides:
+ bool Matches(Description const & d) const override { return (d.m_types & m_types) != 0; }
+
+ bool IdenticalTo(Rule const & rhs) const override
+ {
+ auto const * r = dynamic_cast<OneOfRule const *>(&rhs);
+ return r && m_types == r->m_types;
+ }
+
+ string ToString() const override
+ {
+ ostringstream os;
+ os << "[ one of:";
+ for (size_t i = 0; i < static_cast<size_t>(ftypes::IsHotelChecker::Type::Count); ++i)
+ {
+ auto const type = static_cast<ftypes::IsHotelChecker::Type>(i);
+ os << " " << ftypes::IsHotelChecker::GetHotelTypeTag(type);
+ }
+ os << " ]";
+ return os.str();
+ }
+
+ unsigned m_types;
+};
+
template <typename Field>
shared_ptr<Rule> Eq(typename Field::Value value)
{
@@ -337,6 +369,14 @@ inline shared_ptr<Rule> Or(shared_ptr<Rule> lhs, shared_ptr<Rule> rhs)
return make_shared<OrRule>(lhs, rhs);
}
+inline shared_ptr<Rule> Is(ftypes::IsHotelChecker::Type type)
+{
+ CHECK(type != ftypes::IsHotelChecker::Type::Count, ());
+ return make_shared<OneOfRule>(1U << static_cast<unsigned>(type));
+}
+
+inline shared_ptr<Rule> OneOf(unsigned types) { return make_shared<OneOfRule>(types); }
+
class HotelsFilter
{
public:
diff --git a/search/search_integration_tests/helpers.cpp b/search/search_integration_tests/helpers.cpp
index b1849dad69..c537163d49 100644
--- a/search/search_integration_tests/helpers.cpp
+++ b/search/search_integration_tests/helpers.cpp
@@ -72,6 +72,13 @@ bool SearchTest::ResultsMatch(vector<search::Result> const & results, TRules con
return MatchResults(m_engine, rules, results);
}
+bool SearchTest::ResultsMatch(SearchParams const & params, TRules const & rules)
+{
+ tests_support::TestSearchRequest request(m_engine, params, m_viewport);
+ request.Run();
+ return ResultsMatch(request.Results(), rules);
+}
+
unique_ptr<tests_support::TestSearchRequest> SearchTest::MakeRequest(string const & query)
{
SearchParams params;
diff --git a/search/search_integration_tests/helpers.hpp b/search/search_integration_tests/helpers.hpp
index 0c80cad599..199e8b11f3 100644
--- a/search/search_integration_tests/helpers.hpp
+++ b/search/search_integration_tests/helpers.hpp
@@ -111,6 +111,8 @@ public:
bool ResultsMatch(vector<search::Result> const & results, TRules const & rules);
+ bool ResultsMatch(SearchParams const & params, TRules const & rules);
+
unique_ptr<tests_support::TestSearchRequest> MakeRequest(string const & query);
size_t CountFeatures(m2::RectD const & rect);
diff --git a/search/search_integration_tests/processor_test.cpp b/search/search_integration_tests/processor_test.cpp
index ec892e44a6..c61d46aa3a 100644
--- a/search/search_integration_tests/processor_test.cpp
+++ b/search/search_integration_tests/processor_test.cpp
@@ -12,6 +12,7 @@
#include "generator/generator_tests_support/test_mwm_builder.hpp"
#include "indexer/feature.hpp"
+#include "indexer/ftypes_matcher.hpp"
#include "indexer/index.hpp"
#include "geometry/mercator.hpp"
@@ -36,8 +37,10 @@ namespace
class TestHotel : public TestPOI
{
public:
+ using Type = ftypes::IsHotelChecker::Type;
+
TestHotel(m2::PointD const & center, string const & name, string const & lang, float rating,
- int priceRate)
+ int priceRate, Type type)
: TestPOI(center, name, lang), m_rating(rating), m_priceRate(priceRate)
{
CHECK_GREATER_OR_EQUAL(m_rating, 0.0, ());
@@ -46,7 +49,7 @@ public:
CHECK_GREATER_OR_EQUAL(m_priceRate, 0, ());
CHECK_LESS_OR_EQUAL(m_priceRate, 5, ());
- SetTypes({{"tourism", "hotel"}});
+ SetTypes({{"tourism", ftypes::IsHotelChecker::GetHotelTypeTag(type)}});
}
// TestPOI overrides:
@@ -671,10 +674,14 @@ UNIT_CLASS_TEST(ProcessorTest, HotelsFiltering)
{
char const countryName[] = "Wonderland";
- TestHotel h1(m2::PointD(0, 0), "h1", "en", 8.0 /* rating */, 2 /* priceRate */);
- TestHotel h2(m2::PointD(0, 1), "h2", "en", 7.0 /* rating */, 5 /* priceRate */);
- TestHotel h3(m2::PointD(1, 0), "h3", "en", 9.0 /* rating */, 0 /* priceRate */);
- TestHotel h4(m2::PointD(1, 1), "h4", "en", 2.0 /* rating */, 4 /* priceRate */);
+ TestHotel h1(m2::PointD(0, 0), "h1", "en", 8.0 /* rating */, 2 /* priceRate */,
+ TestHotel::Type::Hotel);
+ TestHotel h2(m2::PointD(0, 1), "h2", "en", 7.0 /* rating */, 5 /* priceRate */,
+ TestHotel::Type::Hostel);
+ TestHotel h3(m2::PointD(1, 0), "h3", "en", 9.0 /* rating */, 0 /* priceRate */,
+ TestHotel::Type::GuestHouse);
+ TestHotel h4(m2::PointD(1, 1), "h4", "en", 2.0 /* rating */, 4 /* priceRate */,
+ TestHotel::Type::GuestHouse);
auto id = BuildCountry(countryName, [&](TestMwmBuilder & builder) {
builder.Add(h1);
@@ -691,36 +698,47 @@ UNIT_CLASS_TEST(ProcessorTest, HotelsFiltering)
SetViewport(m2::RectD(m2::PointD(-1, -1), m2::PointD(2, 2)));
{
- TestSearchRequest request(m_engine, params, m_viewport);
- request.Run();
TRules rules = {ExactMatch(id, h1), ExactMatch(id, h2), ExactMatch(id, h3), ExactMatch(id, h4)};
- TEST(ResultsMatch(request.Results(), rules), ());
+ TEST(ResultsMatch(params, rules), ());
}
using namespace hotels_filter;
params.m_hotelsFilter = And(Gt<Rating>(7.0), Le<PriceRate>(2));
{
- TestSearchRequest request(m_engine, params, m_viewport);
- request.Run();
TRules rules = {ExactMatch(id, h1), ExactMatch(id, h3)};
- TEST(ResultsMatch(request.Results(), rules), ());
+ TEST(ResultsMatch(params, rules), ());
}
params.m_hotelsFilter = Or(Eq<Rating>(9.0), Le<PriceRate>(4));
{
- TestSearchRequest request(m_engine, params, m_viewport);
- request.Run();
TRules rules = {ExactMatch(id, h1), ExactMatch(id, h3), ExactMatch(id, h4)};
- TEST(ResultsMatch(request.Results(), rules), ());
+ TEST(ResultsMatch(params, rules), ());
}
params.m_hotelsFilter = Or(And(Eq<Rating>(7.0), Eq<PriceRate>(5)), Eq<PriceRate>(4));
{
- TestSearchRequest request(m_engine, params, m_viewport);
- request.Run();
TRules rules = {ExactMatch(id, h2), ExactMatch(id, h4)};
- TEST(ResultsMatch(request.Results(), rules), ());
+ TEST(ResultsMatch(params, rules), ());
+ }
+
+ params.m_hotelsFilter = Or(Is(TestHotel::Type::GuestHouse), Is(TestHotel::Type::Hostel));
+ {
+ TRules rules = {ExactMatch(id, h2), ExactMatch(id, h3), ExactMatch(id, h4)};
+ TEST(ResultsMatch(params, rules), ());
+ }
+
+ params.m_hotelsFilter = And(Gt<PriceRate>(3), Is(TestHotel::Type::GuestHouse));
+ {
+ TRules rules = {ExactMatch(id, h4)};
+ TEST(ResultsMatch(params, rules), ());
+ }
+
+ params.m_hotelsFilter = OneOf((1U << static_cast<unsigned>(TestHotel::Type::Hotel)) |
+ (1U << static_cast<unsigned>(TestHotel::Type::Hostel)));
+ {
+ TRules rules = {ExactMatch(id, h1), ExactMatch(id, h2)};
+ TEST(ResultsMatch(params, rules), ());
}
}