[search] Implement additional search around locality (like address).

This commit is contained in:
vng 2012-08-16 18:08:24 +03:00 committed by Alex Zolotarev
parent 383cd6fbcb
commit 73b11cd8d5
6 changed files with 506 additions and 96 deletions

View file

@ -290,14 +290,16 @@ void FeatureType::GetPreferredDrawableNames(string & defaultName, string & intNa
}
}
uint32_t FeatureType::GetPopulation() const
uint8_t FeatureType::GetRank() const
{
ParseCommon();
return m_Params.rank;
}
if (m_Params.rank == 0)
return 1;
return static_cast<uint32_t>(pow(1.1, m_Params.rank));
uint32_t FeatureType::GetPopulation() const
{
uint8_t const r = GetRank();
return (r == 0 ? 1 : static_cast<uint32_t>(pow(1.1, r)));
}
double FeatureType::GetPopulationDrawRank() const

View file

@ -60,6 +60,8 @@ public:
return (Header() & feature::HEADER_HAS_NAME) != 0;
}
// Array with 64 strings ??? Use ForEachName instead!
/*
class GetNamesFn
{
public:
@ -75,6 +77,7 @@ public:
return true;
}
};
*/
template <class T>
inline bool ForEachNameRef(T & functor) const
@ -222,8 +225,13 @@ public:
void GetPrefferedNames(string & defaultName, string & intName) const;
/// Additional - take into account house number for defaultName
void GetPreferredDrawableNames(string & defaultName, string & intName) const;
inline bool GetName(int8_t lang, string & name) const
{
return m_Params.name.GetString(lang, name);
}
//@}
uint8_t GetRank() const;
uint32_t GetPopulation() const;
double GetPopulationDrawRank() const;

View file

