Merge pull request #4359 from ygorshenin/fix-search-in-viewport

[search] Fixed search in viewport filtering.
This commit is contained in:
mpimenov 2016-09-26 13:17:12 +03:00 committed by GitHub
commit 6b8cce5213
17 changed files with 158 additions and 114 deletions

View file

@ -117,7 +117,7 @@ char const kAllow3dKey[] = "Allow3d";
char const kAllow3dBuildingsKey[] = "Buildings3d";
char const kAllowAutoZoom[] = "AutoZoom";
double const kDistEqualQuery = 100.0;
double const kDistEqualQueryMeters = 100.0;
// Must correspond SearchMarkType.
vector<string> kSearchMarks =
@ -1100,10 +1100,10 @@ bool Framework::SearchEverywhere(search::EverywhereSearchParams const & params)
{
search::SearchParams p;
p.m_query = params.m_query;
p.SetInputLocale(params.m_inputLocale);
p.SetForceSearch(true);
p.SetMode(search::Mode::Everywhere);
p.SetSuggestsEnabled(true);
p.m_inputLocale = params.m_inputLocale;
p.m_mode = search::Mode::Everywhere;
p.m_forceSearch = true;
p.m_suggestsEnabled = true;
p.m_onResults = [params](search::Results const & results) {
if (params.m_onResults)
GetPlatform().RunOnGuiThread([params, results]() { params.m_onResults(results); });
@ -1117,10 +1117,10 @@ bool Framework::SearchInViewport(search::ViewportSearchParams const & params)
{
search::SearchParams p;
p.m_query = params.m_query;
p.SetInputLocale(params.m_inputLocale);
p.SetForceSearch(false);
p.SetMode(search::Mode::Viewport);
p.SetSuggestsEnabled(false);
p.m_inputLocale = params.m_inputLocale;
p.m_mode = search::Mode::Viewport;
p.m_forceSearch = false;
p.m_suggestsEnabled = false;
p.m_onStarted = [params]() {
if (params.m_onStarted)
@ -1143,9 +1143,9 @@ bool Framework::SearchInDownloader(DownloaderSearchParams const & params)
search::SearchParams p;
p.m_query = params.m_query;
p.m_inputLocale = params.m_inputLocale;
p.SetMode(search::Mode::Downloader);
p.SetSuggestsEnabled(false);
p.SetForceSearch(true);
p.m_mode = search::Mode::Downloader;
p.m_forceSearch = true;
p.m_suggestsEnabled = false;
p.m_onResults = search::DownloaderSearchCallback(
static_cast<search::DownloaderSearchCallback::Delegate &>(*this), m_model.GetIndex(),
GetCountryInfoGetter(), GetStorage(), params);
@ -1262,7 +1262,7 @@ string Framework::GetCountryName(m2::PointD const & pt) const
bool Framework::Search(search::SearchParams const & params)
{
auto const mode = params.GetMode();
auto const mode = params.m_mode;
auto & intent = m_searchIntents[static_cast<size_t>(mode)];
#ifdef FIXED_LOCATION
@ -1318,18 +1318,26 @@ bool Framework::QueryMayBeSkipped(SearchIntent const & intent, search::SearchPar
auto const & lastParams = intent.m_params;
auto const & lastViewport = intent.m_viewport;
if (params.IsForceSearch())
if (params.m_forceSearch)
return false;
if (!lastParams.IsEqualCommon(params))
return false;
if (!lastViewport.IsValid() || !search::IsEqualMercator(lastViewport, viewport, kDistEqualQuery))
return false;
if (!lastParams.IsSearchAroundPosition() ||
ms::DistanceOnEarth(lastParams.m_lat, lastParams.m_lon, params.m_lat, params.m_lon) <=
kDistEqualQuery)
if (!lastViewport.IsValid() ||
!search::IsEqualMercator(lastViewport, viewport, kDistEqualQueryMeters))
{
return false;
}
if (lastParams.IsValidPosition() && params.IsValidPosition() &&
ms::DistanceOnEarth(lastParams.GetPositionLatLon(), params.GetPositionLatLon()) >
kDistEqualQueryMeters)
{
return false;
}
if (lastParams.IsValidPosition() != params.IsValidPosition())
return false;
return true;
}

View file

@ -227,7 +227,7 @@ void Engine::PostMessage(TArgs &&... args)
void Engine::DoSearch(SearchParams const & params, m2::RectD const & viewport,
shared_ptr<ProcessorHandle> handle, Processor & processor)
{
bool const viewportSearch = params.GetMode() == Mode::Viewport;
bool const viewportSearch = params.m_mode == Mode::Viewport;
processor.Reset();
processor.Init(viewportSearch);

View file

@ -22,10 +22,7 @@
namespace search
{
/// All constants in meters.
double const DIST_EQUAL_RESULTS = 100.0;
double const DIST_SAME_STREET = 5000.0;
double const kDistSameStreetMeters = 5000.0;
char const * const kEmptyRatingSymbol = "-";
char const * const kPricingSymbol = "$";
@ -241,12 +238,17 @@ Result PreResult2::GenerateFinalResult(storage::CountryInfoGetter const & infoGe
}
}
bool PreResult2::StrictEqualF::operator() (PreResult2 const & r) const
PreResult2::StrictEqualF::StrictEqualF(PreResult2 const & r, double const epsMeters)
: m_r(r), m_epsMeters(epsMeters)
{
}
bool PreResult2::StrictEqualF::operator()(PreResult2 const & r) const
{
if (m_r.m_resultType == r.m_resultType && m_r.m_resultType == RESULT_FEATURE)
{
if (m_r.IsEqualCommon(r))
return (PointDistance(m_r.GetCenter(), r.GetCenter()) < DIST_EQUAL_RESULTS);
return PointDistance(m_r.GetCenter(), r.GetCenter()) < m_epsMeters;
}
return false;
@ -266,29 +268,25 @@ bool PreResult2::LessLinearTypesF::operator() (PreResult2 const & r1, PreResult2
return (t1 < t2);
// Should stay the best feature, after unique, so add this criteria:
return (r1.m_distance < r2.m_distance);
return r1.m_distance < r2.m_distance;
}
bool PreResult2::EqualLinearTypesF::operator() (PreResult2 const & r1, PreResult2 const & r2) const
{
// Note! Do compare for distance when filtering linear objects.
// Otherwise we will skip the results for different parts of the map.
return (r1.m_geomType == feature::GEOM_LINE &&
r1.IsEqualCommon(r2) &&
PointDistance(r1.GetCenter(), r2.GetCenter()) < DIST_SAME_STREET);
return r1.m_geomType == feature::GEOM_LINE && r1.IsEqualCommon(r2) &&
PointDistance(r1.GetCenter(), r2.GetCenter()) < kDistSameStreetMeters;
}
bool PreResult2::IsEqualCommon(PreResult2 const & r) const
{
return (m_geomType == r.m_geomType &&
GetBestType() == r.GetBestType() &&
m_str == r.m_str);
return m_geomType == r.m_geomType && GetBestType() == r.GetBestType() && m_str == r.m_str;
}
bool PreResult2::IsStreet() const
{
return (m_geomType == feature::GEOM_LINE &&
ftypes::IsStreetChecker::Instance()(m_types));
return m_geomType == feature::GEOM_LINE && ftypes::IsStreetChecker::Instance()(m_types);
}
string PreResult2::DebugPrint() const

View file

@ -84,10 +84,14 @@ public:
/// Filter equal features for different mwm's.
class StrictEqualF
{
PreResult2 const & m_r;
public:
StrictEqualF(PreResult2 const & r) : m_r(r) {}
bool operator() (PreResult2 const & r) const;
StrictEqualF(PreResult2 const & r, double const epsMeters);
bool operator()(PreResult2 const & r) const;
private:
PreResult2 const & m_r;
double const m_epsMeters;
};
/// To filter equal linear objects.

View file

@ -209,10 +209,7 @@ void PreRanker::Filter(bool viewportSearch)
filtered.insert(m_results.begin(), m_results.begin() + n);
}
m_results.reserve(filtered.size());
m_results.clear();
copy(filtered.begin(), filtered.end(), back_inserter(m_results));
m_results.assign(filtered.begin(), filtered.end());
}
void PreRanker::UpdateResults(bool lastUpdate)

View file

@ -27,6 +27,9 @@ public:
struct Params
{
m2::RectD m_viewport;
// A minimum distance between search results in meters, needed for
// filtering of viewport search results.
double m_minDistanceOnMapBetweenResults = 0.0;
// This is different from geocoder's pivot because pivot is

View file

@ -110,8 +110,9 @@ void SendStatistics(SearchParams const & params, m2::RectD const & viewport, Res
string posX, posY;
if (params.IsValidPosition())
{
posX = strings::to_string(MercatorBounds::LonToX(params.m_lon));
posY = strings::to_string(MercatorBounds::LatToY(params.m_lat));
auto const position = params.GetPositionMercator();
posX = strings::to_string(position.x);
posY = strings::to_string(position.y);
}
alohalytics::TStringMap const stats = {
@ -380,7 +381,7 @@ void Processor::Search(SearchParams const & params, m2::RectD const & viewport)
bool rankPivotIsSet = false;
if (!viewportSearch && params.IsValidPosition())
{
m2::PointD const pos = MercatorBounds::FromLatLon(params.m_lat, params.m_lon);
m2::PointD const pos = params.GetPositionMercator();
if (m2::Inflate(viewport, viewport.SizeX() / 4.0, viewport.SizeY() / 4.0).IsPointInside(pos))
{
SetRankPivot(pos);
@ -391,14 +392,14 @@ void Processor::Search(SearchParams const & params, m2::RectD const & viewport)
SetRankPivot(viewport.Center());
if (params.IsValidPosition())
SetPosition(MercatorBounds::FromLatLon(params.m_lat, params.m_lon));
SetPosition(params.GetPositionMercator());
else
SetPosition(viewport.Center());
SetMinDistanceOnMapBetweenResults(params.m_minDistanceOnMapBetweenResults);
SetMode(params.GetMode());
SetSuggestsEnabled(params.GetSuggestsEnabled());
SetMode(params.m_mode);
SetSuggestsEnabled(params.m_suggestsEnabled);
SetInputLocale(params.m_inputLocale);
ASSERT(!params.m_query.empty(), ());
@ -699,10 +700,12 @@ void Processor::InitRanker(Geocoder::Params const & geocoderParams)
if (viewportSearch)
{
params.m_viewport = GetViewport();
params.m_minDistanceOnMapBetweenResults = m_minDistanceOnMapBetweenResults;
params.m_limit = kPreResultsCount;
}
else
{
params.m_minDistanceOnMapBetweenResults = 100.0;
params.m_limit = kResultsCount;
}
params.m_position = GetPosition();

View file

@ -301,7 +301,8 @@ void Ranker::Init(Params const & params, Geocoder::Params const & geocoderParams
bool Ranker::IsResultExists(PreResult2 const & p, vector<IndexedValue> const & values)
{
PreResult2::StrictEqualF equalCmp(p);
PreResult2::StrictEqualF equalCmp(p, m_params.m_minDistanceOnMapBetweenResults);
// Do not insert duplicating results.
return values.end() != find_if(values.begin(), values.end(), [&equalCmp](IndexedValue const & iv)
{
@ -509,8 +510,8 @@ void Ranker::UpdateResults(bool lastUpdate)
// Emit feature results.
size_t count = m_emitter.GetResults().GetCount();
size_t i;
for (i = 0; i < m_tentativeResults.size(); ++i)
size_t i = 0;
for (; i < m_tentativeResults.size(); ++i)
{
if (!lastUpdate && i >= kBatchSize && !m_params.m_viewportSearch)
break;

View file

@ -60,6 +60,10 @@ public:
m2::PointD m_accuratePivotCenter = m2::PointD(0, 0);
// A minimum distance between search results in meters, needed for
// filtering of indentical search results.
double m_minDistanceOnMapBetweenResults = 0.0;
TLocales m_categoryLocales;
size_t m_limit = 0;

View file

@ -193,9 +193,9 @@ struct SearchEngineProxy
search::SearchParams sp;
sp.m_query = params.m_query;
sp.m_inputLocale = params.m_locale;
sp.SetMode(search::Mode::Everywhere);
sp.m_mode = search::Mode::Everywhere;
sp.SetPosition(params.m_latLon.m_lat, params.m_latLon.m_lon);
sp.SetSuggestsEnabled(false);
sp.m_suggestsEnabled = false;
auto const & bottomLeft = params.m_viewport.m_min;
auto const & topRight = params.m_viewport.m_max;

View file

@ -129,9 +129,9 @@ private:
search::SearchParams p;
p.m_query = query;
p.m_inputLocale = "en";
p.SetMode(search::Mode::Downloader);
p.SetSuggestsEnabled(false);
p.SetForceSearch(true);
p.m_mode = search::Mode::Downloader;
p.m_forceSearch = true;
p.m_suggestsEnabled = false;
return p;
}

View file

@ -120,5 +120,53 @@ UNIT_CLASS_TEST(InteractiveSearchTest, Smoke)
TEST(MatchResults(m_engine, rules, request.Results()), ());
}
}
UNIT_CLASS_TEST(InteractiveSearchTest, NearbyFeaturesInViewport)
{
double const kEps = 1e-5;
TestCafe cafe1(m2::PointD(0.0, 0.0));
TestCafe cafe2(m2::PointD(0.0, kEps));
TestCafe cafe3(m2::PointD(kEps, kEps));
TestCafe cafe4(m2::PointD(kEps, 0.0));
auto const id = BuildCountry("Wonderland", [&](TestMwmBuilder & builder) {
builder.Add(cafe1);
builder.Add(cafe2);
builder.Add(cafe3);
builder.Add(cafe4);
});
SearchParams params;
params.m_query = "cafe";
params.m_mode = Mode::Viewport;
params.m_inputLocale = "en";
params.m_minDistanceOnMapBetweenResults = 0.5;
params.m_forceSearch = true;
params.m_suggestsEnabled = false;
m2::RectD const viewport(m2::PointD(-0.5, -0.5), m2::PointD(0.5, 0.5));
{
TestSearchRequest request(m_engine, params, viewport);
request.Run();
TEST(MatchResults(m_engine, TRules{ExactMatch(id, cafe1), ExactMatch(id, cafe2),
ExactMatch(id, cafe3), ExactMatch(id, cafe4)},
request.Results()),
());
}
params.m_minDistanceOnMapBetweenResults = 1.0;
{
TestSearchRequest request(m_engine, params, viewport);
request.Run();
auto const & results = request.Results();
TEST(MatchResults(m_engine, TRules{ExactMatch(id, cafe1), ExactMatch(id, cafe3)}, results) ||
MatchResults(m_engine, TRules{ExactMatch(id, cafe2), ExactMatch(id, cafe4)}, results), ());
}
}
} // namespace
} // namespace search

View file

@ -36,8 +36,8 @@ public:
SearchParams params;
params.m_query = query;
params.m_inputLocale = "en";
params.SetMode(Mode::Everywhere);
params.SetSuggestsEnabled(false);
params.m_mode = Mode::Everywhere;
params.m_suggestsEnabled = false;
auto request = make_unique<TestSearchRequest>(m_engine, params, m_viewport);
request->Run();
@ -290,8 +290,8 @@ UNIT_CLASS_TEST(ProcessorTest, DisableSuggests)
SearchParams params;
params.m_query = "londo";
params.m_inputLocale = "en";
params.SetMode(Mode::Downloader);
params.SetSuggestsEnabled(false);
params.m_mode = Mode::Downloader;
params.m_suggestsEnabled = false;
TestSearchRequest request(m_engine, params, m_viewport);
request.Run();

View file

@ -4,20 +4,10 @@
#include "coding/multilang_utf8_string.hpp"
#include "base/assert.hpp"
namespace search
{
SearchParams::SearchParams()
: m_lat(0.0)
, m_lon(0.0)
, m_minDistanceOnMapBetweenResults(0.0)
, m_searchRadiusM(-1.0)
, m_mode(Mode::Everywhere)
, m_forceSearch(false)
, m_validPos(false)
, m_suggestsEnabled(true)
{
}
void SearchParams::SetPosition(double lat, double lon)
{
m_lat = lat;
@ -25,21 +15,22 @@ void SearchParams::SetPosition(double lat, double lon)
m_validPos = true;
}
bool SearchParams::GetSearchRect(m2::RectD & rect) const
m2::PointD SearchParams::GetPositionMercator() const
{
if (IsSearchAroundPosition())
{
rect = MercatorBounds::MetresToXY(m_lon, m_lat, m_searchRadiusM);
return true;
}
return false;
ASSERT(IsValidPosition(), ());
return MercatorBounds::FromLatLon(m_lat, m_lon);
}
ms::LatLon SearchParams::GetPositionLatLon() const
{
ASSERT(IsValidPosition(), ());
return ms::LatLon(m_lat, m_lon);
}
bool SearchParams::IsEqualCommon(SearchParams const & rhs) const
{
return (m_query == rhs.m_query && m_inputLocale == rhs.m_inputLocale &&
m_validPos == rhs.m_validPos && m_mode == rhs.m_mode &&
m_searchRadiusM == rhs.m_searchRadiusM);
return m_query == rhs.m_query && m_inputLocale == rhs.m_inputLocale &&
m_validPos == rhs.m_validPos && m_mode == rhs.m_mode;
}
string DebugPrint(SearchParams const & params)

View file

@ -2,6 +2,7 @@
#include "search/mode.hpp"
#include "geometry/latlon.hpp"
#include "geometry/point2d.hpp"
#include "geometry/rect2d.hpp"
@ -18,48 +19,34 @@ public:
using TOnStarted = function<void()>;
using TOnResults = function<void(Results const &)>;
SearchParams();
/// @name Force run search without comparing with previous search params.
//@{
void SetForceSearch(bool b) { m_forceSearch = b; }
bool IsForceSearch() const { return m_forceSearch; }
//@}
inline void SetMode(Mode mode) { m_mode = mode; }
inline Mode GetMode() const { return m_mode; }
void SetPosition(double lat, double lon);
m2::PointD GetPositionMercator() const;
ms::LatLon GetPositionLatLon() const;
inline bool IsValidPosition() const { return m_validPos; }
inline bool IsSearchAroundPosition() const { return (m_searchRadiusM > 0 && IsValidPosition()); }
inline void SetSearchRadiusMeters(double radiusM) { m_searchRadiusM = radiusM; }
bool GetSearchRect(m2::RectD & rect) const;
/// @param[in] locale can be "fr", "en-US", "ru_RU" etc.
inline void SetInputLocale(string const & locale) { m_inputLocale = locale; }
inline void SetSuggestsEnabled(bool enabled) { m_suggestsEnabled = enabled; }
inline bool GetSuggestsEnabled() const { return m_suggestsEnabled; }
bool IsEqualCommon(SearchParams const & rhs) const;
inline void Clear() { m_query.clear(); }
TOnStarted m_onStarted;
TOnResults m_onResults;
string m_query;
string m_inputLocale;
double m_lat, m_lon;
// A minimum distance between search results in mercator, needed for
// A minimum distance between search results in meters, needed for
// pre-ranking of viewport search results.
double m_minDistanceOnMapBetweenResults;
double m_minDistanceOnMapBetweenResults = 0.0;
Mode m_mode = Mode::Everywhere;
bool m_forceSearch = false;
bool m_suggestsEnabled = true;
friend string DebugPrint(SearchParams const & params);
private:
double m_searchRadiusM;
Mode m_mode;
bool m_forceSearch;
bool m_validPos;
bool m_suggestsEnabled;
double m_lat = 0.0;
double m_lon = 0.0;
bool m_validPos = false;
};
} // namespace search

View file

@ -250,9 +250,9 @@ int main(int argc, char * argv[])
search::SearchParams params;
params.m_query = strings::ToUtf8(sample.m_query);
params.m_inputLocale = sample.m_locale;
params.SetMode(Mode::Everywhere);
params.m_mode = Mode::Everywhere;
params.SetPosition(latLon.lat, latLon.lon);
params.SetSuggestsEnabled(false);
params.m_suggestsEnabled = false;
TestSearchRequest request(engine, params, sample.m_viewport);
request.Run();

View file

@ -17,7 +17,7 @@ TestSearchRequest::TestSearchRequest(TestSearchEngine & engine, string const & q
{
m_params.m_query = query;
m_params.m_inputLocale = locale;
m_params.SetMode(mode);
m_params.m_mode = mode;
SetUpCallbacks();
}
@ -36,7 +36,7 @@ TestSearchRequest::TestSearchRequest(TestSearchEngine & engine, string const & q
{
m_params.m_query = query;
m_params.m_inputLocale = locale;
m_params.SetMode(mode);
m_params.m_mode = mode;
m_params.m_onStarted = move(onStarted);
m_params.m_onResults = move(onResults);
}