From f52220ab61ec668a906e5f9869f82afb8e01f569 Mon Sep 17 00:00:00 2001 From: Viktor Govako Date: Wed, 26 Jul 2023 17:27:35 -0300 Subject: [PATCH] [search] Fixed "relaxed" street matching. Signed-off-by: Viktor Govako --- search/geocoder.cpp | 8 ++-- .../processor_test.cpp | 38 +++++++++++++++++++ search/streets_matcher.cpp | 6 ++- search/streets_matcher.hpp | 16 +++++++- 4 files changed, 63 insertions(+), 5 deletions(-) diff --git a/search/geocoder.cpp b/search/geocoder.cpp index be3f17b5ac..b8f49b4f7e 100644 --- a/search/geocoder.cpp +++ b/search/geocoder.cpp @@ -1220,10 +1220,12 @@ void Geocoder::ProcessStreets(BaseContext & ctx, CentersFilter const & centers, vector predictions; StreetsMatcher::Go(ctx, streets, *m_filter, m_params, predictions); - // Iterating from best to worst predictions here. Make "Relaxed" results for the best prediction only - // to avoid dummy streets results, matched by very _common_ tokens. + // Iterating from best to worst predictions here. Make "Relaxed" results for the best probability. for (size_t i = 0; i < predictions.size(); ++i) - CreateStreetsLayerAndMatchLowerLayers(ctx, predictions[i], centers, i == 0 /* makeRelaxed */); + { + CreateStreetsLayerAndMatchLowerLayers(ctx, predictions[i], centers, + predictions[0].SameForRelaxedMatch(predictions[i]) /* makeRelaxed */); + } } void Geocoder::GreedilyMatchStreetsWithSuburbs(BaseContext & ctx, CentersFilter const & centers) diff --git a/search/search_integration_tests/processor_test.cpp b/search/search_integration_tests/processor_test.cpp index 885622a04b..d443b6389f 100644 --- a/search/search_integration_tests/processor_test.cpp +++ b/search/search_integration_tests/processor_test.cpp @@ -3417,4 +3417,42 @@ UNIT_CLASS_TEST(ProcessorTest, StreetCategories) } } +// https://github.com/organicmaps/organicmaps/issues/4421 +UNIT_CLASS_TEST(ProcessorTest, BarcelonaStreet) +{ + TestStreet street({{-1, -1}, {1, 1}}, "Carrer de la Concòrdia", "default"); + street.SetType({"highway", "residential"}); + TestStreet highway({{-0.9, -0.9}, {0.9, -0.9}}, "C-59 Carretera de Mollet", "default"); + highway.SetType({"highway", "trunk"}); + highway.SetRoadNumber("C-59"); + + auto wonderlandId = BuildCountry("Wonderland", [&](TestMwmBuilder & builder) + { + builder.Add(street); + builder.Add(highway); + }); + + SetViewport(m2::RectD(-0.5, -0.5, 0.5, 0.5)); + + { + Rules const rules = { + ExactMatch(wonderlandId, street), + // 1 token match is discarded for _relaxed_ + //ExactMatch(wonderlandId, highway), + }; + TEST(OrderedResultsMatch(MakeRequest("carrer de concordia 59", "en")->Results(), rules), ()); + // Add some misspellings. + TEST(OrderedResultsMatch(MakeRequest("carrer concoria 59", "en")->Results(), rules), ()); + TEST(OrderedResultsMatch(MakeRequest("carer la concoria 59", "en")->Results(), rules), ()); + } + + { + Rules const rules = { + ExactMatch(wonderlandId, street), + ExactMatch(wonderlandId, highway), + }; + TEST(OrderedResultsMatch(MakeRequest("concordia 59", "en")->Results(), rules), ()); + } +} + } // namespace processor_test diff --git a/search/streets_matcher.cpp b/search/streets_matcher.cpp index 1a38c9cf52..1857e8b322 100644 --- a/search/streets_matcher.cpp +++ b/search/streets_matcher.cpp @@ -178,7 +178,11 @@ void StreetsMatcher::Go(BaseContext const & ctx, CBV const & candidates, // // That's why we need all predictions here. - sort(predictions.rbegin(), predictions.rend(), base::LessBy(&Prediction::m_prob)); + sort(predictions.begin(), predictions.end(), [](Prediction const & l, Prediction const & r) + { + return l.IsBetter(r); + }); + while (predictions.size() > kMaxNumOfImprobablePredictions && predictions.back().m_prob < kTailProbability) { diff --git a/search/streets_matcher.hpp b/search/streets_matcher.hpp index 86983edfa3..e1c768bbfa 100644 --- a/search/streets_matcher.hpp +++ b/search/streets_matcher.hpp @@ -18,7 +18,21 @@ class StreetsMatcher public: struct Prediction { - inline size_t GetNumTokens() const { return m_tokenRange.Size(); } + size_t GetNumTokens() const { return m_tokenRange.Size(); } + + /// @todo Check m_withMisprints ? + /// @{ + bool SameForRelaxedMatch(Prediction const & rhs) const + { + return m_prob == rhs.m_prob && GetNumTokens() == rhs.GetNumTokens(); + } + bool IsBetter(Prediction const & rhs) const + { + if (m_prob == rhs.m_prob) + return GetNumTokens() > rhs.GetNumTokens(); + return m_prob > rhs.m_prob; + } + /// @} CBV m_features; TokenRange m_tokenRange;