From 58df58f385a0454a3a7f06d7286a898643f65374 Mon Sep 17 00:00:00 2001 From: Yuri Gorshenin Date: Fri, 12 Feb 2016 12:22:12 +0300 Subject: [PATCH] [search] Implemented search by POI with house numbers. --- .../search_query_v2_test.cpp | 8 ++ search/search_tests_support/test_feature.cpp | 89 ++++++++++++++----- search/search_tests_support/test_feature.hpp | 30 ++++--- search/v2/features_layer_matcher.hpp | 4 - search/v2/search_model.cpp | 20 ++++- search/v2/search_model.hpp | 11 ++- 6 files changed, 121 insertions(+), 41 deletions(-) diff --git a/search/search_integration_tests/search_query_v2_test.cpp b/search/search_integration_tests/search_query_v2_test.cpp index eea1cdda72..297b007b3d 100644 --- a/search/search_integration_tests/search_query_v2_test.cpp +++ b/search/search_integration_tests/search_query_v2_test.cpp @@ -149,7 +149,11 @@ UNIT_CLASS_TEST(SearchQueryV2Test, Smoke) TestPOI busStop(m2::PointD(0, 0), "Bus stop", "en"); TestPOI tramStop(m2::PointD(0.0001, 0.0001), "Tram stop", "en"); TestPOI quantumTeleport1(m2::PointD(0.0002, 0.0002), "Quantum teleport 1", "en"); + TestPOI quantumTeleport2(m2::PointD(10, 10), "Quantum teleport 2", "en"); + quantumTeleport2.SetHouseNumber("3"); + quantumTeleport2.SetStreet(feynmanStreet); + TestPOI quantumCafe(m2::PointD(-0.0002, -0.0002), "Quantum cafe", "en"); TestPOI lantern1(m2::PointD(10.0005, 10.0005), "lantern 1", "en"); TestPOI lantern2(m2::PointD(10.0006, 10.0005), "lantern 2", "en"); @@ -214,6 +218,10 @@ UNIT_CLASS_TEST(SearchQueryV2Test, Smoke) TRules rules = {make_shared(wonderlandId, quantumTeleport2)}; TEST(ResultsMatch("teleport feynman street", rules), ()); } + { + TRules rules = {make_shared(wonderlandId, quantumTeleport2)}; + TEST(ResultsMatch("feynman street 3", rules), ()); + } { TRules rules = {make_shared(wonderlandId, feynmanHouse), make_shared(wonderlandId, lantern1)}; diff --git a/search/search_tests_support/test_feature.cpp b/search/search_tests_support/test_feature.cpp index 1c4fb52b61..4ac152e79a 100644 --- a/search/search_tests_support/test_feature.cpp +++ b/search/search_tests_support/test_feature.cpp @@ -4,6 +4,7 @@ #include "indexer/classificator.hpp" #include "indexer/feature.hpp" +#include "indexer/feature_algo.hpp" #include "indexer/ftypes_matcher.hpp" #include "coding/multilang_utf8_string.hpp" @@ -16,6 +17,11 @@ namespace search { namespace tests_support { +namespace +{ +double const kTestPrecision = 1e-4; +} // namespace + // TestFeature ------------------------------------------------------------------------------------- TestFeature::TestFeature(string const & name, string const & lang) : m_center(0, 0), m_hasCenter(false), m_name(name), m_lang(lang) @@ -38,27 +44,16 @@ bool TestFeature::Matches(FeatureType const & feature) const { uint8_t const langIndex = StringUtf8Multilang::GetLangIndex(m_lang); string name; - return feature.GetName(langIndex, name) && m_name == name; -} - -// TestPOI ----------------------------------------------------------------------------------------- -TestPOI::TestPOI(m2::PointD const & center, string const & name, string const & lang) - : TestFeature(center, name, lang) -{ -} - -void TestPOI::Serialize(FeatureBuilder1 & fb) const -{ - TestFeature::Serialize(fb); - auto const & classificator = classif(); - fb.SetType(classificator.GetTypeByPath({"railway", "station"})); -} - -string TestPOI::ToString() const -{ - ostringstream os; - os << "TestPOI [" << m_name << ", " << m_lang << ", " << DebugPrint(m_center) << "]"; - return os.str(); + bool const nameMatches = feature.GetName(langIndex, name) && m_name == name; + if (!nameMatches) + return false; + if (m_hasCenter) + { + auto const center = feature::GetCenter(feature); + if (!m_center.EqualDxDy(center, kTestPrecision)) + return false; + } + return true; } // TestCountry ------------------------------------------------------------------------------------- @@ -153,6 +148,40 @@ string TestStreet::ToString() const return os.str(); } +// TestPOI ----------------------------------------------------------------------------------------- +TestPOI::TestPOI(m2::PointD const & center, string const & name, string const & lang) + : TestFeature(center, name, lang) +{ +} + +void TestPOI::Serialize(FeatureBuilder1 & fb) const +{ + TestFeature::Serialize(fb); + auto const & classificator = classif(); + fb.SetType(classificator.GetTypeByPath({"railway", "station"})); + if (!m_houseNumber.empty()) + fb.AddHouseNumber(m_houseNumber); + if (!m_streetName.empty()) + fb.AddStreet(m_streetName); +} + +bool TestPOI::Matches(FeatureType const & feature) const +{ + return TestFeature::Matches(feature) && m_houseNumber == feature.GetHouseNumber(); +} + +string TestPOI::ToString() const +{ + ostringstream os; + os << "TestPOI [" << m_name << ", " << m_lang << ", " << DebugPrint(m_center); + if (!m_houseNumber.empty()) + os << ", " << m_houseNumber; + if (!m_streetName.empty()) + os << ", " << m_streetName; + os << "]"; + return os.str(); +} + // TestBuilding ------------------------------------------------------------------------------------ TestBuilding::TestBuilding(m2::PointD const & center, string const & name, string const & houseNumber, string const & lang) @@ -177,6 +206,7 @@ TestBuilding::TestBuilding(vector const & boundary, string const & n , m_houseNumber(houseNumber) , m_streetName(street.GetName()) { + ASSERT(!m_boundary.empty(), ()); } void TestBuilding::Serialize(FeatureBuilder1 & fb) const @@ -201,7 +231,22 @@ bool TestBuilding::Matches(FeatureType const & feature) const auto const & checker = ftypes::IsBuildingChecker::Instance(); if (!checker(feature)) return false; - return TestFeature::Matches(feature) && m_houseNumber == feature.GetHouseNumber(); + if (!TestFeature::Matches(feature)) + return false; + if (m_houseNumber != feature.GetHouseNumber()) + return false; + + // TODO(@y): consider to check m_boundary. + if (!m_hasCenter && !m_boundary.empty()) + { + m2::PointD center(0, 0); + for (auto const & p : m_boundary) + center += p; + center = center / m_boundary.size(); + if (!center.EqualDxDy(feature::GetCenter(feature), kTestPrecision)) + return false; + } + return true; } string TestBuilding::ToString() const diff --git a/search/search_tests_support/test_feature.hpp b/search/search_tests_support/test_feature.hpp index 9932d1d1b8..259e8e1760 100644 --- a/search/search_tests_support/test_feature.hpp +++ b/search/search_tests_support/test_feature.hpp @@ -33,16 +33,6 @@ protected: string const m_lang; }; -class TestPOI : public TestFeature -{ -public: - TestPOI(m2::PointD const & center, string const & name, string const & lang); - - // TestFeature overrides: - void Serialize(FeatureBuilder1 & fb) const override; - string ToString() const override; -}; - class TestCountry : public TestFeature { public: @@ -92,6 +82,24 @@ private: vector m_points; }; +class TestPOI : public TestFeature +{ +public: + TestPOI(m2::PointD const & center, string const & name, string const & lang); + + // TestFeature overrides: + void Serialize(FeatureBuilder1 & fb) const override; + bool Matches(FeatureType const & feature) const override; + string ToString() const override; + + inline void SetHouseNumber(string const & houseNumber) { m_houseNumber = houseNumber; } + inline void SetStreet(TestStreet const & street) { m_streetName = street.GetName(); } + +private: + string m_houseNumber; + string m_streetName; +}; + class TestBuilding : public TestFeature { public: @@ -107,7 +115,7 @@ public: bool Matches(FeatureType const & feature) const override; string ToString() const override; -protected: +private: vector const m_boundary; string const m_houseNumber; string const m_streetName; diff --git a/search/v2/features_layer_matcher.hpp b/search/v2/features_layer_matcher.hpp index 2b3ff2beb7..c1f2279a06 100644 --- a/search/v2/features_layer_matcher.hpp +++ b/search/v2/features_layer_matcher.hpp @@ -239,7 +239,6 @@ private: vector queryTokens; NormalizeHouseNumber(child.m_subQuery, queryTokens); - auto const & checker = ftypes::IsBuildingChecker::Instance(); uint32_t numFilterInvocations = 0; auto houseNumberFilter = [&](uint32_t id, FeatureType & feature, bool & loaded) -> bool { @@ -262,9 +261,6 @@ private: loaded = true; } - if (!checker(feature)) - return false; - if (!child.m_hasDelayedFeatures) return false; diff --git a/search/v2/search_model.cpp b/search/v2/search_model.cpp index 0715e23f18..3b4eb7ca09 100644 --- a/search/v2/search_model.cpp +++ b/search/v2/search_model.cpp @@ -1,6 +1,7 @@ #include "search/v2/search_model.hpp" #include "indexer/classificator.hpp" +#include "indexer/feature.hpp" #include "indexer/ftypes_matcher.hpp" #include "base/macros.hpp" @@ -21,7 +22,7 @@ public: { Classificator const & c = classif(); - auto paths = { "amenity", "historic", "office", "railway", "shop", "sport", "tourism", "craft" }; + auto paths = {"amenity", "historic", "office", "railway", "shop", "sport", "tourism", "craft"}; for (auto const & path : paths) m_types.push_back(c.GetTypeByPath({path})); } @@ -54,6 +55,21 @@ private: OneLevelPOIChecker const m_oneLevel; TwoLevelPOIChecker const m_twoLevel; }; + +class CustomIsBuildingChecker +{ +public: + static CustomIsBuildingChecker const & Instance() + { + static const CustomIsBuildingChecker inst; + return inst; + } + + bool operator()(FeatureType const & ft) const { return !ft.GetHouseNumber().empty(); } + +private: + CustomIsBuildingChecker() {} +}; } // namespace // static @@ -65,7 +81,7 @@ SearchModel const & SearchModel::Instance() SearchModel::SearchType SearchModel::GetSearchType(FeatureType const & feature) const { - static auto const & buildingChecker = IsBuildingChecker::Instance(); + static auto const & buildingChecker = CustomIsBuildingChecker::Instance(); static auto const & streetChecker = IsStreetChecker::Instance(); static auto const & localityChecker = IsLocalityChecker::Instance(); static auto const & poiChecker = IsPoiChecker::Instance(); diff --git a/search/v2/search_model.hpp b/search/v2/search_model.hpp index f2e2def6a4..a6a80efae0 100644 --- a/search/v2/search_model.hpp +++ b/search/v2/search_model.hpp @@ -24,11 +24,18 @@ class SearchModel public: enum SearchType { + // Low-level features such as amenities, offices, shops, buildings + // without house number, etc. SEARCH_TYPE_POI, + + // All features with set house number. SEARCH_TYPE_BUILDING, + SEARCH_TYPE_STREET, - SEARCH_TYPE_UNCLASSIFIED, // all low-level features except POI, - // BUILDING and STREET + + // All low-level features except POI, BUILDING and STREET. + SEARCH_TYPE_UNCLASSIFIED, + SEARCH_TYPE_VILLAGE, SEARCH_TYPE_CITY, SEARCH_TYPE_STATE, // US or Canadian states