[search] Do search in viewport-rect and NearMe-rect in default mode. Don't search in World in "NearMe" mode.

This commit is contained in:
vng 2012-02-15 15:58:33 +03:00 committed by Alex Zolotarev
parent b701a1967c
commit 88f2db2e93
7 changed files with 162 additions and 105 deletions

View file

@ -120,19 +120,18 @@ static void OnSearchResultCallback(search::Results const & res, int queryId)
m_framework = framework;
m_locationManager = lm;
// get current location if needed
bool radarMode = false;
Settings::Get(RADAR_MODE_SETTINGS_KEY, radarMode);
// get current location
CLLocation * l = m_locationManager.lastLocation;
double lat, lon;
if (radarMode && [SearchVC isLocationValid:l])
bool const hasPt = [SearchVC isLocationValid:l];
if (hasPt)
{
lat = l.coordinate.latitude;
lon = l.coordinate.longitude;
}
m_framework->PrepareSearch(radarMode, lat, lon);
m_framework->PrepareSearch(hasPt, lat, lon);
}
return self;
}

View file

@ -682,9 +682,9 @@ search::Engine * Framework::GetSearchEngine()
return m_pSearchEngine.get();
}
void Framework::PrepareSearch(bool nearMe, double lat, double lon)
void Framework::PrepareSearch(bool hasPt, double lat, double lon)
{
GetSearchEngine()->PrepareSearch(GetCurrentViewport(), nearMe, lat, lon);
GetSearchEngine()->PrepareSearch(GetCurrentViewport(), hasPt, lat, lon);
}
void Framework::Search(search::SearchParams const & params)

View file

@ -142,7 +142,7 @@ private:
inline m2::RectD GetCurrentViewport() const { return m_navigator.Screen().ClipRect(); }
search::Engine * GetSearchEngine();
public:
void PrepareSearch(bool nearMe, double lat = 0.0, double lon = 0.0);
void PrepareSearch(bool hasPt, double lat = 0.0, double lon = 0.0);
void Search(search::SearchParams const & params);
bool GetCurrentPosition(double & lat, double & lon);

View file

