diff --git a/indexer/feature.cpp b/indexer/feature.cpp index 87b3e6bf8e..dfb406a894 100644 --- a/indexer/feature.cpp +++ b/indexer/feature.cpp @@ -290,6 +290,15 @@ void FeatureType::GetPreferredDrawableNames(string & defaultName, string & intNa } } +bool FeatureType::GetName(int8_t lang, string & name) const +{ + if (!HasName()) + return false; + + ParseCommon(); + return m_Params.name.GetString(lang, name); +} + uint8_t FeatureType::GetRank() const { ParseCommon(); diff --git a/indexer/feature.hpp b/indexer/feature.hpp index c4d2e10b78..31faeb29b2 100644 --- a/indexer/feature.hpp +++ b/indexer/feature.hpp @@ -225,10 +225,7 @@ 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); - } + bool GetName(int8_t lang, string & name) const; //@} uint8_t GetRank() const; diff --git a/indexer/search_index_builder.cpp b/indexer/search_index_builder.cpp index 204c2f075a..fe52cb5471 100644 --- a/indexer/search_index_builder.cpp +++ b/indexer/search_index_builder.cpp @@ -10,6 +10,8 @@ #include "feature_visibility.hpp" #include "categories_holder.hpp" +#include "../search/search_common.hpp" // for MAX_TOKENS constant + #include "../defines.hpp" #include "../platform/platform.hpp" @@ -47,11 +49,11 @@ struct FeatureNameInserter buffer_vector tokens; SplitUniString(uniName, MakeBackInsertFunctor(tokens), search::Delimiters()); - /// @todo MAX_TOKENS = 32, in Query::Search we use 31 + prefix. Why 30 ??? - if (tokens.size() > 30) + int const maxTokensCount = search::MAX_TOKENS - 1; + if (tokens.size() > maxTokensCount) { LOG(LWARNING, ("Name has too many tokens:", name)); - tokens.resize(30); + tokens.resize(maxTokensCount); } for (size_t i = 0; i < tokens.size(); ++i) diff --git a/search/keyword_matcher.cpp b/search/keyword_matcher.cpp index 4592eda926..1bd9d098cc 100644 --- a/search/keyword_matcher.cpp +++ b/search/keyword_matcher.cpp @@ -11,42 +11,17 @@ namespace search { -KeywordMatcher::KeywordMatcher(strings::UniString const * const * pKeywords, - size_t keywordCount, - strings::UniString const * pPrefix) - : m_pKeywords(pKeywords), m_keywordCount(keywordCount), m_pPrefix(pPrefix), m_bOwnKeywords(false) +void KeywordMatcher::SetKeywords(StringT const * keywords, size_t count, StringT const * prefix) { - Initialize(); -} + ASSERT_LESS ( count, static_cast(MAX_TOKENS), () ); -KeywordMatcher::KeywordMatcher(strings::UniString const * keywords, - size_t keywordCount, - strings::UniString const * pPrefix) - : m_keywordCount(keywordCount), m_pPrefix(pPrefix), m_bOwnKeywords(false) -{ - Initialize(); - if (m_keywordCount > 0) - { - strings::UniString const * * pKeywords = new strings::UniString const * [m_keywordCount]; - for (size_t i = 0; i < m_keywordCount; ++i) - pKeywords[i] = &keywords[i]; - m_bOwnKeywords = true; - m_pKeywords = pKeywords; - } -} + m_keywords.resize(count); + for (size_t i = 0; i < count; ++i) + m_keywords[i] = &keywords[i]; -void KeywordMatcher::Initialize() -{ - ASSERT_LESS(m_keywordCount, size_t(MAX_TOKENS), ()); - m_keywordCount = min(m_keywordCount, size_t(MAX_TOKENS)); - if (m_pPrefix && m_pPrefix->empty()) - m_pPrefix = NULL; -} - -KeywordMatcher::~KeywordMatcher() -{ - if (m_bOwnKeywords) - delete [] m_pKeywords; + m_prefix = prefix; + if (m_prefix && m_prefix->empty()) + m_prefix = 0; } uint32_t KeywordMatcher::Score(string const & name) const @@ -54,55 +29,56 @@ uint32_t KeywordMatcher::Score(string const & name) const return Score(NormalizeAndSimplifyString(name)); } -uint32_t KeywordMatcher::Score(strings::UniString const & name) const +uint32_t KeywordMatcher::Score(StringT const & name) const { - buffer_vector tokens; + buffer_vector tokens; SplitUniString(name, MakeBackInsertFunctor(tokens), Delimiters()); - ASSERT_LESS(tokens.size(), size_t(MAX_TOKENS), ()); - return Score(tokens.data(), static_cast(tokens.size())); + ASSERT_LESS ( tokens.size(), static_cast(MAX_TOKENS), () ); + return Score(tokens.data(), min(size_t(MAX_TOKENS-1), tokens.size())); } -uint32_t KeywordMatcher::Score(strings::UniString const * tokens, int tokenCount) const +uint32_t KeywordMatcher::Score(StringT const * tokens, size_t count) const { - ASSERT_LESS(tokenCount, int(MAX_TOKENS), ()); + ASSERT_LESS ( count, static_cast(MAX_TOKENS), () ); - // We will use this for scoring. + // boolean array of matched input tokens unsigned char isTokenMatched[MAX_TOKENS] = { 0 }; - // Check that all keywords matched. - for (int k = 0; k < m_keywordCount; ++k) + // calculate penalty by keywords - add MAX_TOKENS for each unmatched keyword + uint32_t score = 0; + for (size_t i = 0; i < m_keywords.size(); ++i) { unsigned char isKeywordMatched = 0; - for (int t = 0; t < tokenCount; ++t) - if (*m_pKeywords[k] == tokens[t]) - isKeywordMatched = isTokenMatched[t] = 1; + for (size_t j = 0; j < count; ++j) + if (*m_keywords[i] == tokens[j]) + isKeywordMatched = isTokenMatched[j] = 1; - // All keywords should be matched. if (!isKeywordMatched) - return MAX_SCORE; + score += MAX_TOKENS; } - // Check that prefix matched. - if (m_pPrefix) + // calculate penalty for prefix - add MAX_TOKENS for unmatched prefix + if (m_prefix) { bool bPrefixMatched = false; - for (int t = 0; t < tokenCount && !bPrefixMatched; ++t) - if (StartsWith(tokens[t].begin(), tokens[t].end(), - m_pPrefix->begin(), m_pPrefix->end())) + for (size_t i = 0; i < count && !bPrefixMatched; ++i) + if (StartsWith(tokens[i].begin(), tokens[i].end(), + m_prefix->begin(), m_prefix->end())) + { bPrefixMatched = true; + } + if (!bPrefixMatched) - return MAX_SCORE; + score += MAX_TOKENS; } - // Calculate score. - int lastTokenMatched = 0; - for (int t = 0; t < tokenCount; ++t) - if (isTokenMatched[t]) - lastTokenMatched = t; - uint32_t score = 0; - for (int t = 0; t <= lastTokenMatched; ++t) - if (tokens[t].size() > 2 && !isTokenMatched[t]) + // add penalty for each unmatched token in input sequence + for (size_t i = 0; i <= count; ++i) + { + // check for token length (skip common tokens such as "de", "la", "a") + if (tokens[i].size() > 2 && !isTokenMatched[i]) ++score; + } return score; } diff --git a/search/keyword_matcher.hpp b/search/keyword_matcher.hpp index 0cd41b0697..8730df2c8b 100644 --- a/search/keyword_matcher.hpp +++ b/search/keyword_matcher.hpp @@ -12,27 +12,30 @@ namespace search class KeywordMatcher { public: - enum { MAX_SCORE = MAX_TOKENS }; + enum { MAX_SCORE = MAX_TOKENS * MAX_TOKENS }; + typedef strings::UniString StringT; - KeywordMatcher(strings::UniString const * const * pKeywords, size_t keywordCount, - strings::UniString const * pPrefix); - KeywordMatcher(strings::UniString const * keywords, size_t keywordCount, - strings::UniString const * pPrefix); - ~KeywordMatcher(); + KeywordMatcher() : m_prefix(0) {} + inline void Clear() + { + m_keywords.clear(); + m_prefix = 0; + } - // Returns penalty (which is less than MAX_SCORE) if name matched, or MAX_SCORE otherwise. + /// Store references to keywords from source array of strings. + void SetKeywords(StringT const * keywords, size_t count, StringT const * prefix); + + /// @return penalty of string (less is better). + //@{ uint32_t Score(string const & name) const; - uint32_t Score(strings::UniString const & name) const; - uint32_t Score(strings::UniString const * tokens, int tokenCount) const; + uint32_t Score(StringT const & name) const; + uint32_t Score(StringT const * tokens, size_t count) const; + //@} private: - void Initialize(); - - strings::UniString const * const * m_pKeywords; - size_t m_keywordCount; - strings::UniString const * m_pPrefix; - bool m_bOwnKeywords; + buffer_vector m_keywords; + StringT const * m_prefix; }; } // namespace search diff --git a/search/lang_keywords_scorer.cpp b/search/lang_keywords_scorer.cpp index 3631e263c8..b7315af6c4 100644 --- a/search/lang_keywords_scorer.cpp +++ b/search/lang_keywords_scorer.cpp @@ -11,11 +11,34 @@ namespace search { -LangKeywordsScorer::LangKeywordsScorer(vector > const & languagePriorities, - strings::UniString const * keywords, size_t keywordCount, - strings::UniString const * pPrefix) - : m_languagePriorities(languagePriorities), m_keywordMatcher(keywords, keywordCount, pPrefix) +void LangKeywordsScorer::SetLanguages(vector > const & languagePriorities) { + m_languagePriorities = languagePriorities; + +#ifdef DEBUG + ASSERT_EQUAL ( static_cast(NUM_LANG_PRIORITY_TIERS), m_languagePriorities.size(), () ); + for (int i = 0; i < NUM_LANG_PRIORITY_TIERS; ++i) + ASSERT_LESS_OR_EQUAL ( m_languagePriorities[i].size(), static_cast(MAX_LANGS_IN_TIER), () ); +#endif +} + +bool LangKeywordsScorer::AssertIndex(pair const & ind) const +{ + ASSERT_LESS ( static_cast(ind.first), m_languagePriorities.size(), () ); + ASSERT_LESS ( static_cast(ind.second), m_languagePriorities[ind.first].size(), () ); + return true; +} + +void LangKeywordsScorer::SetLanguage(pair const & ind, int8_t lang) +{ + ASSERT ( AssertIndex(ind), () ); + m_languagePriorities[ind.first][ind.second] = lang; +} + +int8_t LangKeywordsScorer::GetLanguage(pair const & ind) const +{ + ASSERT ( AssertIndex(ind), () ); + return m_languagePriorities[ind.first][ind.second]; } uint32_t LangKeywordsScorer::Score(int8_t lang, string const & name) const @@ -23,29 +46,28 @@ uint32_t LangKeywordsScorer::Score(int8_t lang, string const & name) const return Score(lang, NormalizeAndSimplifyString(name)); } -uint32_t LangKeywordsScorer::Score(int8_t lang, strings::UniString const & name) const +uint32_t LangKeywordsScorer::Score(int8_t lang, StringT const & name) const { - buffer_vector tokens; + buffer_vector tokens; SplitUniString(name, MakeBackInsertFunctor(tokens), Delimiters()); - return Score(lang, tokens.data(), min(MAX_TOKENS-1, static_cast(tokens.size()))); + ASSERT_LESS ( tokens.size(), static_cast(MAX_TOKENS), () ); + return Score(lang, tokens.data(), min(size_t(MAX_TOKENS-1), tokens.size())); } -uint32_t LangKeywordsScorer::Score(int8_t lang, - strings::UniString const * tokens, int tokenCount) const +uint32_t LangKeywordsScorer::Score(int8_t lang, StringT const * tokens, size_t count) const { - uint32_t const keywordScore = m_keywordMatcher.Score(tokens, tokenCount); - if (keywordScore == KeywordMatcher::MAX_SCORE) - return MAX_SCORE; // TODO: Differentiate between langs with MAX_SCORE score. + uint32_t const keywordScore = m_keywordMatcher.Score(tokens, count); + + // get score by language priority + uint32_t const factor = KeywordMatcher::MAX_SCORE * MAX_LANGS_IN_TIER; + uint32_t const value = keywordScore * MAX_LANGS_IN_TIER; for (uint32_t i = 0; i < NUM_LANG_PRIORITY_TIERS; ++i) for (uint32_t j = 0; j < m_languagePriorities[i].size(); ++j) if (m_languagePriorities[i][j] == lang) - return i * KeywordMatcher::MAX_SCORE * (MAX_LANGS_IN_TIER + 1) - + keywordScore * (MAX_LANGS_IN_TIER + 1) - + min(j, static_cast(MAX_LANGS_IN_TIER)); + return (i * factor + value + j); - return NUM_LANG_PRIORITY_TIERS * KeywordMatcher::MAX_SCORE * (MAX_LANGS_IN_TIER + 1) - + keywordScore * (MAX_LANGS_IN_TIER + 1); + return (NUM_LANG_PRIORITY_TIERS * factor); } } // namespace search diff --git a/search/lang_keywords_scorer.hpp b/search/lang_keywords_scorer.hpp index 8a70fa3d86..166375132b 100644 --- a/search/lang_keywords_scorer.hpp +++ b/search/lang_keywords_scorer.hpp @@ -9,21 +9,30 @@ namespace search class LangKeywordsScorer { -public: - enum { NUM_LANG_PRIORITY_TIERS = 3 }; - enum { MAX_LANGS_IN_TIER = 3 }; - enum { MAX_SCORE = KeywordMatcher::MAX_SCORE - * (NUM_LANG_PRIORITY_TIERS + 1) * (MAX_LANGS_IN_TIER + 1) }; + enum { NUM_LANG_PRIORITY_TIERS = 4 }; + enum { MAX_LANGS_IN_TIER = 2 }; - LangKeywordsScorer(vector > const & languagePriorities, - strings::UniString const * keywords, size_t keywordCount, - strings::UniString const * pPrefix); + typedef KeywordMatcher::StringT StringT; + +public: + /// @param[in] languagePriorities Should match the constants above (checked by assertions). + void SetLanguages(vector > const & languagePriorities); + void SetLanguage(pair const & ind, int8_t lang); + int8_t GetLanguage(pair const & ind) const; + + /// Store references to keywords from source array of strings. + inline void SetKeywords(StringT const * keywords, size_t count, StringT const * prefix) + { + m_keywordMatcher.SetKeywords(keywords, count, prefix); + } uint32_t Score(int8_t lang, string const & name) const; - uint32_t Score(int8_t lang, strings::UniString const & name) const; - uint32_t Score(int8_t lang, strings::UniString const * tokens, int tokenCount) const; + uint32_t Score(int8_t lang, StringT const & name) const; + uint32_t Score(int8_t lang, StringT const * tokens, size_t count) const; private: + bool AssertIndex(pair const & ind) const; + vector > m_languagePriorities; KeywordMatcher m_keywordMatcher; }; diff --git a/search/search_common.hpp b/search/search_common.hpp index a3de69a754..6f59052e9a 100644 --- a/search/search_common.hpp +++ b/search/search_common.hpp @@ -3,6 +3,7 @@ namespace search { +/// Upper bound for max count of tokens for indexing and scoring. enum { MAX_TOKENS = 32 }; template diff --git a/search/search_query.cpp b/search/search_query.cpp index a0ebdc405b..e53a67ce4b 100644 --- a/search/search_query.cpp +++ b/search/search_query.cpp @@ -48,6 +48,22 @@ namespace &impl::PreResult2::LessViewportDistance, &impl::PreResult2::LessDistance }; + + /// This indexes should match the initialization routine below. + int g_arrLang1[] = { 0, 1, 2, 2, 3 }; + int g_arrLang2[] = { 0, 0, 0, 1, 0 }; + enum LangIndexT { LANG_CURRENT = 0, + LANG_INPUT, + LANG_INTERNATIONAL, + LANG_ENGLISH, + LANG_DEFAULT, + LANG_COUNT }; + + pair GetLangIndex(int id) + { + ASSERT_LESS ( id, LANG_COUNT, () ); + return make_pair(g_arrLang1[id], g_arrLang2[id]); + } } @@ -67,8 +83,6 @@ Query::Query(Index const * pIndex, ASSERT ( m_pIndex, () ); - SetPreferredLanguage("en"); - // Results queue's initialization. STATIC_ASSERT ( m_qCount == ARRAY_SIZE(g_arrCompare1) ); STATIC_ASSERT ( m_qCount == ARRAY_SIZE(g_arrCompare2) ); @@ -78,12 +92,34 @@ Query::Query(Index const * pIndex, m_results[i] = QueueT(2 * resultsNeeded, QueueCompareT(g_arrCompare1[i])); m_results[i].reserve(2 * resultsNeeded); } + + // Initialize keywords scorer. + // Note! This order should match the indexes arrays above. + vector > langPriorities(4); + langPriorities[0].push_back(0); // future current lang + langPriorities[1].push_back(0); // future input lang + langPriorities[2].push_back(StringUtf8Multilang::GetLangIndex("int_name")); + langPriorities[2].push_back(StringUtf8Multilang::GetLangIndex("en")); + langPriorities[3].push_back(StringUtf8Multilang::GetLangIndex("default")); + m_keywordsScorer.SetLanguages(langPriorities); + + SetPreferredLanguage("en"); } Query::~Query() { } +void Query::SetLanguage(int id, int8_t lang) +{ + m_keywordsScorer.SetLanguage(GetLangIndex(id), lang); +} + +int8_t Query::GetLanguage(int id) const +{ + return m_keywordsScorer.GetLanguage(GetLangIndex(id)); +} + namespace { inline bool IsEqualMercator(m2::RectD const & r1, m2::RectD const & r2, double epsMeters) @@ -125,11 +161,17 @@ void Query::SetViewportByIndex(MWMVectorT const & mwmInfo, m2::RectD const & vie void Query::SetPreferredLanguage(string const & lang) { - m_currentLang = StringUtf8Multilang::GetLangIndex(lang); + int8_t const code = StringUtf8Multilang::GetLangIndex(lang); + SetLanguage(LANG_CURRENT, code); // Default initialization. // If you want to reset input language, call SetInputLanguage before search. - m_inputLang = m_currentLang; + SetInputLanguage(code); +} + +void Query::SetInputLanguage(int8_t lang) +{ + SetLanguage(LANG_INPUT, lang); } void Query::ClearCache() @@ -203,18 +245,6 @@ void Query::InitSearch(string const & query) m_prefix.clear(); } -void Query::InitKeywordsScorer() -{ - vector > 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::ClearQueues() { for (size_t i = 0; i < m_qCount; ++i) @@ -223,10 +253,9 @@ void Query::ClearQueues() void Query::Search(string const & query, Results & res) { - // Initialize. - InitSearch(query); + // split input query by tokens and prefix search::Delimiters delims; SplitUniString(NormalizeAndSimplifyString(query), MakeBackInsertFunctor(m_tokens), delims); @@ -235,10 +264,13 @@ void Query::Search(string const & query, Results & res) m_prefix.swap(m_tokens.back()); m_tokens.pop_back(); } - if (m_tokens.size() > 31) - m_tokens.resize(31); - InitKeywordsScorer(); + int const maxTokensCount = MAX_TOKENS-1; + if (m_tokens.size() > maxTokensCount) + m_tokens.resize(maxTokensCount); + + // assign tokens and prefix to scorer + m_keywordsScorer.SetKeywords(m_tokens.data(), m_tokens.size(), &m_prefix); ClearQueues(); @@ -259,6 +291,7 @@ void Query::Search(string const & query, Results & res) SearchAddress(); if (m_cancel) return; + LOG(LDEBUG, ("Usual search")); SearchFeatures(); if (m_cancel) return; @@ -585,7 +618,7 @@ public: void Query::GetBestMatchName(FeatureType const & f, uint32_t & penalty, string & name) const { - impl::BestNameFinder bestNameFinder(penalty, name, *m_pKeywordsScorer); + impl::BestNameFinder bestNameFinder(penalty, name, m_keywordsScorer); (void)f.ForEachNameRef(bestNameFinder); /* @@ -598,6 +631,11 @@ void Query::GetBestMatchName(FeatureType const & f, uint32_t & penalty, string & */ } +Result Query::MakeResult(impl::PreResult2 const & r, set const * pPrefferedTypes/* = 0*/) const +{ + return r.GenerateFinalResult(m_pInfoGetter, m_pCategories, pPrefferedTypes, GetLanguage(LANG_CURRENT)); +} + namespace impl { @@ -704,11 +742,8 @@ void Query::Params::EraseTokens(vector const & eraseInds) 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")); - m_langs.insert(StringUtf8Multilang::GetLangIndex("en")); - m_langs.insert(StringUtf8Multilang::GetLangIndex("default")); + for (int i = 0; i < LANG_COUNT; ++i) + m_langs.insert(q.GetLanguage(i)); } namespace impl @@ -723,7 +758,16 @@ namespace impl Locality() : m_type(0) {} Locality(Query::TrieValueT const & val, uint32_t type) : m_value(val), m_type(type) {} - bool operator<(Locality const & rhs) const + void Swap(Locality & rhs) + { + m_name.swap(rhs.m_name); + m_enName.swap(rhs.m_enName); + swap(m_value, rhs.m_value); + swap(m_type, rhs.m_type); + m_matchedTokens.swap(rhs.m_matchedTokens); + } + + bool operator< (Locality const & rhs) const { if (m_matchedTokens.size() != rhs.m_matchedTokens.size()) return (m_matchedTokens.size() < rhs.m_matchedTokens.size()); @@ -750,6 +794,8 @@ namespace impl return (count <= m_matchedTokens.size()); } }; + + void swap(Locality & r1, Locality & r2) { r1.Swap(r2); } } void Query::SearchAddress() @@ -769,10 +815,11 @@ void Query::SearchAddress() impl::Locality loc; if (SearchLocality(pMwm, loc)) { - LOG(LDEBUG, ("Locality = ", loc.m_name)); + LOG(LDEBUG, ("Locality = ", loc.m_enName)); 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); @@ -801,15 +848,11 @@ namespace impl bool operator() (Locality const & l) const { return (l.m_value.m_featureId == m_id); } }; - Query const & m_query; - vector m_localities; FeaturesVector m_vector; size_t m_index; ///< index of processing token - volatile bool & m_isCancelled; - class TypeChecker { vector m_vec; @@ -848,16 +891,18 @@ namespace impl } }; - int8_t m_en, m_int; + int8_t m_lang, 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); } + volatile bool & m_isCancelled; + public: - DoFindLocality(Query const & query, MwmValue * pMwm, volatile bool & isCancelled) - : m_query(query), m_vector(pMwm->m_cont, pMwm->GetHeader()), m_isCancelled(isCancelled) + DoFindLocality(MwmValue * pMwm, int8_t lang, volatile bool & isCancelled) + : m_vector(pMwm->m_cont, pMwm->GetHeader()), m_lang(lang), m_isCancelled(isCancelled) { m_en = StringUtf8Multilang::GetLangIndex("en"); m_int = StringUtf8Multilang::GetLangIndex("int_name"); @@ -892,8 +937,7 @@ namespace impl { m_localities.push_back(Locality(v, t)); - uint32_t penalty; - m_query.GetBestMatchName(f, penalty, m_localities.back().m_name); + f.GetName(m_lang, m_localities.back().m_name); m_localities.back().m_matchedTokens.push_back(m_index); @@ -934,11 +978,12 @@ bool Query::SearchLocality(MwmValue * pMwm, impl::Locality & res) 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(edge[0]))) + int8_t const lang = static_cast(edge[0]); + if (lang < search::CATEGORIES_LANG && params.IsLangExist(lang)) { scoped_ptr pLangRoot(pTrieRoot->GoToEdge(i)); - impl::DoFindLocality doFind(*this, pMwm, m_cancel); + impl::DoFindLocality doFind(pMwm, lang, m_cancel); GetFeaturesInTrie(params.m_tokens, params.m_prefixTokens, TrieRootPrefix(*pLangRoot, edge), doFind); @@ -957,8 +1002,9 @@ void Query::SearchFeatures() MWMVectorT mwmInfo; m_pIndex->GetMwmInfo(mwmInfo); - // do usual search in viewport and near me (without last rect) Params params(*this); + + // do usual search in viewport and near me (without last rect) for (size_t i = 0; i < RECTSCOUNT-1; ++i) { if (m_viewport[i].IsValid()) @@ -1149,8 +1195,8 @@ bool Query::MatchForSuggestionsImpl(strings::UniString const & token, int8_t lan void Query::MatchForSuggestions(strings::UniString const & token, Results & res) { - if (!MatchForSuggestionsImpl(token, m_inputLang, res)) - MatchForSuggestionsImpl(token, StringUtf8Multilang::GetLangIndex("en"), res); + if (!MatchForSuggestionsImpl(token, GetLanguage(LANG_INPUT), res)) + MatchForSuggestionsImpl(token, GetLanguage(LANG_ENGLISH), res); } m2::RectD const & Query::GetViewport(int viewportID/* = -1*/) const @@ -1194,9 +1240,7 @@ void Query::SearchAllInViewport(m2::RectD const & viewport, Results & res, unsig UpdateViewportOffsets(mwmInfo, viewport, offsets); } - // Init search. InitSearch(string()); - InitKeywordsScorer(); vector indV; diff --git a/search/search_query.hpp b/search/search_query.hpp index cb39d86067..973bd953d4 100644 --- a/search/search_query.hpp +++ b/search/search_query.hpp @@ -1,5 +1,6 @@ #pragma once #include "intermediate_result.hpp" +#include "lang_keywords_scorer.hpp" #include "../indexer/search_trie.hpp" #include "../indexer/index.hpp" // for Index::MwmLock @@ -18,8 +19,6 @@ class FeatureType; -//class Index; -//class MwmInfo; class CategoriesHolder; namespace storage { class CountryInfoGetter; } @@ -27,8 +26,6 @@ namespace storage { class CountryInfoGetter; } namespace search { -class LangKeywordsScorer; - namespace impl { class FeatureLoader; @@ -75,7 +72,7 @@ public: inline void SetSearchInWorld(bool b) { m_worldSearch = b; } void SetPreferredLanguage(string const & lang); - inline void SetInputLanguage(int8_t lang) { m_inputLang = lang; } + void SetInputLanguage(int8_t lang); void Search(string const & query, Results & res); void SearchAllInViewport(m2::RectD const & viewport, Results & res, unsigned int resultsNeeded = 30); @@ -96,7 +93,6 @@ private: friend class impl::DoFindLocality; void InitSearch(string const & query); - void InitKeywordsScorer(); void ClearQueues(); typedef vector MWMVectorT; @@ -151,16 +147,12 @@ private: void GetBestMatchName(FeatureType const & f, uint32_t & penalty, string & name) const; - inline Result MakeResult(impl::PreResult2 const & r, set const * pPrefferedTypes = 0) const - { - return r.GenerateFinalResult(m_pInfoGetter, m_pCategories, pPrefferedTypes, m_currentLang); - } + Result MakeResult(impl::PreResult2 const & r, set const * pPrefferedTypes = 0) const; Index const * m_pIndex; CategoriesHolder const * m_pCategories; StringsToSuggestVectorT const * m_pStringsToSuggest; storage::CountryInfoGetter const * m_pInfoGetter; - int8_t m_currentLang, m_inputLang; volatile bool m_cancel; @@ -186,7 +178,10 @@ private: m2::PointD m_position; - scoped_ptr m_pKeywordsScorer; + void SetLanguage(int id, int8_t lang); + int8_t GetLanguage(int id) const; + + LangKeywordsScorer m_keywordsScorer; OffsetsVectorT m_offsetsInViewport[RECTSCOUNT]; diff --git a/search/search_tests/keyword_matcher_test.cpp b/search/search_tests/keyword_matcher_test.cpp index 35683d9e20..2653869d5f 100644 --- a/search/search_tests/keyword_matcher_test.cpp +++ b/search/search_tests/keyword_matcher_test.cpp @@ -22,69 +22,58 @@ public: m_prefix = m_keywords.back(); m_keywords.pop_back(); } - m_ptrs.resize(m_keywords.size()); - for (size_t i = 0; i < m_keywords.size(); ++i) - m_ptrs[i] = &m_keywords[i]; - m_pMatcher.reset(new search::KeywordMatcher(m_ptrs.data(), int(m_ptrs.size()), &m_prefix)); + + m_matcher.SetKeywords(m_keywords.data(), m_keywords.size(), &m_prefix); } - scoped_ptr m_pMatcher; + search::KeywordMatcher m_matcher; private: buffer_vector m_keywords; - buffer_vector m_ptrs; strings::UniString m_prefix; }; } // unnamed namespace + UNIT_TEST(KeywordMatcher_New) { Matcher matcher("new "); - TEST_EQUAL(matcher.m_pMatcher->Score("new"), 0, ()); - TEST_EQUAL(matcher.m_pMatcher->Score("york"), MAX_SCORE, ()); - TEST_EQUAL(matcher.m_pMatcher->Score("new york"), 0, ()); + TEST_EQUAL(matcher.m_matcher.Score("new"), 0, ()); + TEST_EQUAL(matcher.m_matcher.Score("york"), MAX_SCORE, ()); + TEST_EQUAL(matcher.m_matcher.Score("new york"), 0, ()); } UNIT_TEST(KeywordMatcher_York) { Matcher matcher("york "); - TEST_EQUAL(matcher.m_pMatcher->Score("new"), MAX_SCORE, ()); - TEST_EQUAL(matcher.m_pMatcher->Score("york"), 0, ()); - TEST_EQUAL(matcher.m_pMatcher->Score("new york"), 1, ()); + TEST_EQUAL(matcher.m_matcher.Score("new"), MAX_SCORE, ()); + TEST_EQUAL(matcher.m_matcher.Score("york"), 0, ()); + TEST_EQUAL(matcher.m_matcher.Score("new york"), 1, ()); } UNIT_TEST(KeywordMatcher_NewYork) { Matcher matcher1("new york "); Matcher matcher2("new york"); - TEST_EQUAL(matcher1.m_pMatcher->Score("new"), MAX_SCORE, ()); - TEST_EQUAL(matcher2.m_pMatcher->Score("new"), MAX_SCORE, ()); - TEST_EQUAL(matcher1.m_pMatcher->Score("york"), MAX_SCORE, ()); - TEST_EQUAL(matcher2.m_pMatcher->Score("york"), MAX_SCORE, ()); - TEST_EQUAL(matcher1.m_pMatcher->Score("new york"), 0, ()); - TEST_EQUAL(matcher2.m_pMatcher->Score("new york"), 0, ()); + TEST_EQUAL(matcher1.m_matcher.Score("new"), MAX_SCORE, ()); + TEST_EQUAL(matcher2.m_matcher.Score("new"), MAX_SCORE, ()); + TEST_EQUAL(matcher1.m_matcher.Score("york"), MAX_SCORE, ()); + TEST_EQUAL(matcher2.m_matcher.Score("york"), MAX_SCORE, ()); + TEST_EQUAL(matcher1.m_matcher.Score("new york"), 0, ()); + TEST_EQUAL(matcher2.m_matcher.Score("new york"), 0, ()); } UNIT_TEST(KeywordMatcher_YorkNew) { Matcher matcher("new york "); - TEST_EQUAL(matcher.m_pMatcher->Score("new"), MAX_SCORE, ()); - TEST_EQUAL(matcher.m_pMatcher->Score("york"), MAX_SCORE, ()); - TEST_EQUAL(matcher.m_pMatcher->Score("new york"), 0, ()); + TEST_EQUAL(matcher.m_matcher.Score("new"), MAX_SCORE, ()); + TEST_EQUAL(matcher.m_matcher.Score("york"), MAX_SCORE, ()); + TEST_EQUAL(matcher.m_matcher.Score("new york"), 0, ()); } UNIT_TEST(KeywordMatcher_NewYo) { Matcher matcher("new yo"); - TEST_EQUAL(matcher.m_pMatcher->Score("new"), MAX_SCORE, ()); - TEST_EQUAL(matcher.m_pMatcher->Score("york"), MAX_SCORE, ()); - TEST_EQUAL(matcher.m_pMatcher->Score("new york"), 0, ()); + TEST_EQUAL(matcher.m_matcher.Score("new"), MAX_SCORE, ()); + TEST_EQUAL(matcher.m_matcher.Score("york"), MAX_SCORE, ()); + TEST_EQUAL(matcher.m_matcher.Score("new york"), 0, ()); } - - - - - - - - -