From ec814e1437d28a7ebb49b79b05bb85d0724ac6aa Mon Sep 17 00:00:00 2001 From: tatiana-yan Date: Mon, 29 Jul 2019 16:27:06 +0300 Subject: [PATCH] [search] Support cities postcodes from World.mwm. --- search/geocoder.cpp | 44 ++++++++++++++----- search/geocoder.hpp | 17 +++++-- .../processor_test.cpp | 39 ++++++++++++++-- 3 files changed, 82 insertions(+), 18 deletions(-) diff --git a/search/geocoder.cpp b/search/geocoder.cpp index f3fdb7eb89..9083e20c1c 100644 --- a/search/geocoder.cpp +++ b/search/geocoder.cpp @@ -1010,8 +1010,19 @@ void Geocoder::WithPostcodes(BaseContext & ctx, Fn && fn) ScopedMarkTokens mark(ctx.m_tokens, BaseContext::TOKEN_TYPE_POSTCODE, tokenRange); m_postcodes.Clear(); + + vector> infos; + m_dataSource.GetMwmsInfo(infos); + MwmSet::MwmHandle handle = indexer::FindWorld(m_dataSource, infos); + if (handle.IsAlive()) + { + auto worldContext = make_unique(move(handle)); + m_postcodes.m_worldFeatures = + RetrievePostcodeFeatures(*worldContext, TokenSlice(m_params, tokenRange)); + } + m_postcodes.m_tokenRange = tokenRange; - m_postcodes.m_features = move(postcodes); + m_postcodes.m_countryFeatures = move(postcodes); fn(); } @@ -1074,16 +1085,16 @@ void Geocoder::MatchPOIsAndBuildings(BaseContext & ctx, size_t curToken) { // All tokens were consumed, find paths through layers, emit // features. - if (m_postcodes.m_features.IsEmpty()) + if (m_postcodes.IsEmpty()) return FindPaths(ctx); // When there are no layers but user entered a postcode, we have // to emit all features matching to the postcode. if (layers.size() == 0) { - CBV filtered = m_postcodes.m_features; - if (m_filter->NeedToFilter(m_postcodes.m_features)) - filtered = m_filter->Filter(m_postcodes.m_features); + CBV filtered = m_postcodes.m_countryFeatures; + if (m_filter->NeedToFilter(m_postcodes.m_countryFeatures)) + filtered = m_filter->Filter(m_postcodes.m_countryFeatures); filtered.ForEach([&](uint64_t bit) { auto const featureId = base::asserted_cast(bit); Model::Type type; @@ -1125,7 +1136,7 @@ void Geocoder::MatchPOIsAndBuildings(BaseContext & ctx, size_t curToken) InitLayer(Model::TYPE_BUILDING, m_postcodes.m_tokenRange, layer); vector features; - m_postcodes.m_features.ForEach([&features](uint64_t bit) { + m_postcodes.m_countryFeatures.ForEach([&features](uint64_t bit) { features.push_back(base::asserted_cast(bit)); }); layer.m_sortedFeatures = &features; @@ -1153,7 +1164,7 @@ void Geocoder::MatchPOIsAndBuildings(BaseContext & ctx, size_t curToken) // TYPE_STREET features were filtered in GreedilyMatchStreets(). if (type < kNumClusters) { - if (m_postcodes.m_features.IsEmpty() || m_postcodes.Has(featureId)) + if (m_postcodes.IsEmpty() || m_postcodes.Has(featureId)) clusters[type].push_back(featureId); } }; @@ -1307,10 +1318,23 @@ void Geocoder::FindPaths(BaseContext & ctx) auto const & innermostLayer = *sortedLayers.front(); - if (m_postcodes.m_features.IsEmpty() || (ctx.m_city && m_postcodes.Has(ctx.m_city->m_featureId))) - m_matcher->SetPostcodes(nullptr); + auto needPostcodes = [&]() { + if (m_postcodes.IsEmpty()) + return false; + + if (ctx.m_city) + { + auto const isWorld = ctx.m_city->m_countryId.GetInfo()->GetType() == MwmInfo::WORLD; + if (m_postcodes.Has(ctx.m_city->m_featureId, isWorld)) + return false; + } + return true; + }; + + if (needPostcodes()) + m_matcher->SetPostcodes(&m_postcodes.m_countryFeatures); else - m_matcher->SetPostcodes(&m_postcodes.m_features); + m_matcher->SetPostcodes(nullptr); auto isExactMatch = [](BaseContext const & context, IntersectionResult const & result) { bool regionsChecked = false; diff --git a/search/geocoder.hpp b/search/geocoder.hpp index e776e39342..5bfaf6237d 100644 --- a/search/geocoder.hpp +++ b/search/geocoder.hpp @@ -137,13 +137,22 @@ private: void Clear() { m_tokenRange.Clear(); - m_features.Reset(); + m_countryFeatures.Reset(); + m_worldFeatures.Reset(); } - bool Has(uint32_t id) const { return m_features.HasBit(id); } + bool Has(uint32_t id, bool searchWorld = false) const + { + if (searchWorld) + return m_worldFeatures.HasBit(id); + return m_countryFeatures.HasBit(id); + } + + bool IsEmpty() const { return m_countryFeatures.IsEmpty() && m_worldFeatures.IsEmpty(); } TokenRange m_tokenRange; - CBV m_features; + CBV m_countryFeatures; + CBV m_worldFeatures; }; // Sets search query params for categorial search. @@ -290,7 +299,7 @@ private: PivotRectsCache m_pivotRectsCache; LocalityRectsCache m_localityRectsCache; - // Postcodes features in the mwm that is currently being processed. + // Postcodes features in the mwm that is currently being processed and World.mwm. Postcodes m_postcodes; // This filter is used to throw away excess features. diff --git a/search/search_integration_tests/processor_test.cpp b/search/search_integration_tests/processor_test.cpp index 59efda2c0f..1e2107f42a 100644 --- a/search/search_integration_tests/processor_test.cpp +++ b/search/search_integration_tests/processor_test.cpp @@ -2208,7 +2208,7 @@ UNIT_CLASS_TEST(ProcessorTest, SynonymMisprintsTest) } } -UNIT_CLASS_TEST(ProcessorTest, CityPostcodes) +UNIT_CLASS_TEST(ProcessorTest, VillagePostcodes) { string const countryName = "France"; @@ -2230,12 +2230,12 @@ UNIT_CLASS_TEST(ProcessorTest, CityPostcodes) SetViewport(m2::RectD(-1, -1, 1, 1)); { Rules rules{ExactMatch(countryId, building4), ExactMatch(countryId, street)}; - // Test that we not require the building to have a postcode if the city has. + // Test that we do not require the building to have a postcode if the village has. TEST(ResultsMatch("Rue des Serpents 4 Marckolsheim 67390 ", rules), ()); } { Rules rules{ExactMatch(countryId, street), ExactMatch(countryId, marckolsheim)}; - // Test that we do not require the street to have a postcode if the city has. + // Test that we do not require the street to have a postcode if the village has. TEST(ResultsMatch("Rue des Serpents Marckolsheim 67390 ", rules), ()); } { @@ -2266,7 +2266,7 @@ UNIT_CLASS_TEST(ProcessorTest, StreetPostcodes) SetViewport(m2::RectD(-1, -1, 1, 1)); { Rules rules{ExactMatch(countryId, building4), ExactMatch(countryId, street)}; - // Test that we not require the building to have a postcode if the street has. + // Test that we do not require the building to have a postcode if the street has. TEST(ResultsMatch("Rue des Serpents 4 67390 ", "ru", rules), ()); } { @@ -2275,5 +2275,36 @@ UNIT_CLASS_TEST(ProcessorTest, StreetPostcodes) TEST(ResultsMatch("67390", rules), ()); } } + +UNIT_CLASS_TEST(ProcessorTest, CityPostcodes) +{ + string const countryName = "Russia"; + + TestCity moscow(m2::PointD(0, 0), "Moscow", "en", 100 /* rank */); + moscow.SetPostcode("123456"); + + TestStreet street( + vector{m2::PointD(-0.5, 0.0), m2::PointD(0, 0), m2::PointD(0.5, 0.0)}, + "Tverskaya", "en"); + + TestBuilding building(m2::PointD(0.0, 0.00001), "", "4", street.GetName("en"), "en"); + + auto const worldId = BuildWorld([&](TestMwmBuilder & builder) { + builder.Add(moscow); + }); + + auto countryId = BuildCountry(countryName, [&](TestMwmBuilder & builder) { + builder.Add(moscow); + builder.Add(street); + builder.Add(building); + }); + + SetViewport(m2::RectD(-1, -1, 1, 1)); + { + Rules rules{ExactMatch(countryId, building), ExactMatch(countryId, street)}; + // Test that we do not require the building to have a postcode if the city has. + TEST(ResultsMatch("Tverskaya 4 Moscow 123456 ", rules), ()); + } +} } // namespace } // namespace search