@ -236,31 +236,66 @@ struct TrieRootPrefix
}
};
template <class ToDo, class FilterT>
void MatchFeaturesInTrie(vector<vector<strings::UniString> > const & tokens,
vector<strings::UniString> const & prefixTokens,
TrieRootPrefix const & trieRoot,
TrieRootPrefix const & catRoot,
FilterT const & filter,
ToDo & toDo)
/// Return features set for each token.
template <class HolderT>
void GetFeaturesInTrie(vector<vector<strings::UniString> > const & tokens,
vector<strings::UniString> const & prefixTokens,
TrieRootPrefix const & trieRoot,
HolderT & holder)
{
//LOG(LDEBUG, ("Tokens: ", tokens));
//LOG(LDEBUG, ("Prefix: ", prefixTokens));
impl::OffsetIntersecter<FilterT> intersecter(filter);
// Match tokens.
for (size_t i = 0; i < tokens.size(); ++i)
size_t const count = tokens.size();
holder.Resize(count + 1);
for (size_t i = 0; i < count; ++i)
{
holder.StartNew(i);
for (size_t j = 0; j < tokens[i].size(); ++j)
{
ASSERT ( !tokens[i][j].empty(), () );
impl::FullMatchInTrie(trieRoot.m_root, trieRoot.m_prefix, trieRoot.m_prefixSize,
tokens[i][j], holder);
}
}
// Match prefix.
holder.StartNew(count);
for (size_t i = 0; i < prefixTokens.size(); ++i)
{
ASSERT ( !prefixTokens[i].empty(), () );
impl::FullMatchInTrie(trieRoot.m_root, trieRoot.m_prefix, trieRoot.m_prefixSize,
prefixTokens[i], holder);
}
}
/// Do set intersection of features for each token.
template <class ToDo, class FilterT, class HolderT>
void MatchFeaturesInTrie(vector<vector<strings::UniString> > const & tokens,
vector<strings::UniString> const & prefixTokens,
TrieRootPrefix const & trieRoot,
FilterT const & filter,
HolderT const & addHolder,
ToDo & toDo)
{
impl::OffsetIntersecter<FilterT> intersecter(filter);
// Match tokens.
size_t const count = tokens.size();
for (size_t i = 0; i < count; ++i)
{
for (size_t j = 0; j < tokens[i].size(); ++j)
{
ASSERT ( !tokens[i][j].empty(), () );
// match in trie
impl::FullMatchInTrie(trieRoot.m_root, trieRoot.m_prefix, trieRoot.m_prefixSize,
tokens[i][j], intersecter);
impl::FullMatchInTrie(catRoot.m_root, catRoot.m_prefix, catRoot.m_prefixSize,
tokens[i][j], intersecter);
// get additional features for token
addHolder.GetValues(i, intersecter);
}
intersecter.NextStep();
@ -272,11 +307,12 @@ void MatchFeaturesInTrie(vector<vector<strings::UniString> > const & tokens,
{
ASSERT ( !prefixTokens[i].empty(), () );
// match in trie
impl::PrefixMatchInTrie(trieRoot.m_root, trieRoot.m_prefix, trieRoot.m_prefixSize,
prefixTokens[i], intersecter);
impl::FullMatchInTrie(catRoot.m_root, catRoot.m_prefix, catRoot.m_prefixSize,
prefixTokens[i], intersecter);
// get additional features for token
addHolder.GetValues(count, intersecter);
}
if (prefixCount > 0)

View file

@ -123,7 +123,7 @@ namespace
else
{
if (arrRects[VIEWPORT_RECT].IsRectInside(arrRects[NEARME_RECT]) &&
(scales::GetScaleLevel(arrRects[VIEWPORT_RECT]) + Query::m_scaleDepthSearch >= scales::GetUpperScale()))
(scales::GetScaleLevel(arrRects[VIEWPORT_RECT]) + Query::SCALE_SEARCH_DEPTH >= scales::GetUpperScale()))
{
arrRects[NEARME_RECT].MakeEmpty();
}

View file

@ -13,6 +13,7 @@
#include "../indexer/search_delimiters.hpp"
#include "../indexer/search_string_utils.hpp"
#include "../indexer/categories_holder.hpp"
#include "../indexer/classificator.hpp"
#include "../coding/multilang_utf8_string.hpp"
#include "../coding/reader_wrapper.hpp"
@ -102,19 +103,24 @@ void Query::SetViewport(m2::RectD viewport[], size_t count)
m_pIndex->GetMwmInfo(mwmInfo);
for (size_t i = 0; i < count; ++i)
SetViewportByIndex(mwmInfo, viewport[i], i);
}
void Query::SetViewportByIndex(MWMVectorT const & mwmInfo, m2::RectD const & viewport, size_t idx)
{
ASSERT_LESS_OR_EQUAL(idx, static_cast<size_t>(RECTSCOUNT), ());
if (viewport.IsValid())
{
if (viewport[i].IsValid())
// Check if viewports are equal (10 meters).
if (!m_viewport[idx].IsValid() || !IsEqualMercator(m_viewport[idx], viewport, 10.0))
{
// 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];
UpdateViewportOffsets(mwmInfo, viewport[i], m_offsetsInViewport[i]);
}
m_viewport[idx] = viewport;
UpdateViewportOffsets(mwmInfo, viewport, m_offsetsInViewport[idx]);
}
else
ClearCache(i);
}
else
ClearCache(idx);
}
void Query::SetPreferredLanguage(string const & lang)
@ -159,7 +165,7 @@ void Query::UpdateViewportOffsets(MWMVectorT const & mwmInfo, m2::RectD const &
if (header.GetType() == feature::DataHeader::country)
{
pair<int, int> const scaleR = header.GetScaleRange();
int const scale = min(max(viewScale + m_scaleDepthSearch, scaleR.first), scaleR.second);
int const scale = min(max(viewScale + SCALE_SEARCH_DEPTH, scaleR.first), scaleR.second);
covering::IntervalsT const & interval = cov.Get(header.GetLastScale());
@ -222,8 +228,7 @@ void Query::Search(string const & query, Results & res)
InitSearch(query);
search::Delimiters delims;
SplitUniString(NormalizeAndSimplifyString(query),
MakeBackInsertFunctor(m_tokens), delims);
SplitUniString(NormalizeAndSimplifyString(query), MakeBackInsertFunctor(m_tokens), delims);
if (!m_tokens.empty() && !delims(strings::LastUniChar(query)))
{
@ -250,6 +255,9 @@ void Query::Search(string const & query, Results & res)
if (m_cancel) return;
SuggestStrings(res);
if (m_cancel) return;
SearchAddress();
if (m_cancel) return;
SearchFeatures();
@ -533,9 +541,10 @@ namespace
};
}
void Query::AddResultFromTrie(TrieValueT const & val, size_t mwmID)
void Query::AddResultFromTrie(TrieValueT const & val, size_t mwmID, int viewportID)
{
impl::PreResult1 res(val.m_featureId, val.m_rank, val.m_pt, mwmID, m_position, GetViewport());
impl::PreResult1 res(val.m_featureId, val.m_rank, val.m_pt, mwmID,
GetPosition(viewportID), GetViewport(viewportID));
for (size_t i = 0; i < m_qCount; ++i)
{
@ -552,9 +561,9 @@ class BestNameFinder
{
uint32_t & m_penalty;
string & m_name;
LangKeywordsScorer & m_keywordsScorer;
LangKeywordsScorer const & m_keywordsScorer;
public:
BestNameFinder(uint32_t & penalty, string & name, LangKeywordsScorer & keywordsScorer)
BestNameFinder(uint32_t & penalty, string & name, LangKeywordsScorer const & keywordsScorer)
: m_penalty(penalty), m_name(name), m_keywordsScorer(keywordsScorer)
{
m_penalty = uint32_t(-1);
@ -574,10 +583,11 @@ public:
} // namespace search::impl
void Query::GetBestMatchName(FeatureType const & f, uint32_t & penalty, string & name)
void Query::GetBestMatchName(FeatureType const & f, uint32_t & penalty, string & name) const
{
impl::BestNameFinder bestNameFinder(penalty, name, *m_pKeywordsScorer);
(void)f.ForEachNameRef(bestNameFinder);
/*
if (!f.ForEachNameRef(bestNameFinder))
{
@ -594,19 +604,19 @@ namespace impl
class FeatureLoader
{
Query & m_query;
size_t m_mwmID;
size_t m_count;
size_t m_mwmID, m_count;
int m_viewportID;
public:
FeatureLoader(Query & query, size_t mwmID)
: m_query(query), m_mwmID(mwmID), m_count(0)
FeatureLoader(Query & query, size_t mwmID, int viewportID)
: m_query(query), m_mwmID(mwmID), m_count(0), m_viewportID(viewportID)
{
}
void operator() (Query::TrieValueT const & value)
{
++m_count;
m_query.AddResultFromTrie(value, m_mwmID);
m_query.AddResultFromTrie(value, m_mwmID, m_viewportID);
}
size_t GetCount() const { return m_count; }
@ -634,7 +644,7 @@ public:
} // namespace search::impl
Query::Params::Params(Query & q)
Query::Params::Params(Query const & q, bool isLocalities/* = false*/)
{
if (!q.m_prefix.empty())
m_prefixTokens.push_back(q.m_prefix);
@ -646,8 +656,8 @@ Query::Params::Params(Query & q)
for (size_t i = 0; i < tokensCount; ++i)
m_tokens[i].push_back(q.m_tokens[i]);
// Add names of categories.
if (q.m_pCategories)
// Add names of categories (and synonims).
if (q.m_pCategories && !isLocalities)
{
for (size_t i = 0; i < tokensCount; ++i)
q.m_pCategories->ForEachTypeByName(q.m_tokens[i], DoInsertTypeNames(m_tokens[i]));
@ -656,6 +666,44 @@ Query::Params::Params(Query & q)
q.m_pCategories->ForEachTypeByName(q.m_prefix, DoInsertTypeNames(m_prefixTokens));
}
FillLanguages(q);
}
void Query::Params::EraseTokens(vector<size_t> const & eraseInds)
{
// fill temporary vector
vector<TokensVectorT> newTokens;
size_t skipI = 0;
size_t const count = m_tokens.size();
size_t const eraseCount = eraseInds.size();
for (size_t i = 0; i < count; ++i)
{
if (skipI < eraseCount && eraseInds[skipI] == i)
{
++skipI;
}
else
{
newTokens.push_back(TokensVectorT());
newTokens.back().swap(m_tokens[i]);
}
}
// assign to m_tokens
newTokens.swap(m_tokens);
if (skipI < eraseCount)
{
// it means that we need to skip prefix tokens
ASSERT_EQUAL ( skipI+1, eraseCount, (eraseInds) );
ASSERT_EQUAL ( eraseInds[skipI], count, (eraseInds) );
m_prefixTokens.clear();
}
}
void Query::Params::FillLanguages(Query const & q)
{
m_langs.insert(q.m_currentLang);
m_langs.insert(q.m_inputLang);
m_langs.insert(StringUtf8Multilang::GetLangIndex("int_name"));
@ -663,13 +711,255 @@ Query::Params::Params(Query & q)
m_langs.insert(StringUtf8Multilang::GetLangIndex("default"));
}
namespace impl
{
struct Locality
{
string m_name, m_enName; ///< native name and english name of locality
Query::TrieValueT m_value;
uint32_t m_type; ///< feature type
vector<size_t> m_matchedTokens; ///< indexes of matched tokens for locality
Locality() : m_type(0) {}
Locality(Query::TrieValueT const & val, uint32_t type) : m_value(val), m_type(type) {}
bool operator<(Locality const & rhs) const
{
if (m_matchedTokens.size() != rhs.m_matchedTokens.size())
return (m_matchedTokens.size() < rhs.m_matchedTokens.size());
return (m_value.m_rank < rhs.m_value.m_rank);
/// @todo Add sorting by type: 'city' is better than 'town' etc ...
}
private:
class DoCount
{
size_t & m_count;
public:
DoCount(size_t & count) : m_count(count) { m_count = 0; }
template <class T> void operator() (T const &) { ++m_count; }
};
public:
bool IsFullNameMatched() const
{
size_t count;
SplitUniString(NormalizeAndSimplifyString(m_name), DoCount(count), search::Delimiters());
return (count <= m_matchedTokens.size());
}
};
}
void Query::SearchAddress()
{
// Find World.mwm and do special search there.
MWMVectorT mwmInfo;
m_pIndex->GetMwmInfo(mwmInfo);
for (MwmSet::MwmId mwmId = 0; mwmId < mwmInfo.size(); ++mwmId)
{
Index::MwmLock mwmLock(*m_pIndex, mwmId);
MwmValue * pMwm = mwmLock.GetValue();
if (pMwm &&
pMwm->m_cont.IsReaderExist(SEARCH_INDEX_FILE_TAG) &&
pMwm->GetHeader().GetType() == feature::DataHeader::world)
{
impl::Locality loc;
if (SearchLocality(pMwm, loc))
{
LOG(LDEBUG, ("Locality = ", loc.m_name));
Params params(*this);
params.EraseTokens(loc.m_matchedTokens);
if (!params.IsEmpty())
{
SetViewportByIndex(mwmInfo, scales::GetRectForLevel(ADDRESS_SCALE, loc.m_value.m_pt, 1.0), ADDRESS_RECT_ID);
/// @todo Hack - do not search for address in World.mwm; Do it better in future.
bool const b = m_worldSearch;
m_worldSearch = false;
SearchFeatures(params, mwmInfo, ADDRESS_RECT_ID);
m_worldSearch = b;
}
}
return;
}
}
}
namespace impl
{
class DoFindLocality
{
class EqualID
{
uint32_t m_id;
public:
EqualID(uint32_t id) : m_id(id) {}
bool operator() (Locality const & l) const { return (l.m_value.m_featureId == m_id); }
};
Query const & m_query;
vector<Locality> m_localities;
FeaturesVector m_vector;
size_t m_index; ///< index of processing token
volatile bool & m_isCancelled;
class TypeChecker
{
vector<uint32_t> m_vec;
public:
TypeChecker()
{
char const * arr[][2] = {
{ "place", "country" },
{ "place", "city" },
{ "place", "town" }
};
Classificator const & c = classif();
for (size_t i = 0; i < ARRAY_SIZE(arr); ++i)
m_vec.push_back(c.GetTypeByPath(vector<string>(arr[i], arr[i] + 2)));
}
uint32_t GetType(FeatureType const & f)
{
feature::TypesHolder types(f);
for (size_t i = 0; i < types.Size(); ++i)
{
uint32_t t = types[i];
ftype::TruncValue(t, 2);
if (find(m_vec.begin(), m_vec.end(), t) != m_vec.end())
return t;
}
return 0;
}
bool IsCountry(uint32_t t) const
{
return (t == m_vec[0]);
}
};
int8_t m_en, m_int;
void AssignEnglishName(FeatureType const & f, Locality & l)
{
if (!f.GetName(m_en, l.m_enName))
(void)f.GetName(m_int, l.m_enName);
}
public:
DoFindLocality(Query const & query, MwmValue * pMwm, volatile bool & isCancelled)
: m_query(query), m_vector(pMwm->m_cont, pMwm->GetHeader()), m_isCancelled(isCancelled)
{
m_en = StringUtf8Multilang::GetLangIndex("en");
m_int = StringUtf8Multilang::GetLangIndex("int_name");
}
void Resize(size_t) {}
void StartNew(size_t ind) { m_index = ind; }
void operator() (Query::TrieValueT const & v)
{
if (m_isCancelled)
throw Query::CancelException();
// find locality in current results
vector<Locality>::iterator it = find_if(m_localities.begin(), m_localities.end(),
EqualID(v.m_featureId));
if (it != m_localities.end())
{
it->m_matchedTokens.push_back(m_index);
return;
}
// load feature
FeatureType f;
m_vector.Get(v.m_featureId, f);
// check, if feature is locality
static TypeChecker checker;
uint32_t const t = checker.GetType(f);
/// @todo Process countries too.
if (t > 0 && !checker.IsCountry(t))
{
m_localities.push_back(Locality(v, t));
uint32_t penalty;
m_query.GetBestMatchName(f, penalty, m_localities.back().m_name);
m_localities.back().m_matchedTokens.push_back(m_index);
AssignEnglishName(f, m_localities.back());
}
}
bool GetBestLocality(Locality & res)
{
sort(m_localities.begin(), m_localities.end());
for (vector<Locality>::const_reverse_iterator i = m_localities.rbegin(); i != m_localities.rend(); ++i)
{
if (i->IsFullNameMatched())
{
res = *i;
return true;
}
}
return false;
}
};
}
bool Query::SearchLocality(MwmValue * pMwm, impl::Locality & res)
{
Params params(*this, true);
serial::CodingParams cp(GetCPForTrie(pMwm->GetHeader().GetDefCodingParams()));
ModelReaderPtr searchReader = pMwm->m_cont.GetReader(SEARCH_INDEX_FILE_TAG);
scoped_ptr<TrieIterator> pTrieRoot(::trie::reader::ReadTrie(
SubReaderWrapper<Reader>(searchReader.GetPtr()),
trie::ValueReader(cp),
trie::EdgeValueReader()));
for (size_t i = 0; i < pTrieRoot->m_edge.size(); ++i)
{
TrieIterator::Edge::EdgeStrT const & edge = pTrieRoot->m_edge[i].m_str;
if (edge[0] < search::CATEGORIES_LANG && params.IsLangExist(static_cast<int8_t>(edge[0])))
{
scoped_ptr<TrieIterator> pLangRoot(pTrieRoot->GoToEdge(i));
impl::DoFindLocality doFind(*this, pMwm, m_cancel);
GetFeaturesInTrie(params.m_tokens, params.m_prefixTokens,
TrieRootPrefix(*pLangRoot, edge), doFind);
// save better locality, if any
impl::Locality loc;
if (doFind.GetBestLocality(loc) && (res < loc))
res = loc;
}
}
return (res.m_type != 0);
}
void Query::SearchFeatures()
{
MWMVectorT mwmInfo;
m_pIndex->GetMwmInfo(mwmInfo);
// do usual search in viewport and near me (without last rect)
Params params(*this);
for (size_t i = 0; i < RECTSCOUNT; ++i)
for (size_t i = 0; i < RECTSCOUNT-1; ++i)
{
if (m_viewport[i].IsValid())
SearchFeatures(params, mwmInfo, i);
@ -698,11 +988,33 @@ namespace
binary_search(m_offsets->begin(), m_offsets->end(), offset));
}
};
template <class FilterT> class TrieValuesHolder
{
vector<vector<Query::TrieValueT> > m_holder;
size_t m_ind;
FilterT const & m_filter;
public:
TrieValuesHolder(FilterT const & filter) : m_filter(filter) {}
void Resize(size_t count) { m_holder.resize(count); }
void StartNew(size_t ind) { m_ind = ind; }
void operator() (Query::TrieValueT const & v)
{
if (m_filter(v.m_featureId))
m_holder[m_ind].push_back(v);
}
template <class ToDo> void GetValues(size_t ind, ToDo & toDo) const
{
for (size_t i = 0; i < m_holder[ind].size(); ++i)
toDo(m_holder[ind][i]);
}
};
}
void Query::SearchFeatures(Params const & params,
MWMVectorT const & mwmInfo,
size_t ind)
void Query::SearchFeatures(Params const & params, MWMVectorT const & mwmInfo, int ind)
{
for (MwmSet::MwmId mwmId = 0; mwmId < mwmInfo.size(); ++mwmId)
{
@ -710,21 +1022,21 @@ void Query::SearchFeatures(Params const & params,
if (m_viewport[ind].IsIntersect(mwmInfo[mwmId].m_limitRect))
{
Index::MwmLock mwmLock(*m_pIndex, mwmId);
SearchInMWM(mwmLock, params, &m_offsetsInViewport[ind]);
SearchInMWM(mwmLock, params, ind);
}
}
}
void Query::SearchInMWM(Index::MwmLock const & mwmLock, Params const & params,
OffsetsVectorT const * offsets)
void Query::SearchInMWM(Index::MwmLock const & mwmLock, Params const & params, int ind)
{
if (MwmValue * pMwm = mwmLock.GetValue())
{
if (pMwm->m_cont.IsReaderExist(SEARCH_INDEX_FILE_TAG))
{
feature::DataHeader const & header = pMwm->GetHeader();
bool const isWorld = (header.GetType() == feature::DataHeader::world);
/// @todo do not process World.mwm here - do it in SearchLocality
bool const isWorld = (header.GetType() == feature::DataHeader::world);
if (isWorld && !m_worldSearch)
return;
@ -736,42 +1048,48 @@ void Query::SearchInMWM(Index::MwmLock const & mwmLock, Params const & params,
trie::ValueReader(cp),
trie::EdgeValueReader()));
// Get categories edge root.
scoped_ptr<TrieIterator> pCategoriesRoot;
TrieIterator::Edge::EdgeStrT categoriesEdge;
size_t const count = pTrieRoot->m_edge.size();
for (size_t i = 0; i < count; ++i)
{
TrieIterator::Edge::EdgeStrT const & edge = pTrieRoot->m_edge[i].m_str;
ASSERT_GREATER_OR_EQUAL(edge.size(), 1, ());
if (edge[0] == search::CATEGORIES_LANG)
{
categoriesEdge = edge;
pCategoriesRoot.reset(pTrieRoot->GoToEdge(i));
break;
}
}
ASSERT_NOT_EQUAL(pCategoriesRoot, 0, ());
MwmSet::MwmId const mwmId = mwmLock.GetID();
impl::FeatureLoader emitter(*this, mwmId);
FeaturesFilter filter((ind == -1 || isWorld) ? 0 : &m_offsetsInViewport[ind][mwmId], m_cancel);
// Iterate through first language edges.
// Get categories for each token separately - find needed edge with categories.
TrieValuesHolder<FeaturesFilter> categoriesHolder(filter);
size_t const count = pTrieRoot->m_edge.size();
{
scoped_ptr<TrieIterator> pCategoriesRoot;
TrieIterator::Edge::EdgeStrT categoriesEdge;
for (size_t i = 0; i < count; ++i)
{
TrieIterator::Edge::EdgeStrT const & edge = pTrieRoot->m_edge[i].m_str;
ASSERT_GREATER_OR_EQUAL(edge.size(), 1, ());
if (edge[0] == search::CATEGORIES_LANG)
{
categoriesEdge = edge;
pCategoriesRoot.reset(pTrieRoot->GoToEdge(i));
break;
}
}
ASSERT_NOT_EQUAL(pCategoriesRoot, 0, ());
GetFeaturesInTrie(params.m_tokens, params.m_prefixTokens,
TrieRootPrefix(*pCategoriesRoot, categoriesEdge),
categoriesHolder);
}
impl::FeatureLoader emitter(*this, mwmId, ind);
// Match tokens to feature for each language - iterate through first edges.
for (size_t i = 0; i < count; ++i)
{
TrieIterator::Edge::EdgeStrT const & edge = pTrieRoot->m_edge[i].m_str;
if (edge[0] < search::CATEGORIES_LANG && params.m_langs.count(static_cast<int8_t>(edge[0])))
if (edge[0] < search::CATEGORIES_LANG && params.IsLangExist(static_cast<int8_t>(edge[0])))
{
scoped_ptr<TrieIterator> pLangRoot(pTrieRoot->GoToEdge(i));
MatchFeaturesInTrie(params.m_tokens, params.m_prefixTokens,
TrieRootPrefix(*pLangRoot, edge),
TrieRootPrefix(*pCategoriesRoot, categoriesEdge),
FeaturesFilter((isWorld || offsets == 0) ? 0 : &((*offsets)[mwmId]),
m_cancel),
emitter);
filter, categoriesHolder, emitter);
LOG(LDEBUG, ("Lang:",
StringUtf8Multilang::GetLangByCode(static_cast<int8_t>(edge[0])),
@ -835,8 +1153,15 @@ void Query::MatchForSuggestions(strings::UniString const & token, Results & res)
MatchForSuggestionsImpl(token, StringUtf8Multilang::GetLangIndex("en"), res);
}
m2::RectD const & Query::GetViewport() const
m2::RectD const & Query::GetViewport(int viewportID/* = -1*/) const
{
if (viewportID == ADDRESS_RECT_ID)
{
// special case for search address - return viewport around location
return m_viewport[viewportID];
}
// return first valid actual viewport
if (m_viewport[0].IsValid())
return m_viewport[0];
else
@ -846,6 +1171,16 @@ m2::RectD const & Query::GetViewport() const
}
}
m2::PointD Query::GetPosition(int viewportID/* = -1*/) const
{
if (viewportID == ADDRESS_RECT_ID)
{
// special case for search address - return center of location
return m_viewport[viewportID].Center();
}
return m_position;
}
void Query::SearchAllInViewport(m2::RectD const & viewport, Results & res, unsigned int resultsNeeded)
{
ASSERT ( viewport.IsValid(), () );

View file

@ -34,12 +34,15 @@ namespace impl
class FeatureLoader;
class BestNameFinder;
class PreResult2Maker;
struct Locality;
class DoFindLocality;
}
class Query
{
public:
static int const m_scaleDepthSearch = 7;
static int const SCALE_SEARCH_DEPTH = 7;
static int const ADDRESS_SCALE = 10;
struct SuggestT
{
@ -84,10 +87,13 @@ public:
inline bool IsCanceled() const { return m_cancel; }
struct CancelException {};
typedef trie::ValueReader::ValueType TrieValueT;
private:
friend class impl::FeatureLoader;
friend class impl::BestNameFinder;
friend class impl::PreResult2Maker;
friend class impl::DoFindLocality;
void InitSearch(string const & query);
void InitKeywordsScorer();
@ -96,12 +102,12 @@ private:
typedef vector<MwmInfo> MWMVectorT;
typedef vector<vector<uint32_t> > OffsetsVectorT;
void SetViewportByIndex(MWMVectorT const & mwmInfo, m2::RectD const & viewport, size_t idx);
void UpdateViewportOffsets(MWMVectorT const & mwmInfo, m2::RectD const & rect,
OffsetsVectorT & offsets);
void ClearCache(size_t ind);
typedef trie::ValueReader::ValueType TrieValueT;
void AddResultFromTrie(TrieValueT const & val, size_t mwmID);
void AddResultFromTrie(TrieValueT const & val, size_t mwmID, int viewportID);
void FlushResults(Results & res, void (Results::*pAddFn)(Result const &));
@ -114,22 +120,36 @@ private:
TokensVectorT m_prefixTokens;
LangsSetT m_langs;
Params(Query & q);
/// Initialize search params (tokens, languages).
/// @param[in] isLocalities Use true when search for locality in World.
Params(Query const & q, bool isLocalities = false);
/// @param[in] eraseInds Sorted vector of token's indexes.
void EraseTokens(vector<size_t> const & eraseInds);
bool IsEmpty() const { return (m_tokens.empty() && m_prefixTokens.empty()); }
bool IsLangExist(uint8_t l) const { return (m_langs.count(l) > 0); }
private:
void AddSynonims(Query const & q, bool isLocalities);
void FillLanguages(Query const & q);
};
void SearchAddress();
bool SearchLocality(MwmValue * pMwm, impl::Locality & res);
void SearchFeatures();
void SearchFeatures(Params const & params,
MWMVectorT const & mwmInfo,
size_t ind);
void SearchInMWM(Index::MwmLock const & mwmLock,
Params const & params,
OffsetsVectorT const * offsets);
void SearchFeatures(Params const & params, MWMVectorT const & mwmInfo, int ind);
/// Do search in particular map. Pass offsets == 0 if you don't want
/// results set to be intersected with source feature's offsets.
void SearchInMWM(Index::MwmLock const & mwmLock, Params const & params, int ind);
void SuggestStrings(Results & res);
bool MatchForSuggestionsImpl(strings::UniString const & token, int8_t lang, Results & res);
void MatchForSuggestions(strings::UniString const & token, Results & res);
void GetBestMatchName(FeatureType const & f, uint32_t & penalty, string & name);
void GetBestMatchName(FeatureType const & f, uint32_t & penalty, string & name) const;
inline Result MakeResult(impl::PreResult2 const & r, set<uint32_t> const * pPrefferedTypes = 0) const
{
@ -147,13 +167,22 @@ private:
buffer_vector<strings::UniString, 32> m_tokens;
strings::UniString m_prefix;
static size_t const RECTSCOUNT = 2;
/// 0 - current viewport rect
/// 1 - near me rect
/// 2 - around city rect
static size_t const RECTSCOUNT = 3;
static int const ADDRESS_RECT_ID = RECTSCOUNT-1;
m2::RectD m_viewport[RECTSCOUNT];
bool m_worldSearch;
/// @name Get ranking params.
/// @param[in] viewportID Index of search viewport (@see comments above); -1 means default viewport.
//@{
/// @return Rect for viewport-distance calculation.
m2::RectD const & GetViewport() const;
m2::RectD const & GetViewport(int viewportID = -1) const;
m2::PointD GetPosition(int viewportID = -1) const;
//@}
m2::PointD m_position;