diff --git a/search/intermediate_result.cpp b/search/intermediate_result.cpp index 55412da569..fd9412a650 100644 --- a/search/intermediate_result.cpp +++ b/search/intermediate_result.cpp @@ -57,8 +57,6 @@ void ProcessMetadata(FeatureType const & ft, Result::Metadata & meta) namespace impl { -PreResult1::PreResult1(): PreResult1(0 /* priority */) {} - PreResult1::PreResult1(double priority) : m_priority(priority) {} PreResult1::PreResult1(FeatureID const & fID, double priority, int8_t viewportID, diff --git a/search/intermediate_result.hpp b/search/intermediate_result.hpp index b2dd6f11fd..1cd58fee76 100644 --- a/search/intermediate_result.hpp +++ b/search/intermediate_result.hpp @@ -33,8 +33,6 @@ class PreResult1 v2::PreRankingInfo m_info; public: - PreResult1(); - explicit PreResult1(double priority); PreResult1(FeatureID const & fID, double priority, int8_t viewportID, diff --git a/search/search_integration_tests/search_query_v2_test.cpp b/search/search_integration_tests/search_query_v2_test.cpp index d18d2a51a7..0b35f25dca 100644 --- a/search/search_integration_tests/search_query_v2_test.cpp +++ b/search/search_integration_tests/search_query_v2_test.cpp @@ -9,10 +9,13 @@ #include "geometry/point2d.hpp" #include "geometry/rect2d.hpp" +#include "base/math.hpp" + #include "std/shared_ptr.hpp" #include "std/vector.hpp" using namespace search::tests_support; +using namespace search::v2; using TRules = vector>; @@ -264,5 +267,56 @@ UNIT_CLASS_TEST(SearchQueryV2Test, DisableSuggests) TEST(MatchResults(m_engine, rules, request.Results()), ()); } } + +UNIT_CLASS_TEST(SearchQueryV2Test, TestRankingInfo) +{ + string const countryName = "Wonderland"; + + TestCity sanFrancisco(m2::PointD(1, 1), "San Francisco", "en", 100 /* rank */); + + // Golden Gate Bridge-bridge is located in this test on the Golden + // Gate Bridge-street. Therefore, there are several valid parses of + // the query "Golden Gate Bridge", and search engine must return + // both features (street and bridge) as they were matched by full + // name. + TestStreet goldenGateStreet( + vector{m2::PointD(-0.5, -0.5), m2::PointD(0, 0), m2::PointD(0.5, 0.5)}, + "Golden Gate Bridge", "en"); + TestPOI goldenGateBridge(m2::PointD(0, 0), "Golden Gate Bridge", "en"); + + auto worldId = BuildMwm("testWorld", feature::DataHeader::world, [&](TestMwmBuilder & builder) + { + builder.Add(sanFrancisco); + }); + auto wonderlandId = BuildMwm(countryName, feature::DataHeader::country, [&](TestMwmBuilder & builder) + { + builder.Add(goldenGateStreet); + builder.Add(goldenGateBridge); + }); + RegisterCountry("Wonderland", m2::RectD(m2::PointD(-2, -2), m2::PointD(2, 2))); + + SetViewport(m2::RectD(m2::PointD(-0.5, -0.5), m2::PointD(0.5, 0.5))); + { + SearchParams params; + params.m_query = "golden gate bridge "; + params.m_inputLocale = "en"; + params.SetMode(Mode::Everywhere); + params.SetSuggestsEnabled(false); + + TestSearchRequest request(m_engine, params, m_viewport); + request.Wait(); + + TRules rules = {ExactMatch(wonderlandId, goldenGateBridge), + ExactMatch(wonderlandId, goldenGateStreet)}; + + TEST(MatchResults(m_engine, rules, request.Results()), ()); + for (auto const & result : request.Results()) + { + auto const & info = result.GetRankingInfo(); + TEST_EQUAL(NAME_SCORE_FULL_MATCH, info.m_nameScore, ()); + TEST(my::AlmostEqualAbs(1.0, info.m_nameCoverage, 1e-6), (info.m_nameCoverage)); + } + } +} } // namespace } // namespace search diff --git a/search/search_query.cpp b/search/search_query.cpp index 0b20cccb4f..08b55f88b5 100644 --- a/search/search_query.cpp +++ b/search/search_query.cpp @@ -551,46 +551,47 @@ namespace { struct LessFeatureID { - using ValueT = impl::PreResult1; - bool operator()(ValueT const & r1, ValueT const & r2) const { return (r1.GetID() < r2.GetID()); } + using TValue = impl::PreResult1; + + inline bool operator()(TValue const & lhs, TValue const & rhs) const + { + return lhs.GetID() < rhs.GetID(); + } }; -class EqualFeatureID +struct EqualFeatureID { - using ValueT = impl::PreResult1; - ValueT const & m_val; + using TValue = impl::PreResult1; -public: - explicit EqualFeatureID(ValueT const & v) : m_val(v) {} - bool operator()(ValueT const & r) const { return (m_val.GetID() == r.GetID()); } + inline bool operator()(TValue const & lhs, TValue const & rhs) const + { + return lhs.GetID() == rhs.GetID(); + } +}; + +// Orders PreResult1 by following criterion: +// 1. Feature Id (increasing), if same... +// 2. Number of matched tokens from the query (decreasing), if same... +// 3. Index of the first matched token from the query (increasing). +struct ComparePreResult1 +{ + bool operator()(impl::PreResult1 const & lhs, impl::PreResult1 const & rhs) const + { + if (lhs.GetID() != rhs.GetID()) + return lhs.GetID() < rhs.GetID(); + + auto const & linfo = lhs.GetInfo(); + auto const & rinfo = rhs.GetInfo(); + if (linfo.GetNumTokens() != rinfo.GetNumTokens()) + return linfo.GetNumTokens() > rinfo.GetNumTokens(); + return linfo.m_startToken < rinfo.m_startToken; + } }; void RemoveDuplicatingPreResults1(vector & results) { - sort(results.begin(), results.end(), LessFeatureID()); - size_t i = 0; - size_t k = 0; - while (i != results.size()) - { - size_t j = i; - size_t b = i; - while (j != results.size() && results[j].GetID() == results[i].GetID()) - { - auto const & curr = results[j].GetInfo(); - auto const & best = results[b].GetInfo(); - if (curr.GetNumTokens() > best.GetNumTokens() || - (curr.GetNumTokens() == best.GetNumTokens() && curr.m_startToken < best.m_startToken)) - { - b = j; - } - ++j; - } - - swap(results[k], results[b]); - ++k; - i = j; - } - results.resize(k); + sort(results.begin(), results.end(), ComparePreResult1()); + results.erase(unique(results.begin(), results.end(), EqualFeatureID()), results.end()); } bool IsResultExists(impl::PreResult2 const & p, vector const & indV) diff --git a/search/search_tests_support/test_feature.cpp b/search/search_tests_support/test_feature.cpp index 61acd9dd82..ffba68bcf0 100644 --- a/search/search_tests_support/test_feature.cpp +++ b/search/search_tests_support/test_feature.cpp @@ -131,6 +131,7 @@ TestStreet::TestStreet(vector const & points, string const & name, s void TestStreet::Serialize(FeatureBuilder1 & fb) const { + fb.SetTestId(m_id); CHECK(fb.AddName(m_lang, m_name), ("Can't set feature name:", m_name, "(", m_lang, ")")); if (m_lang != "default") CHECK(fb.AddName("default", m_name), ("Can't set feature name:", m_name, "( default )"));