@ -7,6 +7,7 @@
#include "../indexer/categories_holder.hpp"
#include "../indexer/search_string_utils.hpp"
#include "../indexer/mercator.hpp"
#include "../indexer/scales.hpp"
#include "../platform/platform.hpp"
@ -94,14 +95,30 @@ namespace
{
return MercatorBounds::MetresToXY(lon, lat, radius);
}
/// Check rects for optimal search (avoid duplicating).
void AnalizeRects(m2::RectD arrRects[2])
{
if (arrRects[1].IsRectInside(arrRects[0]))
arrRects[0].MakeEmpty();
else
{
if (arrRects[0].IsRectInside(arrRects[1]) &&
scales::GetScaleLevel(arrRects[0]) + Query::m_scaleDepthSearch >= scales::GetUpperScale())
{
arrRects[1].MakeEmpty();
}
}
}
}
void Engine::PrepareSearch(m2::RectD const & viewport, bool nearMe,
double lat, double lon)
void Engine::PrepareSearch(m2::RectD const & viewport,
bool hasPt, double lat, double lon)
{
// bind does copy of viewport
m2::RectD const r = (nearMe ? GetViewportRect(lat, lon) : viewport);
GetPlatform().RunAsync(bind(&Engine::SetViewportAsync, this, r));
m2::RectD const nearby = (hasPt ? GetViewportRect(lat, lon) : m2::RectD());
// bind does copy of all rects
GetPlatform().RunAsync(bind(&Engine::SetViewportAsync, this, viewport, nearby));
}
void Engine::Search(SearchParams const & params, m2::RectD const & viewport)
@ -118,7 +135,7 @@ void Engine::Search(SearchParams const & params, m2::RectD const & viewport)
p.RunAsync(bind(&Engine::SearchAsync, this));
}
void Engine::SetViewportAsync(m2::RectD const & viewport)
void Engine::SetViewportAsync(m2::RectD const & viewport, m2::RectD const & nearby)
{
// First of all - cancel previous query.
m_pQuery->DoCancel();
@ -126,7 +143,10 @@ void Engine::SetViewportAsync(m2::RectD const & viewport)
// Enter to run new search.
threads::MutexGuard searchGuard(m_searchMutex);
m_pQuery->SetViewport(viewport);
m2::RectD arrRects[] = { viewport, nearby };
AnalizeRects(arrRects);
m_pQuery->SetViewport(arrRects, ARRAY_SIZE(arrRects));
}
void Engine::SearchAsync()
@ -139,52 +159,47 @@ void Engine::SearchAsync()
// Get current search params.
SearchParams params;
m2::RectD viewport;
m2::RectD arrRects[2];
{
threads::MutexGuard updateGuard(m_updateMutex);
params = m_params;
viewport = m_viewport;
arrRects[0] = m_viewport;
}
// Initialize query.
bool const nearMe = params.IsNearMeMode();
if (nearMe)
m_pQuery->SetViewport(GetViewportRect(params.m_lat, params.m_lon));
else
m_pQuery->SetViewport(viewport);
bool worldSearch = true;
if (params.m_validPos)
{
m_pQuery->SetPosition(GetViewportXY(params.m_lat, params.m_lon));
arrRects[1] = GetViewportRect(params.m_lat, params.m_lon);
// Do not search in viewport for "NearMe" mode.
if (params.IsNearMeMode())
{
worldSearch = false;
arrRects[0].MakeEmpty();
}
else
AnalizeRects(arrRects);
}
else
m_pQuery->NullPosition();
unsigned int const resultsNeeded = 10;
m_pQuery->SetViewport(arrRects, 2);
m_pQuery->SetSearchInWorld(worldSearch);
Results res;
// Run first search with needed params.
try
{
m_pQuery->Search(params.m_query, res, resultsNeeded);
m_pQuery->Search(params.m_query, res);
}
catch (Query::CancelException const &)
{
}
// If not enough results, run second search with "Near Me" viewport.
if (!m_pQuery->IsCanceled() && !nearMe && params.m_validPos && (res.Count() < resultsNeeded))
{
m_pQuery->SetViewport(GetViewportRect(params.m_lat, params.m_lon));
try
{
m_pQuery->Search(params.m_query, res, resultsNeeded);
}
catch (Query::CancelException const &)
{
}
}
// Emit results in any way, even if search was canceled.
params.m_callback(res);
}

View file

@ -36,14 +36,14 @@ public:
string const & lang);
~Engine();
void PrepareSearch(m2::RectD const & viewport, bool nearMe,
double lat, double lon);
void PrepareSearch(m2::RectD const & viewport,
bool hasPt, double lat, double lon);
void Search(SearchParams const & params, m2::RectD const & viewport);
string GetCountryFile(m2::PointD const & pt) const;
private:
void SetViewportAsync(m2::RectD const & viewport);
void SetViewportAsync(m2::RectD const & viewport, m2::RectD const & nearby);
void SearchAsync();
threads::Mutex m_searchMutex, m_updateMutex;

View file

