[search] Search near my position for empty query.

This commit is contained in:
vng 2012-02-23 15:05:46 +03:00 committed by Alex Zolotarev
parent c48b6ccd11
commit b75ca70b25
6 changed files with 211 additions and 99 deletions

View file

@ -174,10 +174,10 @@ static void OnSearchResultCallback(search::Results const & res, int queryId)
else
[self disableRadarMode];
// Refresh search results with new mode, but
// do not search if text is not entered
// Refresh search results with new mode.
NSString * queryString = m_searchBar.text;
if (queryString.length)
// Search even with empty string.
//if (queryString.length)
{
search::SearchParams params;
[self fillSearchParams:params withText:queryString];
@ -332,19 +332,20 @@ static void OnSearchResultCallback(search::Results const & res, int queryId)
{
++g_queryId;
if (searchText.length)
// Search even with empty string.
//if (searchText.length)
{
search::SearchParams params;
[self fillSearchParams:params withText:searchText];
m_framework->Search(params);
}
else
{
[g_lastSearchResults release];
g_lastSearchResults = nil;
// Clean the table
[m_table reloadData];
}
//else
//{
// [g_lastSearchResults release];
// g_lastSearchResults = nil;
// // Clean the table
// [m_table reloadData];
//}
}
- (void)onCloseButton:(id)sender
@ -553,10 +554,10 @@ static void OnSearchResultCallback(search::Results const & res, int queryId)
- (void)onGpsUpdate:(location::GpsInfo const &)info
{
// Refresh search results with newer location, but
// do not search if text is not entered
// Refresh search results with newer location.
NSString * queryString = m_searchBar.text;
if (queryString.length)
// Search even with empty string.
//if (queryString.length)
{
search::SearchParams params;
[self fillSearchParams:params withText:queryString];

View file

@ -167,7 +167,9 @@ void SearchPanel::OnSearchTextChanged(QString const & str)
++m_queryId;
QString const normalized = str.normalized(QString::NormalizationForm_KC);
if (!normalized.isEmpty())
// search even with empty query
//if (!normalized.isEmpty())
{
m_params.m_query = normalized.toUtf8().constData();
m_params.m_callback = bind(&SearchPanel::SearchResultThreadFunc, this, _1, m_queryId);
@ -181,11 +183,11 @@ void SearchPanel::OnSearchTextChanged(QString const & str)
m_pClearButton->setFlat(true);
m_pClearButton->setVisible(true);
}
else
{
// hide X button
m_pClearButton->setVisible(false);
}
//else
//{
// // hide X button
// m_pClearButton->setVisible(false);
//}
}
void SearchPanel::OnSearchPanelItemClicked(int row, int)
@ -209,6 +211,7 @@ void SearchPanel::OnSearchPanelItemClicked(int row, int)
void SearchPanel::showEvent(QShowEvent *)
{
connect(m_pDrawWidget, SIGNAL(ViewportChanged()), this, SLOT(OnViewportChanged()));
OnSearchTextChanged(QString());
}
void SearchPanel::hideEvent(QHideEvent *)

View file

@ -15,9 +15,9 @@ public:
enum { MAX_SCORE = KeywordMatcher::MAX_SCORE
* (NUM_LANG_PRIORITY_TIERS + 1) * (MAX_LANGS_IN_TIER + 1) };
explicit LangKeywordsScorer(vector<vector<int8_t> > const & languagePriorities,
strings::UniString const * keywords, size_t keywordCount,
strings::UniString const * pPrefix);
LangKeywordsScorer(vector<vector<int8_t> > const & languagePriorities,
strings::UniString const * keywords, size_t keywordCount,
strings::UniString const * pPrefix);
uint32_t Score(int8_t lang, string const & name) const;
uint32_t Score(int8_t lang, strings::UniString const & name) const;

View file

@ -96,17 +96,19 @@ namespace
return MercatorBounds::MetresToXY(lon, lat, radius);
}
enum { VIEWPORT_RECT = 0, NEARME_RECT = 1 };
/// Check rects for optimal search (avoid duplicating).
void AnalizeRects(m2::RectD arrRects[2])
{
if (arrRects[1].IsRectInside(arrRects[0]))
arrRects[0].MakeEmpty();
if (arrRects[NEARME_RECT].IsRectInside(arrRects[VIEWPORT_RECT]))
arrRects[VIEWPORT_RECT].MakeEmpty();
else
{
if (arrRects[0].IsRectInside(arrRects[1]) &&
scales::GetScaleLevel(arrRects[0]) + Query::m_scaleDepthSearch >= scales::GetUpperScale())
if (arrRects[VIEWPORT_RECT].IsRectInside(arrRects[NEARME_RECT]) &&
(scales::GetScaleLevel(arrRects[VIEWPORT_RECT]) + Query::m_scaleDepthSearch >= scales::GetUpperScale()))
{
arrRects[1].MakeEmpty();
arrRects[NEARME_RECT].MakeEmpty();
}
}
}
@ -164,7 +166,7 @@ void Engine::SearchAsync()
{
threads::MutexGuard updateGuard(m_updateMutex);
params = m_params;
arrRects[0] = m_viewport;
arrRects[VIEWPORT_RECT] = m_viewport;
}
// Initialize query.
@ -173,16 +175,27 @@ void Engine::SearchAsync()
{
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())
if (!params.m_query.empty())
{
worldSearch = false;
arrRects[0].MakeEmpty();
arrRects[NEARME_RECT] = GetViewportRect(params.m_lat, params.m_lon);
// Do not search in viewport for "NearMe" mode.
if (params.IsNearMeMode())
{
worldSearch = false;
arrRects[VIEWPORT_RECT].MakeEmpty();
}
else
AnalizeRects(arrRects);
}
else
AnalizeRects(arrRects);
{
// For empty query search in small viewport near position.
arrRects[NEARME_RECT] = GetViewportRect(params.m_lat, params.m_lon, 2500);
worldSearch = false;
arrRects[VIEWPORT_RECT].MakeEmpty();
}
}
else
m_pQuery->NullPosition();
@ -196,7 +209,13 @@ void Engine::SearchAsync()
try
{
m_pQuery->Search(params.m_query, res);
if (params.m_query.empty())
{
if (params.m_validPos)
m_pQuery->SearchAllNearMe(res);
}
else
m_pQuery->Search(params.m_query, res);
}
catch (Query::CancelException const &)
{

View file

@ -181,45 +181,54 @@ namespace
};
}
void Query::InitSearch(string const & query)
{
m_cancel = false;
m_rawQuery = query;
m_uniQuery = NormalizeAndSimplifyString(m_rawQuery);
m_tokens.clear();
m_prefix.clear();
}
void Query::InitKeywordsScorer()
{
vector<vector<int8_t> > langPriorities(4);
langPriorities[0].push_back(m_currentLang);
langPriorities[1].push_back(m_inputLang);
langPriorities[2].push_back(StringUtf8Multilang::GetLangIndex("int_name"));
langPriorities[2].push_back(StringUtf8Multilang::GetLangIndex("en"));
langPriorities[3].push_back(StringUtf8Multilang::GetLangIndex("default"));
m_pKeywordsScorer.reset(new LangKeywordsScorer(langPriorities,
m_tokens.data(), m_tokens.size(), &m_prefix));
}
void Query::Search(string const & query, Results & res, unsigned int resultsNeeded)
{
// Initialize.
InitSearch(query);
search::Delimiters delims;
SplitUniString(m_uniQuery, MakeBackInsertFunctor(m_tokens), delims);
if (!m_tokens.empty() && !delims(strings::LastUniChar(m_rawQuery)))
{
m_cancel = false;
m_rawQuery = query;
m_uniQuery = NormalizeAndSimplifyString(m_rawQuery);
m_tokens.clear();
m_prefix.clear();
m_prefix.swap(m_tokens.back());
m_tokens.pop_back();
}
if (m_tokens.size() > 31)
m_tokens.resize(31);
search::Delimiters delims;
SplitUniString(m_uniQuery, MakeBackInsertFunctor(m_tokens), delims);
InitKeywordsScorer();
if (!m_tokens.empty() && !delims(strings::LastUniChar(m_rawQuery)))
{
m_prefix.swap(m_tokens.back());
m_tokens.pop_back();
}
if (m_tokens.size() > 31)
m_tokens.resize(31);
// Results queue's initialization.
STATIC_ASSERT ( m_qCount == ARRAY_SIZE(g_arrCompare1) );
STATIC_ASSERT ( m_qCount == ARRAY_SIZE(g_arrCompare2) );
vector<vector<int8_t> > langPriorities(4);
langPriorities[0].push_back(m_currentLang);
langPriorities[1].push_back(m_inputLang);
langPriorities[2].push_back(StringUtf8Multilang::GetLangIndex("int_name"));
langPriorities[2].push_back(StringUtf8Multilang::GetLangIndex("en"));
langPriorities[3].push_back(StringUtf8Multilang::GetLangIndex("default"));
m_pKeywordsScorer.reset(new LangKeywordsScorer(langPriorities,
m_tokens.data(), m_tokens.size(), &m_prefix));
// Results queue's initialization.
STATIC_ASSERT ( m_qCount == ARRAY_SIZE(g_arrCompare1) );
STATIC_ASSERT ( m_qCount == ARRAY_SIZE(g_arrCompare2) );
for (size_t i = 0; i < m_qCount; ++i)
{
m_results[i] = QueueT(2 * resultsNeeded, QueueCompareT(g_arrCompare1[i]));
m_results[i].reserve(2 * resultsNeeded);
}
for (size_t i = 0; i < m_qCount; ++i)
{
m_results[i] = QueueT(2 * resultsNeeded, QueueCompareT(g_arrCompare1[i]));
m_results[i].reserve(2 * resultsNeeded);
}
// Match (lat, lon).
@ -279,7 +288,7 @@ namespace
shared_ptr<value_type> m_val;
public:
explicit IndexedValue(value_type * v) : m_val(v)
IndexedValue(value_type * v) : m_val(v)
{
for (size_t i = 0; i < m_ind.size(); ++i)
m_ind[i] = numeric_limits<size_t>::max();
@ -328,6 +337,29 @@ namespace
return (r1.GetID() < r2.GetID());
}
};
template <class T>
void RemoveDuplicatingLinear(vector<T> & indV)
{
sort(indV.begin(), indV.end(), ProxyFunctor2<impl::PreResult2::LessLinearTypesF>());
indV.erase(unique(indV.begin(), indV.end(),
ProxyFunctor2<impl::PreResult2::EqualLinearTypesF>()),
indV.end());
}
template <class T>
void AddPreResult2(impl::PreResult2 * p, vector<T> & indV)
{
if (p)
{
// do not insert duplicating results
if (indV.end() == find_if(indV.begin(), indV.end(),
ProxyFunctor1<impl::PreResult2::StrictEqualF>(p)))
indV.push_back(p);
else
delete p;
}
}
}
namespace impl
@ -359,34 +391,56 @@ namespace impl
scoped_ptr<LockedFeaturesVector> m_pFV;
void LoadFeature(pair<size_t, uint32_t> const & id,
FeatureType & f, string & name, string & country)
{
if (m_pFV.get() == 0 || m_pFV->GetID() != id.first)
m_pFV.reset(new LockedFeaturesVector(*m_query.m_pIndex, id.first));
m_pFV->m_vector.Get(id.second, f);
uint32_t penalty;
m_query.GetBestMatchName(f, penalty, name);
country = m_pFV->GetCountry();
}
public:
PreResult2Maker(Query & q) : m_query(q)
{
}
// For the best performance, impl::PreResult1 should be sorted by impl::PreResult1::GetID().
impl::PreResult2 * operator() (impl::PreResult1 const & r)
impl::PreResult2 * operator() (impl::PreResult1 const & res)
{
pair<size_t, uint32_t> const id = r.GetID();
if (m_pFV.get() == 0 || m_pFV->GetID() != id.first)
m_pFV.reset(new LockedFeaturesVector(*m_query.m_pIndex, id.first));
FeatureType feature;
m_pFV->m_vector.Get(id.second, feature);
string name, country;
LoadFeature(res.GetID(), feature, name, country);
uint32_t penalty;
string name;
m_query.GetBestMatchName(feature, penalty, name);
return new impl::PreResult2(feature, res, name, country);
}
return new impl::PreResult2(feature, r, name, m_pFV->GetCountry());
impl::PreResult2 * operator() (pair<size_t, uint32_t> const & id)
{
FeatureType feature;
string name, country;
LoadFeature(id, feature, name, country);
if (!name.empty() && !country.empty())
{
// this results will be with equal rank
impl::PreResult1 res(0, 0, feature.GetLimitRect(FeatureType::WORST_GEOMETRY).Center(),
0, m_query.m_position, m_query.GetViewport());
return new impl::PreResult2(feature, res, name, country);
}
else
return 0;
}
};
}
void Query::FlushResults(Results & res)
{
typedef impl::PreResult2 ResultT;
vector<IndexedValue> indV;
{
@ -403,27 +457,14 @@ void Query::FlushResults(Results & res)
// make PreResult2 vector
impl::PreResult2Maker maker(*this);
for (PreResultSetT::const_iterator i = theSet.begin(); i != theSet.end(); ++i)
{
ResultT * res = maker(*i);
if (res == 0) continue;
// do not insert duplicating results
if (indV.end() == find_if(indV.begin(), indV.end(), ProxyFunctor1<ResultT::StrictEqualF>(res)))
indV.push_back(IndexedValue(res));
else
delete res;
}
AddPreResult2(maker(*i), indV);
}
// remove duplicating linear objects
sort(indV.begin(), indV.end(), ProxyFunctor2<ResultT::LessLinearTypesF>());
indV.erase(unique(indV.begin(), indV.end(),
ProxyFunctor2<ResultT::EqualLinearTypesF>()),
indV.end());
RemoveDuplicatingLinear(indV);
for (size_t i = 0; i < m_qCount; ++i)
{
CompareT<ResultT, RefSmartPtr> comp(g_arrCompare2[i]);
CompareT<impl::PreResult2, RefPointer> comp(g_arrCompare2[i]);
// sort by needed criteria
sort(indV.begin(), indV.end(), comp);
@ -750,4 +791,47 @@ m2::RectD const & Query::GetViewport() const
}
}
void Query::SearchAllNearMe(Results & res, unsigned int resultsNeeded)
{
InitSearch(string());
InitKeywordsScorer();
size_t const ind = 1;
ASSERT ( m_viewport[ind].IsValid(), () );
vector<impl::PreResult2*> indV;
impl::PreResult2Maker maker(*this);
// load results
for (size_t i = 0; i < m_offsetsInViewport[ind].size(); ++i)
{
if (m_cancel) break;
for (size_t j = 0; j < m_offsetsInViewport[ind][i].size(); ++j)
{
if (m_cancel) break;
AddPreResult2(maker(make_pair(i, m_offsetsInViewport[ind][i][j])), indV);
}
}
if (!m_cancel)
{
RemoveDuplicatingLinear(indV);
// sort by distance from m_position
sort(indV.begin(), indV.end(),
CompareT<impl::PreResult2, RefPointer>(&impl::PreResult2::LessDistance));
indV.resize(resultsNeeded);
// emit results
for (size_t i = 0; i < indV.size(); ++i)
res.AddResult(MakeResult(*(indV[i])));
}
for_each(indV.begin(), indV.end(), DeleteFunctor());
}
} // namespace search

View file

@ -61,6 +61,7 @@ public:
inline void SetInputLanguage(int8_t lang) { m_inputLang = lang; }
void Search(string const & query, Results & res, unsigned int resultsNeeded = 10);
void SearchAllNearMe(Results & res, unsigned int resultsNeeded = 30);
void ClearCache();
@ -73,6 +74,9 @@ private:
friend class impl::BestNameFinder;
friend class impl::PreResult2Maker;
void InitSearch(string const & query);
void InitKeywordsScorer();
void UpdateViewportOffsets(size_t ind);
void ClearCache(size_t ind);
@ -144,9 +148,10 @@ private:
{
template <class T> T const & operator() (T const & t) const { return t; }
};
struct RefSmartPtr
struct RefPointer
{
template <class T> typename T::value_type const & operator() (T const & t) const { return *t; }
template <class T> T const & operator() (T const * t) const { return *t; }
};
typedef CompareT<impl::PreResult1, NothingRef> QueueCompareT;