@ -35,10 +35,11 @@ Query::Query(Index const * pIndex,
m_pStringsToSuggest(pStringsToSuggest),
m_pInfoGetter(pInfoGetter),
m_currentLang(StringUtf8Multilang::GetLangIndex("en")),
m_viewport(m2::RectD::GetEmptyRect()), m_viewportExtended(m2::RectD::GetEmptyRect()),
m_position(empty_pos_value, empty_pos_value),
m_bOffsetsCacheIsValid(false)
m_position(empty_pos_value, empty_pos_value)
{
// m_viewport, m_viewportExtended are initialized as empty rects
ASSERT ( m_pIndex, () );
}
Query::~Query()
@ -47,9 +48,9 @@ Query::~Query()
namespace
{
inline bool IsEqual(m2::RectD const & r1, m2::RectD const & r2, double eps)
inline bool IsEqualMercator(m2::RectD const & r1, m2::RectD const & r2, double epsMeters)
{
eps = eps * MercatorBounds::degreeInMetres;
double const eps = epsMeters * MercatorBounds::degreeInMetres;
m2::RectD r = r1;
r.Inflate(eps, eps);
@ -63,17 +64,26 @@ namespace
}
}
void Query::SetViewport(m2::RectD const & viewport)
void Query::SetViewport(m2::RectD viewport[], size_t count)
{
// Check if viewports are equal.
// 10.0 - is 10 meters
if (!m_bOffsetsCacheIsValid || !IsEqual(m_viewport, viewport, 10.0))
{
m_viewport = viewport;
m_viewportExtended = m_viewport;
m_viewportExtended.Scale(3);
ASSERT_LESS_OR_EQUAL(count, m_rectsCount, ());
UpdateViewportOffsets();
for (size_t i = 0; i < count; ++i)
{
if (viewport[i].IsValid())
{
// Check if viewports are equal (10 meters).
if (!m_viewport[i].IsValid() || !IsEqualMercator(m_viewport[i], viewport[i], 10.0))
{
m_viewport[i] = viewport[i];
m_viewportExtended[i] = m_viewport[i];
m_viewportExtended[i].Scale(3);
UpdateViewportOffsets(i);
}
}
else
ClearCache(i);
}
}
@ -84,25 +94,32 @@ void Query::SetPreferredLanguage(string const & lang)
void Query::ClearCache()
{
m_offsetsInViewport.clear();
m_bOffsetsCacheIsValid = false;
for (size_t i = 0; i < m_rectsCount; ++i)
ClearCache(i);
}
void Query::UpdateViewportOffsets()
void Query::ClearCache(size_t ind)
{
m_offsetsInViewport.clear();
m_offsetsInViewport[ind].clear();
m_viewport[ind].MakeEmpty();
m_viewportExtended[ind].MakeEmpty();
}
void Query::UpdateViewportOffsets(size_t ind)
{
m_offsetsInViewport[ind].clear();
vector<MwmInfo> mwmInfo;
m_pIndex->GetMwmInfo(mwmInfo);
m_offsetsInViewport.resize(mwmInfo.size());
m_offsetsInViewport[ind].resize(mwmInfo.size());
int const viewScale = scales::GetScaleLevel(m_viewport);
covering::CoveringGetter cov(m_viewport, 0);
int const viewScale = scales::GetScaleLevel(m_viewport[ind]);
covering::CoveringGetter cov(m_viewport[ind], 0);
for (MwmSet::MwmId mwmId = 0; mwmId < mwmInfo.size(); ++mwmId)
{
// Search only mwms that intersect with viewport (world always does).
if (m_viewportExtended.IsIntersect(mwmInfo[mwmId].m_limitRect))
if (m_viewportExtended[ind].IsIntersect(mwmInfo[mwmId].m_limitRect))
{
Index::MwmLock mwmLock(*m_pIndex, mwmId);
if (MwmValue * pMwm = mwmLock.GetValue())
@ -111,7 +128,7 @@ void Query::UpdateViewportOffsets()
if (header.GetType() == feature::DataHeader::country)
{
pair<int, int> const scaleR = header.GetScaleRange();
int const scale = min(max(viewScale + 7, scaleR.first), scaleR.second);
int const scale = min(max(viewScale + m_scaleDepthSearch, scaleR.first), scaleR.second);
covering::IntervalsT const & interval = cov.Get(header.GetLastScale());
@ -120,23 +137,21 @@ void Query::UpdateViewportOffsets()
for (size_t i = 0; i < interval.size(); ++i)
{
index.ForEachInIntervalAndScale(MakeBackInsertFunctor(m_offsetsInViewport[mwmId]),
index.ForEachInIntervalAndScale(MakeBackInsertFunctor(m_offsetsInViewport[ind][mwmId]),
interval[i].first, interval[i].second,
scale);
}
sort(m_offsetsInViewport[mwmId].begin(), m_offsetsInViewport[mwmId].end());
sort(m_offsetsInViewport[ind][mwmId].begin(), m_offsetsInViewport[ind][mwmId].end());
}
}
}
}
m_bOffsetsCacheIsValid = true;
#ifdef DEBUG
size_t offsetsCached = 0;
for (MwmSet::MwmId mwmId = 0; mwmId < mwmInfo.size(); ++mwmId)
offsetsCached += m_offsetsInViewport[mwmId].size();
offsetsCached += m_offsetsInViewport[ind][mwmId].size();
LOG(LDEBUG, ("For search in viewport cached ",
"mwms:", mwmInfo.size(),
@ -210,7 +225,7 @@ void Query::Search(string const & query, Results & res, unsigned int resultsNeed
if (search::MatchLatLon(m_rawQuery, lat, lon, latPrec, lonPrec))
{
//double const precision = 5.0 * max(0.0001, min(latPrec, lonPrec)); // Min 55 meters
res.AddResult(impl::PreResult2(m_viewport, m_position, lat, lon).
res.AddResult(impl::PreResult2(GetViewport(), m_position, lat, lon).
GenerateFinalResult(m_pInfoGetter, m_pCategories, m_currentLang));
}
}
@ -387,21 +402,21 @@ void Query::FlushResults(Results & res)
{
typedef impl::PreResult2 ResultT;
/*
#ifdef DEBUG
{
impl::PreResult2Maker maker(*this);
LOG(LDEBUG, ("Dump features for rank:"));
for (QueueT::const_iterator i = m_results[0].begin(); i != m_results[0].end(); ++i)
{
ResultT * res = maker(*i);
LOG(LDEBUG, (*res));
delete res;
}
LOG(LDEBUG, ("------------------------"));
}
#endif
*/
/*
#ifdef DEBUG
{
impl::PreResult2Maker maker(*this);
LOG(LDEBUG, ("Dump features for rank:"));
for (QueueT::const_iterator i = m_results[0].begin(); i != m_results[0].end(); ++i)
{
ResultT * res = maker(*i);
LOG(LDEBUG, (*res));
delete res;
}
LOG(LDEBUG, ("------------------------"));
}
#endif
*/
vector<IndexedValue> indV;
@ -490,7 +505,7 @@ namespace
void Query::AddResultFromTrie(TrieValueT const & val, size_t mwmID)
{
impl::PreResult1 res(val.m_featureId, val.m_rank, val.m_pt, mwmID, m_position, m_viewport);
impl::PreResult1 res(val.m_featureId, val.m_rank, val.m_pt, mwmID, m_position, GetViewport());
for (size_t i = 0; i < m_qCount; ++i)
{
@ -584,9 +599,6 @@ public:
void Query::SearchFeatures()
{
if (!m_pIndex)
return;
vector<vector<strings::UniString> > tokens(m_tokens.size());
// Add normal tokens.
@ -609,7 +621,11 @@ void Query::SearchFeatures()
langs.insert(StringUtf8Multilang::GetLangIndex("en"));
langs.insert(StringUtf8Multilang::GetLangIndex("default"));
SearchFeatures(tokens, mwmInfo, langs, true);
for (size_t i = 0; i < m_rectsCount; ++i)
{
if (m_viewportExtended[i].IsValid())
SearchFeatures(tokens, mwmInfo, langs, i);
}
}
namespace
@ -639,13 +655,12 @@ namespace
void Query::SearchFeatures(vector<vector<strings::UniString> > const & tokens,
vector<MwmInfo> const & mwmInfo,
unordered_set<int8_t> const & langs,
bool onlyInViewport)
size_t ind)
{
for (MwmSet::MwmId mwmId = 0; mwmId < mwmInfo.size(); ++mwmId)
{
// Search only mwms that intersect with viewport (world always does).
if (!onlyInViewport ||
m_viewportExtended.IsIntersect(mwmInfo[mwmId].m_limitRect))
if (m_viewportExtended[ind].IsIntersect(mwmInfo[mwmId].m_limitRect))
{
Index::MwmLock mwmLock(*m_pIndex, mwmId);
if (MwmValue * pMwm = mwmLock.GetValue())
@ -653,8 +668,12 @@ void Query::SearchFeatures(vector<vector<strings::UniString> > const & tokens,
if (pMwm->m_cont.IsReaderExist(SEARCH_INDEX_FILE_TAG))
{
feature::DataHeader const & header = pMwm->GetHeader();
serial::CodingParams cp(GetCPForTrie(header.GetDefCodingParams()));
bool const isWorld = (header.GetType() == feature::DataHeader::world);
if (isWorld && !m_worldSearch)
continue;
serial::CodingParams cp(GetCPForTrie(header.GetDefCodingParams()));
scoped_ptr<TrieIterator> pTrieRoot(::trie::reader::ReadTrie(
pMwm->m_cont.GetReader(SEARCH_INDEX_FILE_TAG),
trie::ValueReader(cp),
@ -679,8 +698,6 @@ void Query::SearchFeatures(vector<vector<strings::UniString> > const & tokens,
}
ASSERT_NOT_EQUAL(pCategoriesRoot, 0, ());
bool const isWorld = (header.GetType() == feature::DataHeader::world);
impl::FeatureLoader emitter(*this, mwmId);
// Iterate through first language edges.
@ -694,7 +711,8 @@ void Query::SearchFeatures(vector<vector<strings::UniString> > const & tokens,
MatchFeaturesInTrie(tokens, m_prefix,
TrieRootPrefix(*pLangRoot, edge),
TrieRootPrefix(*pCategoriesRoot, categoriesEdge),
FeaturesFilter(m_offsetsInViewport[mwmId], isWorld, m_cancel), emitter);
FeaturesFilter(m_offsetsInViewport[ind][mwmId], isWorld, m_cancel),
emitter);
LOG(LDEBUG, ("Lang:",
StringUtf8Multilang::GetLangByCode(static_cast<int8_t>(edge[0])),
@ -746,4 +764,15 @@ void Query::MatchForSuggestions(strings::UniString const & token, Results & res)
}
}
m2::RectD const & Query::GetViewport() const
{
if (m_viewport[0].IsValid())
return m_viewport[0];
else
{
ASSERT ( m_viewport[1].IsValid(), () );
return m_viewport[1];
}
}
} // namespace search

View file

@ -38,6 +38,8 @@ namespace impl
class Query
{
public:
static int const m_scaleDepthSearch = 7;
// Vector of pairs (string_to_suggest, min_prefix_length_to_suggest).
typedef vector<pair<strings::UniString, uint8_t> > StringsToSuggestVectorT;
@ -47,12 +49,14 @@ public:
storage::CountryInfoGetter const * pInfoGetter);
~Query();
void SetViewport(m2::RectD const & viewport);
void SetViewport(m2::RectD viewport[], size_t count);
static const int empty_pos_value = -1000;
inline void SetPosition(m2::PointD const & pos) { m_position = pos; }
inline void NullPosition() { m_position = m2::PointD(empty_pos_value, empty_pos_value); }
inline void SetSearchInWorld(bool b) { m_worldSearch = b; }
void SetPreferredLanguage(string const & lang);
void Search(string const & query, Results & res, unsigned int resultsNeeded = 10);
@ -68,7 +72,8 @@ private:
friend class impl::BestNameFinder;
friend class impl::PreResult2Maker;
void UpdateViewportOffsets();
void UpdateViewportOffsets(size_t ind);
void ClearCache(size_t ind);
typedef trie::ValueReader::ValueType TrieValueT;
void AddResultFromTrie(TrieValueT const & val, size_t mwmID);
@ -79,7 +84,7 @@ private:
void SearchFeatures(vector<vector<strings::UniString> > const & tokens,
vector<MwmInfo> const & mwmInfo,
unordered_set<int8_t> const & langs,
bool onlyInViewport);
size_t ind);
void SuggestStrings(Results & res);
void MatchForSuggestions(strings::UniString const & token, Results & res);
@ -99,13 +104,22 @@ private:
buffer_vector<strings::UniString, 32> m_tokens;
strings::UniString m_prefix;
m2::RectD m_viewport, m_viewportExtended;
/// @todo OMG, this static integral constant does't link ???
//static size_t const m_rectsCount = 2;
enum { m_rectsCount = 2 };
m2::RectD m_viewport[m_rectsCount];
m2::RectD m_viewportExtended[m_rectsCount];
bool m_worldSearch;
/// @return Rect for viewport-distance calculation.
m2::RectD const & GetViewport() const;
m2::PointD m_position;
scoped_ptr<LangKeywordsScorer> m_pKeywordsScorer;
bool m_bOffsetsCacheIsValid;
vector<vector<uint32_t> > m_offsetsInViewport;
vector<vector<uint32_t> > m_offsetsInViewport[m_rectsCount];
template <class ParamT, class RefT> class CompareT
{