diff options
author | ygorshenin <mipt.vi002@gmail.com> | 2016-06-29 15:01:33 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-06-29 15:01:33 +0300 |
commit | 3a7817fbdf44b11203bdadccdb34a08b8181e46b (patch) | |
tree | c01867116c9cdbddfdd86e4afb3b5ae0fb7ad2c0 /search | |
parent | e68ec46f1888b59d37caa6401cc5f13d31f66821 (diff) | |
parent | 62b300cbaf5641a19b56e35c27c7229bb4609ffa (diff) |
Merge pull request #3675 from mpimenov/ranker
[search] Removed Ranker's dependency on Processor.
Diffstat (limited to 'search')
-rw-r--r-- | search/engine.cpp | 22 | ||||
-rw-r--r-- | search/engine.hpp | 3 | ||||
-rw-r--r-- | search/features_layer_matcher.cpp | 2 | ||||
-rw-r--r-- | search/features_layer_matcher.hpp | 2 | ||||
-rw-r--r-- | search/geocoder.cpp | 4 | ||||
-rw-r--r-- | search/geocoder.hpp | 4 | ||||
-rw-r--r-- | search/nested_rects_cache.cpp | 2 | ||||
-rw-r--r-- | search/nested_rects_cache.hpp | 4 | ||||
-rw-r--r-- | search/params.hpp | 1 | ||||
-rw-r--r-- | search/pre_ranker.cpp | 2 | ||||
-rw-r--r-- | search/pre_ranker.hpp | 2 | ||||
-rw-r--r-- | search/processor.cpp | 400 | ||||
-rw-r--r-- | search/processor.hpp | 61 | ||||
-rw-r--r-- | search/processor_factory.hpp | 1 | ||||
-rw-r--r-- | search/ranker.cpp | 309 | ||||
-rw-r--r-- | search/ranker.hpp | 127 | ||||
-rw-r--r-- | search/search.pro | 1 |
17 files changed, 498 insertions, 449 deletions
diff --git a/search/engine.cpp b/search/engine.cpp index a761e3e556..2046e09a2d 100644 --- a/search/engine.cpp +++ b/search/engine.cpp @@ -1,7 +1,8 @@ #include "search/engine.hpp" -#include "geometry_utils.hpp" -#include "processor.hpp" +#include "search/geometry_utils.hpp" +#include "search/params.hpp" +#include "search/processor.hpp" #include "storage/country_info_getter.hpp" @@ -126,16 +127,16 @@ Engine::Params::Params(string const & locale, size_t numThreads) Engine::Engine(Index & index, CategoriesHolder const & categories, storage::CountryInfoGetter const & infoGetter, unique_ptr<ProcessorFactory> factory, Params const & params) - : m_categories(categories), m_shutdown(false) + : m_shutdown(false) { InitSuggestions doInit; - m_categories.ForEachName(bind<void>(ref(doInit), _1)); + categories.ForEachName(bind<void>(ref(doInit), _1)); doInit.GetSuggests(m_suggests); m_contexts.resize(params.m_numThreads); for (size_t i = 0; i < params.m_numThreads; ++i) { - auto processor = factory->Build(index, m_categories, m_suggests, infoGetter); + auto processor = factory->Build(index, categories, m_suggests, infoGetter); processor->SetPreferredLocale(params.m_locale); m_contexts[i].m_processor = move(processor); } @@ -320,7 +321,14 @@ void Engine::DoSearch(SearchParams const & params, m2::RectD const & viewport, Results res; - processor.SearchCoordinates(res); + try + { + processor.SearchCoordinates(res); + } + catch (CancelException const &) + { + LOG(LDEBUG, ("Search has been cancelled.")); + } try { @@ -336,7 +344,7 @@ void Engine::DoSearch(SearchParams const & params, m2::RectD const & viewport, if (!processor.IsCancelled()) EmitResults(params, res); } - catch (Processor::CancelException const &) + catch (CancelException const &) { LOG(LDEBUG, ("Search has been cancelled.")); } diff --git a/search/engine.hpp b/search/engine.hpp index 2462a4c616..07f66119e2 100644 --- a/search/engine.hpp +++ b/search/engine.hpp @@ -91,7 +91,7 @@ public: size_t m_numThreads; }; - // Doesn't take ownership of index. Takes ownership of categoriesR. + // Doesn't take ownership of index and categories. Engine(Index & index, CategoriesHolder const & categories, storage::CountryInfoGetter const & infoGetter, unique_ptr<ProcessorFactory> factory, Params const & params); @@ -161,7 +161,6 @@ private: void DoSearch(SearchParams const & params, m2::RectD const & viewport, shared_ptr<ProcessorHandle> handle, Processor & processor); - CategoriesHolder const & m_categories; vector<Suggest> m_suggests; bool m_shutdown; diff --git a/search/features_layer_matcher.cpp b/search/features_layer_matcher.cpp index 1f98b22ffb..0132857e76 100644 --- a/search/features_layer_matcher.cpp +++ b/search/features_layer_matcher.cpp @@ -13,7 +13,7 @@ namespace search /// even if there is no exact street written for this house. int constexpr kMaxApproxStreetDistanceM = 100; -FeaturesLayerMatcher::FeaturesLayerMatcher(Index & index, my::Cancellable const & cancellable) +FeaturesLayerMatcher::FeaturesLayerMatcher(Index const & index, my::Cancellable const & cancellable) : m_context(nullptr) , m_postcodes(nullptr) , m_reverseGeocoder(index) diff --git a/search/features_layer_matcher.hpp b/search/features_layer_matcher.hpp index f9ae2df657..5d69b58bbc 100644 --- a/search/features_layer_matcher.hpp +++ b/search/features_layer_matcher.hpp @@ -59,7 +59,7 @@ public: static int constexpr kBuildingRadiusMeters = 50; static int constexpr kStreetRadiusMeters = 100; - FeaturesLayerMatcher(Index & index, my::Cancellable const & cancellable); + FeaturesLayerMatcher(Index const & index, my::Cancellable const & cancellable); void SetContext(MwmContext * context); void SetPostcodes(coding::CompressedBitVector const * postcodes); diff --git a/search/geocoder.cpp b/search/geocoder.cpp index 29a9af2409..a2ae1e262c 100644 --- a/search/geocoder.cpp +++ b/search/geocoder.cpp @@ -258,7 +258,7 @@ bool HasSearchIndex(MwmValue const & value) { return value.m_cont.IsExist(SEARCH bool HasGeometryIndex(MwmValue & value) { return value.m_cont.IsExist(INDEX_FILE_TAG); } -MwmSet::MwmHandle FindWorld(Index & index, vector<shared_ptr<MwmInfo>> const & infos) +MwmSet::MwmHandle FindWorld(Index const & index, vector<shared_ptr<MwmInfo>> const & infos) { MwmSet::MwmHandle handle; for (auto const & info : infos) @@ -406,7 +406,7 @@ void UniteCBVs(vector<unique_ptr<coding::CompressedBitVector>> & cbvs) Geocoder::Params::Params() : m_mode(Mode::Everywhere), m_accuratePivotCenter(0, 0) {} // Geocoder::Geocoder ------------------------------------------------------------------------------ -Geocoder::Geocoder(Index & index, storage::CountryInfoGetter const & infoGetter, +Geocoder::Geocoder(Index const & index, storage::CountryInfoGetter const & infoGetter, my::Cancellable const & cancellable) : m_index(index) , m_infoGetter(infoGetter) diff --git a/search/geocoder.hpp b/search/geocoder.hpp index 79e549bba6..c771402ad9 100644 --- a/search/geocoder.hpp +++ b/search/geocoder.hpp @@ -141,7 +141,7 @@ public: #endif }; - Geocoder(Index & index, storage::CountryInfoGetter const & infoGetter, + Geocoder(Index const & index, storage::CountryInfoGetter const & infoGetter, my::Cancellable const & cancellable); ~Geocoder(); @@ -306,7 +306,7 @@ private: // |m_usedTokens| if there are no unused tokens. size_t SkipUsedTokens(size_t curToken) const; - Index & m_index; + Index const & m_index; storage::CountryInfoGetter const & m_infoGetter; diff --git a/search/nested_rects_cache.cpp b/search/nested_rects_cache.cpp index 3e9f37abcc..5cecd69070 100644 --- a/search/nested_rects_cache.cpp +++ b/search/nested_rects_cache.cpp @@ -19,7 +19,7 @@ namespace double const kPositionToleranceMeters = 15.0; } // namespace -NestedRectsCache::NestedRectsCache(Index & index) +NestedRectsCache::NestedRectsCache(Index const & index) : m_index(index), m_scale(0), m_position(0, 0), m_valid(false) { } diff --git a/search/nested_rects_cache.hpp b/search/nested_rects_cache.hpp index 077c37b34c..62c454da40 100644 --- a/search/nested_rects_cache.hpp +++ b/search/nested_rects_cache.hpp @@ -14,7 +14,7 @@ namespace search class NestedRectsCache { public: - explicit NestedRectsCache(Index & index); + explicit NestedRectsCache(Index const & index); void SetPosition(m2::PointD const & position, int scale); @@ -37,7 +37,7 @@ private: void Update(); - Index & m_index; + Index const & m_index; int m_scale; m2::PointD m_position; bool m_valid; diff --git a/search/params.hpp b/search/params.hpp index 211ffb6c17..0c688a1e3b 100644 --- a/search/params.hpp +++ b/search/params.hpp @@ -50,7 +50,6 @@ namespace search inline void Clear() { m_query.clear(); } - public: TOnStarted m_onStarted; TOnResults m_onResults; diff --git a/search/pre_ranker.cpp b/search/pre_ranker.cpp index b5782fbbfb..f333b5efcd 100644 --- a/search/pre_ranker.cpp +++ b/search/pre_ranker.cpp @@ -44,8 +44,6 @@ struct ComparePreResult1 PreRanker::PreRanker(size_t limit) : m_limit(limit) {} -void PreRanker::Add(PreResult1 const & result) { m_results.push_back(result); } - void PreRanker::Filter(bool viewportSearch) { using TSet = set<PreResult1, LessFeatureID>; diff --git a/search/pre_ranker.hpp b/search/pre_ranker.hpp index 2bb61f6901..725c11d61f 100644 --- a/search/pre_ranker.hpp +++ b/search/pre_ranker.hpp @@ -17,8 +17,6 @@ class PreRanker public: explicit PreRanker(size_t limit); - void Add(PreResult1 const & result); - template <typename... TArgs> void Emplace(TArgs &&... args) { diff --git a/search/processor.cpp b/search/processor.cpp index 50ff2cc7a3..4262e6b372 100644 --- a/search/processor.cpp +++ b/search/processor.cpp @@ -12,7 +12,7 @@ #include "search/ranking_utils.hpp" #include "search/region.hpp" #include "search/search_index_values.hpp" -#include "search/string_intersection.hpp" +#include "search/utils.hpp" #include "storage/country_info_getter.hpp" #include "storage/index.hpp" @@ -53,13 +53,6 @@ #include "std/iterator.hpp" #include "std/limits.hpp" -#define LONG_OP(op) \ - { \ - if (IsCancelled()) \ - return; \ - op; \ - } - namespace search { namespace @@ -84,24 +77,6 @@ pair<int, int> GetLangIndex(int id) return make_pair(g_arrLang1[id], g_arrLang2[id]); } -ftypes::Type GetLocalityIndex(feature::TypesHolder const & types) -{ - using namespace ftypes; - - // Inner logic of SearchAddress expects COUNTRY, STATE and CITY only. - Type const type = IsLocalityChecker::Instance().GetType(types); - switch (type) - { - case NONE: - case COUNTRY: - case STATE: - case CITY: return type; - case TOWN: return CITY; - case VILLAGE: return NONE; - case LOCALITY_COUNT: return type; - } -} - m2::RectD NormalizeViewport(m2::RectD viewport) { m2::RectD minViewport = MercatorBounds::RectByCenterXYAndSizeInMeters( @@ -119,15 +94,6 @@ m2::RectD GetRectAroundPosition(m2::PointD const & position) double constexpr kMaxPositionRadiusM = 50.0 * 1000; return MercatorBounds::RectByCenterXYAndSizeInMeters(position, kMaxPositionRadiusM); } - -inline bool IsHashtagged(strings::UniString const & s) { return !s.empty() && s[0] == '#'; } - -inline strings::UniString RemoveHashtag(strings::UniString const & s) -{ - if (IsHashtagged(s)) - return strings::UniString(s.begin() + 1, s.end()); - return s; -} } // namespace // static @@ -137,24 +103,19 @@ size_t const Processor::kPreResultsCount; double const Processor::kMinViewportRadiusM = 5.0 * 1000; double const Processor::kMaxViewportRadiusM = 50.0 * 1000; -Processor::Processor(Index & index, CategoriesHolder const & categories, +Processor::Processor(Index const & index, CategoriesHolder const & categories, vector<Suggest> const & suggests, storage::CountryInfoGetter const & infoGetter) - : m_index(index) - , m_categories(categories) - , m_suggests(suggests) + : m_categories(categories) , m_infoGetter(infoGetter) -#ifdef FIND_LOCALITY_TEST - , m_locality(&index) -#endif , m_position(0, 0) , m_mode(Mode::Everywhere) , m_worldSearch(true) , m_suggestsEnabled(true) , m_preRanker(kPreResultsCount) - , m_ranker(m_preRanker, *this) + , m_ranker(m_preRanker, index, infoGetter, categories, suggests, + static_cast<my::Cancellable const &>(*this)) , m_geocoder(index, infoGetter, static_cast<my::Cancellable const &>(*this)) - , m_reverseGeocoder(index) { // Initialize keywords scorer. // Note! This order should match the indexes arrays above. @@ -164,7 +125,7 @@ Processor::Processor(Index & index, CategoriesHolder const & categories, {StringUtf8Multilang::kInternationalCode, StringUtf8Multilang::kEnglishCode}, {StringUtf8Multilang::kDefaultCode}}; - m_keywordsScorer.SetLanguages(langPriorities); + m_ranker.SetLanguages(langPriorities); SetPreferredLocale("en"); } @@ -186,7 +147,7 @@ void Processor::SetPreferredLocale(string const & locale) { ASSERT(!locale.empty(), ()); - LOG(LINFO, ("New preffered locale:", locale)); + LOG(LINFO, ("New preferred locale:", locale)); int8_t const code = StringUtf8Multilang::GetLangIndex(languages::Normalize(locale)); SetLanguage(LANG_CURRENT, code); @@ -196,10 +157,9 @@ void Processor::SetPreferredLocale(string const & locale) // Default initialization. // If you want to reset input language, call SetInputLocale before search. SetInputLocale(locale); - #ifdef FIND_LOCALITY_TEST - m_locality.SetLanguage(code); -#endif + m_ranker.SetLocalityFinderLanguage(code); +#endif // FIND_LOCALITY_TEST } void Processor::SetInputLocale(string const & locale) @@ -269,15 +229,15 @@ void Processor::SetQuery(string const & query) m_tokens.resize(maxTokensCount); // Assign tokens and prefix to scorer. - m_keywordsScorer.SetKeywords(m_tokens.data(), m_tokens.size(), m_prefix); + m_ranker.SetKeywords(m_tokens.data(), m_tokens.size(), m_prefix); - // get preffered types to show in results - m_prefferedTypes.clear(); + // get preferred types to show in results + m_preferredTypes.clear(); ForEachCategoryType(QuerySliceOnRawStrings<decltype(m_tokens)>(m_tokens, m_prefix), - [&](size_t, uint32_t t) - { - m_prefferedTypes.insert(t); - }); + [&](size_t, uint32_t t) + { + m_preferredTypes.insert(t); + }); } void Processor::SetRankPivot(m2::PointD const & pivot) @@ -294,12 +254,12 @@ void Processor::SetRankPivot(m2::PointD const & pivot) void Processor::SetLanguage(int id, int8_t lang) { - m_keywordsScorer.SetLanguage(GetLangIndex(id), lang); + m_ranker.SetLanguage(GetLangIndex(id), lang); } int8_t Processor::GetLanguage(int id) const { - return m_keywordsScorer.GetLanguage(GetLangIndex(id)); + return m_ranker.GetLanguage(GetLangIndex(id)); } m2::PointD Processor::GetPivotPoint() const @@ -360,68 +320,41 @@ void Processor::SetViewportByIndex(m2::RectD const & viewport, size_t idx, bool void Processor::ClearCache(size_t ind) { m_viewport[ind].MakeEmpty(); } -int Processor::GetCategoryLocales(int8_t(&arr)[3]) const +TLocales Processor::GetCategoryLocales() const { static int8_t const enLocaleCode = CategoriesHolder::MapLocaleToInteger("en"); + TLocales result; // Prepare array of processing locales. English locale is always present for category matching. - int count = 0; if (m_currentLocaleCode != -1) - arr[count++] = m_currentLocaleCode; + result.push_back(m_currentLocaleCode); if (m_inputLocaleCode != -1 && m_inputLocaleCode != m_currentLocaleCode) - arr[count++] = m_inputLocaleCode; + result.push_back(m_inputLocaleCode); if (enLocaleCode != m_currentLocaleCode && enLocaleCode != m_inputLocaleCode) - arr[count++] = enLocaleCode; + result.push_back(enLocaleCode); - return count; + return result; } -void Processor::ForEachCategoryType(StringSliceBase const & slice, - function<void(size_t, uint32_t)> const & fn) const +template <typename ToDo> +void Processor::ForEachCategoryType(StringSliceBase const & slice, ToDo && todo) const { - int8_t arrLocales[3]; - int const localesCount = GetCategoryLocales(arrLocales); - - for (size_t i = 0; i < slice.Size(); ++i) - { - auto token = RemoveHashtag(slice.Get(i)); - for (int j = 0; j < localesCount; ++j) - m_categories.ForEachTypeByName(arrLocales[j], token, bind<void>(fn, i, _1)); - ProcessEmojiIfNeeded(token, i, fn); - } -} - -// template <class ToDo> -void Processor::ProcessEmojiIfNeeded(strings::UniString const & token, size_t index, - function<void(size_t, uint32_t)> const & fn) const -{ - // Special process of 2 codepoints emoji (e.g. black guy on a bike). - // Only emoji synonyms can have one codepoint. - if (token.size() > 1) - { - static int8_t const enLocaleCode = CategoriesHolder::MapLocaleToInteger("en"); - - m_categories.ForEachTypeByName(enLocaleCode, strings::UniString(1, token[0]), - bind<void>(fn, index, _1)); - } + ::search::ForEachCategoryType(slice, GetCategoryLocales(), m_categories, forward<ToDo>(todo)); } void Processor::Search(Results & results, size_t limit) { - if (m_tokens.empty()) - SuggestStrings(results); + Geocoder::Params geocoderParams; + InitGeocoderParams(geocoderParams); - Geocoder::Params params; + Ranker::Params rankerParams; + InitRankerParams(rankerParams); - InitParams(params); - params.m_mode = m_mode; - params.m_pivot = GetPivotRect(); - params.m_accuratePivotCenter = GetPivotPoint(); - m_geocoder.SetParams(params); + if (m_tokens.empty()) + m_ranker.SuggestStrings(results); m_geocoder.GoEverywhere(m_preRanker); - - m_ranker.FlushResults(params, results, limit); + m_ranker.FlushResults(geocoderParams, results, limit); } void Processor::SearchViewportPoints(Results & results) @@ -429,6 +362,7 @@ void Processor::SearchViewportPoints(Results & results) Geocoder::Params params; InitParams(params); + params.m_mode = m_mode; params.m_pivot = m_viewport[CURRENT_V]; params.m_accuratePivotCenter = params.m_pivot.Center(); m_geocoder.SetParams(params); @@ -444,212 +378,12 @@ void Processor::SearchCoordinates(Results & res) const if (MatchLatLonDegree(m_query, lat, lon)) { ASSERT_EQUAL(res.GetCount(), 0, ()); - res.AddResultNoChecks(MakeResult(PreResult2(lat, lon))); + // Note that ranker's locale is not set up here but + // it is never used when making lat-lon results anyway. + res.AddResultNoChecks(m_ranker.MakeResult(PreResult2(lat, lon))); } } -void Processor::RemoveStringPrefix(string const & str, string & res) const -{ - search::Delimiters delims; - // Find start iterator of prefix in input query. - using TIter = utf8::unchecked::iterator<string::const_iterator>; - TIter iter(str.end()); - while (iter.base() != str.begin()) - { - TIter prev = iter; - --prev; - - if (delims(*prev)) - break; - else - iter = prev; - } - - // Assign result with input string without prefix. - res.assign(str.begin(), iter.base()); -} - -void Processor::GetSuggestion(string const & name, string & suggest) const -{ - // Splits result's name. - search::Delimiters delims; - vector<strings::UniString> tokens; - SplitUniString(NormalizeAndSimplifyString(name), MakeBackInsertFunctor(tokens), delims); - - // Finds tokens that are already present in the input query. - vector<bool> tokensMatched(tokens.size()); - bool prefixMatched = false; - bool fullPrefixMatched = false; - - for (size_t i = 0; i < tokens.size(); ++i) - { - auto const & token = tokens[i]; - - if (find(m_tokens.begin(), m_tokens.end(), token) != m_tokens.end()) - { - tokensMatched[i] = true; - } - else if (StartsWith(token, m_prefix)) - { - prefixMatched = true; - fullPrefixMatched = token.size() == m_prefix.size(); - } - } - - // When |name| does not match prefix or when prefix equals to some - // token of the |name| (for example, when user entered "Moscow" - // without space at the end), we should not suggest anything. - if (!prefixMatched || fullPrefixMatched) - return; - - RemoveStringPrefix(m_query, suggest); - - // Appends unmatched result's tokens to the suggestion. - for (size_t i = 0; i < tokens.size(); ++i) - { - if (tokensMatched[i]) - continue; - suggest.append(strings::ToUtf8(tokens[i])); - suggest.push_back(' '); - } -} - -void Processor::ProcessSuggestions(vector<IndexedValue> & vec, Results & res) const -{ - if (m_prefix.empty() || !m_suggestsEnabled) - return; - - int added = 0; - for (auto i = vec.begin(); i != vec.end();) - { - PreResult2 const & r = **i; - - ftypes::Type const type = GetLocalityIndex(r.GetTypes()); - if ((type == ftypes::COUNTRY || type == ftypes::CITY) || r.IsStreet()) - { - string suggest; - GetSuggestion(r.GetName(), suggest); - if (!suggest.empty() && added < MAX_SUGGESTS_COUNT) - { - if (res.AddResult((Result(MakeResult(r), suggest)))) - ++added; - - i = vec.erase(i); - continue; - } - } - ++i; - } -} - -class BestNameFinder -{ - KeywordLangMatcher::ScoreT m_score; - string & m_name; - KeywordLangMatcher const & m_keywordsScorer; - -public: - BestNameFinder(string & name, KeywordLangMatcher const & keywordsScorer) - : m_score(), m_name(name), m_keywordsScorer(keywordsScorer) - { - } - - bool operator()(int8_t lang, string const & name) - { - KeywordLangMatcher::ScoreT const score = m_keywordsScorer.Score(lang, name); - if (m_score < score) - { - m_score = score; - m_name = name; - } - return true; - } -}; - -void Processor::GetBestMatchName(FeatureType const & f, string & name) const -{ - BestNameFinder finder(name, m_keywordsScorer); - UNUSED_VALUE(f.ForEachName(finder)); -} - -/// Makes continuous range for tokens and prefix. -template <class TIter, class ValueT> -class CombinedIter -{ - TIter m_i, m_end; - ValueT const * m_val; - -public: - CombinedIter(TIter i, TIter end, ValueT const * val) : m_i(i), m_end(end), m_val(val) {} - - ValueT const & operator*() const - { - ASSERT(m_val != 0 || m_i != m_end, ("dereferencing of empty iterator")); - if (m_i != m_end) - return *m_i; - - return *m_val; - } - - CombinedIter & operator++() - { - if (m_i != m_end) - ++m_i; - else - m_val = 0; - return *this; - } - - bool operator==(CombinedIter const & other) const - { - return m_val == other.m_val && m_i == other.m_i; - } - - bool operator!=(CombinedIter const & other) const - { - return m_val != other.m_val || m_i != other.m_i; - } -}; - -class AssignHighlightRange -{ - Result & m_res; - -public: - AssignHighlightRange(Result & res) : m_res(res) {} - - void operator()(pair<uint16_t, uint16_t> const & range) { m_res.AddHighlightRange(range); } -}; - -Result Processor::MakeResult(PreResult2 const & r) const -{ - Result res = r.GenerateFinalResult(m_infoGetter, &m_categories, &m_prefferedTypes, - m_currentLocaleCode, &m_reverseGeocoder); - MakeResultHighlight(res); -#ifdef FIND_LOCALITY_TEST - if (ftypes::IsLocalityChecker::Instance().GetType(r.GetTypes()) == ftypes::NONE) - { - string city; - m_locality.GetLocality(res.GetFeatureCenter(), city); - res.AppendCity(city); - } -#endif - - res.SetRankingInfo(r.GetRankingInfo()); - return res; -} - -void Processor::MakeResultHighlight(Result & res) const -{ - using TIter = buffer_vector<strings::UniString, 32>::const_iterator; - using TCombinedIter = CombinedIter<TIter, strings::UniString>; - - TCombinedIter beg(m_tokens.begin(), m_tokens.end(), m_prefix.empty() ? 0 : &m_prefix); - TCombinedIter end(m_tokens.end(), m_tokens.end(), 0); - - SearchStringTokensIntersectionRanges(res.GetString(), beg, end, AssignHighlightRange(res)); -} - namespace { int GetOldTypeFromIndex(size_t index) @@ -852,46 +586,38 @@ void Processor::InitParams(QueryParams & params) params.m_langs.insert(GetLanguage(i)); } -void Processor::ClearCaches() +void Processor::InitGeocoderParams(Geocoder::Params & params) { - for (size_t i = 0; i < COUNT_V; ++i) - ClearCache(i); - - m_locality.ClearCache(); - m_geocoder.ClearCaches(); + InitParams(params); + params.m_mode = m_mode; + params.m_pivot = GetPivotRect(); + params.m_accuratePivotCenter = GetPivotPoint(); + m_geocoder.SetParams(params); } -void Processor::SuggestStrings(Results & res) +void Processor::InitRankerParams(Ranker::Params & params) { - if (m_prefix.empty() || !m_suggestsEnabled) - return; - int8_t arrLocales[3]; - int const localesCount = GetCategoryLocales(arrLocales); - - string prolog; - RemoveStringPrefix(m_query, prolog); - - for (int i = 0; i < localesCount; ++i) - MatchForSuggestionsImpl(m_prefix, arrLocales[i], prolog, res); + params.m_currentLocaleCode = m_currentLocaleCode; + if (m_mode == Mode::Viewport) + params.m_viewport = GetViewport(); + params.m_position = GetPosition(); + params.m_pivotRegion = GetPivotRegion(); + params.m_preferredTypes = m_preferredTypes; + params.m_suggestsEnabled = m_suggestsEnabled; + params.m_query = m_query; + params.m_tokens = m_tokens; + params.m_prefix = m_prefix; + params.m_categoryLocales = GetCategoryLocales(); + m_ranker.SetParams(params); } -void Processor::MatchForSuggestionsImpl(strings::UniString const & token, int8_t locale, - string const & prolog, Results & res) +void Processor::ClearCaches() { - for (auto const & suggest : m_suggests) - { - strings::UniString const & s = suggest.m_name; - if ((suggest.m_prefixLength <= token.size()) && - (token != s) && // do not push suggestion if it already equals to token - (suggest.m_locale == locale) && // push suggestions only for needed language - StartsWith(s.begin(), s.end(), token.begin(), token.end())) - { - string const utf8Str = strings::ToUtf8(s); - Result r(utf8Str, prolog + utf8Str + " "); - MakeResultHighlight(r); - res.AddResult(move(r)); - } - } + for (size_t i = 0; i < COUNT_V; ++i) + ClearCache(i); + + m_geocoder.ClearCaches(); + m_ranker.ClearCaches(); } m2::RectD const & Processor::GetViewport(ViewportID vID /*= DEFAULT_V*/) const diff --git a/search/processor.hpp b/search/processor.hpp index 0a0de1b566..7e77c72125 100644 --- a/search/processor.hpp +++ b/search/processor.hpp @@ -1,11 +1,10 @@ #pragma once #include "search/geocoder.hpp" -#include "search/keyword_lang_matcher.hpp" #include "search/mode.hpp" +#include "search/params.hpp" #include "search/pre_ranker.hpp" #include "search/ranker.hpp" #include "search/rank_table_cache.hpp" -#include "search/reverse_geocoder.hpp" #include "search/search_trie.hpp" #include "search/suggest.hpp" #include "search/token_slice.hpp" @@ -29,12 +28,6 @@ #include "std/unique_ptr.hpp" #include "std/vector.hpp" -#define FIND_LOCALITY_TEST - -#ifdef FIND_LOCALITY_TEST -#include "search/locality_finder.hpp" -#endif - class FeatureType; class CategoriesHolder; @@ -61,7 +54,6 @@ class Ranker; class PreResult2Maker; class FeatureLoader; -class BestNameFinder; class DoFindLocality; class HouseCompFactory; @@ -74,8 +66,8 @@ public: static double const kMinViewportRadiusM; static double const kMaxViewportRadiusM; - Processor(Index & index, CategoriesHolder const & categories, vector<Suggest> const & suggests, - storage::CountryInfoGetter const & infoGetter); + Processor(Index const & index, CategoriesHolder const & categories, + vector<Suggest> const & suggests, storage::CountryInfoGetter const & infoGetter); inline void SupportOldFormat(bool b) { m_supportOldFormat = b; } @@ -111,11 +103,9 @@ public: void SearchCoordinates(Results & res) const; //@} - struct CancelException - { - }; - void InitParams(QueryParams & params); + void InitGeocoderParams(Geocoder::Params & params); + void InitRankerParams(Ranker::Params & params); void ClearCaches(); @@ -137,19 +127,15 @@ protected: friend class PreResult2Maker; friend class Ranker; - int GetCategoryLocales(int8_t(&arr)[3]) const; - - void ForEachCategoryType( - StringSliceBase const & slice, - function<void(size_t /* tokenId */, uint32_t /* typeId */)> const & fn) const; - - void ProcessEmojiIfNeeded( - strings::UniString const & token, size_t index, - function<void(size_t /* tokenId */, uint32_t /* typeId */)> const & fn) const; - using TMWMVector = vector<shared_ptr<MwmInfo>>; using TOffsetsVector = map<MwmSet::MwmId, vector<uint32_t>>; using TFHeader = feature::DataHeader; + using TLocales = buffer_vector<int8_t, 3>; + + TLocales GetCategoryLocales() const; + + template <typename ToDo> + void ForEachCategoryType(StringSliceBase const & slice, ToDo && todo) const; m2::PointD GetPivotPoint() const; m2::RectD GetPivotRect() const; @@ -157,34 +143,14 @@ protected: void SetViewportByIndex(m2::RectD const & viewport, size_t idx, bool forceUpdate); void ClearCache(size_t ind); - void RemoveStringPrefix(string const & str, string & res) const; - void GetSuggestion(string const & name, string & suggest) const; - - void ProcessSuggestions(vector<IndexedValue> & vec, Results & res) const; - - void SuggestStrings(Results & res); - void MatchForSuggestionsImpl(strings::UniString const & token, int8_t locale, - string const & prolog, Results & res); - - void GetBestMatchName(FeatureType const & f, string & name) const; - - Result MakeResult(PreResult2 const & r) const; - void MakeResultHighlight(Result & res) const; - - Index & m_index; CategoriesHolder const & m_categories; - vector<Suggest> const & m_suggests; storage::CountryInfoGetter const & m_infoGetter; string m_region; string m_query; buffer_vector<strings::UniString, 32> m_tokens; strings::UniString m_prefix; - set<uint32_t> m_prefferedTypes; - -#ifdef FIND_LOCALITY_TEST - mutable LocalityFinder m_locality; -#endif + set<uint32_t> m_preferredTypes; m2::RectD m_viewport[COUNT_V]; m2::PointD m_pivot; @@ -202,8 +168,6 @@ protected: void SetLanguage(int id, int8_t lang); int8_t GetLanguage(int id) const; - KeywordLangMatcher m_keywordsScorer; - bool m_supportOldFormat; protected: @@ -212,6 +176,5 @@ protected: PreRanker m_preRanker; Ranker m_ranker; Geocoder m_geocoder; - ReverseGeocoder const m_reverseGeocoder; }; } // namespace search diff --git a/search/processor_factory.hpp b/search/processor_factory.hpp index 5e0fc0fe78..4eeb8cec74 100644 --- a/search/processor_factory.hpp +++ b/search/processor_factory.hpp @@ -1,5 +1,6 @@ #pragma once +#include "search/params.hpp" #include "search/processor.hpp" #include "search/suggest.hpp" diff --git a/search/ranker.cpp b/search/ranker.cpp index 8507cc5ff4..c2c0d5b3ad 100644 --- a/search/ranker.cpp +++ b/search/ranker.cpp @@ -1,6 +1,8 @@ #include "search/ranker.hpp" -#include "search/processor.hpp" +#include "search/pre_ranker.hpp" +#include "search/string_intersection.hpp" #include "search/token_slice.hpp" +#include "search/utils.hpp" #include "indexer/feature_algo.hpp" @@ -46,12 +48,94 @@ void RemoveDuplicatingLinear(vector<IndexedValue> & values) }), values.end()); } + +// Chops off the last query token (the "prefix" one) from |str| and stores the result in |res|. +void GetStringPrefix(string const & str, string & res) +{ + search::Delimiters delims; + // Find start iterator of prefix in input query. + using TIter = utf8::unchecked::iterator<string::const_iterator>; + TIter iter(str.end()); + while (iter.base() != str.begin()) + { + TIter prev = iter; + --prev; + + if (delims(*prev)) + break; + + iter = prev; + } + + // Assign result with input string without prefix. + res.assign(str.begin(), iter.base()); +} + +ftypes::Type GetLocalityIndex(feature::TypesHolder const & types) +{ + using namespace ftypes; + + // Inner logic of SearchAddress expects COUNTRY, STATE and CITY only. + Type const type = IsLocalityChecker::Instance().GetType(types); + switch (type) + { + case NONE: + case COUNTRY: + case STATE: + case CITY: return type; + case TOWN: return CITY; + case VILLAGE: return NONE; + case LOCALITY_COUNT: return type; + } +} + +/// Makes continuous range for tokens and prefix. +template <class TIter, class TValue> +class CombinedIter +{ + TIter m_cur; + TIter m_end; + TValue const * m_val; + +public: + CombinedIter(TIter cur, TIter end, TValue const * val) : m_cur(cur), m_end(end), m_val(val) {} + + TValue const & operator*() const + { + ASSERT(m_val != 0 || m_cur != m_end, ("dereferencing of empty iterator")); + if (m_cur != m_end) + return *m_cur; + + return *m_val; + } + + CombinedIter & operator++() + { + if (m_cur != m_end) + ++m_cur; + else + m_val = 0; + return *this; + } + + bool operator==(CombinedIter const & other) const + { + return m_val == other.m_val && m_cur == other.m_cur; + } + + bool operator!=(CombinedIter const & other) const + { + return m_val != other.m_val || m_cur != other.m_cur; + } +}; } // namespace class PreResult2Maker { - Processor & m_processor; + Ranker & m_ranker; + Index const & m_index; Geocoder::Params const & m_params; + storage::CountryInfoGetter const & m_infoGetter; unique_ptr<Index::FeaturesLoaderGuard> m_pFV; @@ -60,14 +144,14 @@ class PreResult2Maker string & country) { if (m_pFV.get() == 0 || m_pFV->GetId() != id.m_mwmId) - m_pFV.reset(new Index::FeaturesLoaderGuard(m_processor.m_index, id.m_mwmId)); + m_pFV.reset(new Index::FeaturesLoaderGuard(m_index, id.m_mwmId)); m_pFV->GetFeatureByIndex(id.m_index, f); f.SetID(id); center = feature::GetCenter(f); - m_processor.GetBestMatchName(f, name); + m_ranker.GetBestMatchName(f, name); // country (region) name is a file name if feature isn't from World.mwm if (m_pFV->IsWorld()) @@ -108,12 +192,13 @@ class PreResult2Maker feature::TypesHolder holder(ft); vector<pair<size_t, size_t>> matched(slice.Size()); - m_processor.ForEachCategoryType(QuerySlice(slice), [&](size_t i, uint32_t t) - { - ++matched[i].second; - if (holder.Has(t)) - ++matched[i].first; - }); + ForEachCategoryType(QuerySlice(slice), m_ranker.m_params.m_categoryLocales, + m_ranker.m_categories, [&](size_t i, uint32_t t) + { + ++matched[i].second; + if (holder.Has(t)) + ++matched[i].first; + }); info.m_pureCats = all_of(matched.begin(), matched.end(), [](pair<size_t, size_t> const & m) { @@ -133,15 +218,15 @@ class PreResult2Maker case SearchModel::SEARCH_TYPE_VILLAGE: return rank /= 1.5; case SearchModel::SEARCH_TYPE_CITY: { - if (m_processor.GetViewport(Processor::CURRENT_V).IsPointInside(center)) + if (m_ranker.m_params.m_viewport.IsPointInside(center)) return rank * 2; storage::CountryInfo info; if (country.empty()) - m_processor.m_infoGetter.GetRegionInfo(center, info); + m_infoGetter.GetRegionInfo(center, info); else - m_processor.m_infoGetter.GetRegionInfo(country, info); - if (info.IsNotEmpty() && info.m_name == m_processor.GetPivotRegion()) + m_infoGetter.GetRegionInfo(country, info); + if (info.IsNotEmpty() && info.m_name == m_ranker.m_params.m_pivotRegion) return rank *= 1.7; } case SearchModel::SEARCH_TYPE_COUNTRY: @@ -153,8 +238,10 @@ class PreResult2Maker } public: - explicit PreResult2Maker(Processor & q, Geocoder::Params const & params) - : m_processor(q), m_params(params) + explicit PreResult2Maker(Ranker & ranker, Index const & index, + storage::CountryInfoGetter const & infoGetter, + Geocoder::Params const & params) + : m_ranker(ranker), m_index(index), m_params(params), m_infoGetter(infoGetter) { } @@ -167,7 +254,7 @@ public: LoadFeature(res1.GetId(), ft, center, name, country); - auto res2 = make_unique<PreResult2>(ft, &res1, center, m_processor.GetPosition() /* pivot */, + auto res2 = make_unique<PreResult2>(ft, &res1, center, m_ranker.m_params.m_position /* pivot */, name, country); search::RankingInfo info; @@ -189,13 +276,13 @@ bool Ranker::IsResultExists(PreResult2 const & p, vector<IndexedValue> const & v }); } -void Ranker::MakePreResult2(Geocoder::Params const & params, vector<IndexedValue> & cont, +void Ranker::MakePreResult2(Geocoder::Params const & geocoderParams, vector<IndexedValue> & cont, vector<FeatureID> & streets) { - m_preRanker.Filter(m_viewportSearch); + m_preRanker.Filter(m_params.m_viewportSearch); // Makes PreResult2 vector. - PreResult2Maker maker(m_processor, params); + PreResult2Maker maker(*this, m_index, m_infoGetter, geocoderParams); m_preRanker.ForEach( [&](PreResult1 const & r) { @@ -203,7 +290,8 @@ void Ranker::MakePreResult2(Geocoder::Params const & params, vector<IndexedValue if (!p) return; - if (params.m_mode == Mode::Viewport && !params.m_pivot.IsPointInside(p->GetCenter())) + if (geocoderParams.m_mode == Mode::Viewport && + !geocoderParams.m_pivot.IsPointInside(p->GetCenter())) return; if (p->IsStreet()) @@ -214,6 +302,160 @@ void Ranker::MakePreResult2(Geocoder::Params const & params, vector<IndexedValue }); } +Result Ranker::MakeResult(PreResult2 const & r) const +{ + Result res = r.GenerateFinalResult(m_infoGetter, &m_categories, &m_params.m_preferredTypes, + m_params.m_currentLocaleCode, &m_reverseGeocoder); + MakeResultHighlight(res); +#ifdef FIND_LOCALITY_TEST + if (ftypes::IsLocalityChecker::Instance().GetType(r.GetTypes()) == ftypes::NONE) + { + string city; + m_locality.GetLocality(res.GetFeatureCenter(), city); + res.AppendCity(city); + } +#endif // FIND_LOCALITY_TEST + + res.SetRankingInfo(r.GetRankingInfo()); + return res; +} + +void Ranker::MakeResultHighlight(Result & res) const +{ + using TIter = buffer_vector<strings::UniString, 32>::const_iterator; + using TCombinedIter = CombinedIter<TIter, strings::UniString>; + + TCombinedIter beg(m_params.m_tokens.begin(), m_params.m_tokens.end(), + m_params.m_prefix.empty() ? 0 : &m_params.m_prefix); + TCombinedIter end(m_params.m_tokens.end(), m_params.m_tokens.end(), 0); + auto assignHighlightRange = [&](pair<uint16_t, uint16_t> const & range) + { + res.AddHighlightRange(range); + }; + + SearchStringTokensIntersectionRanges(res.GetString(), beg, end, assignHighlightRange); +} + +void Ranker::GetSuggestion(string const & name, string & suggest) const +{ + // Splits result's name. + search::Delimiters delims; + vector<strings::UniString> tokens; + SplitUniString(NormalizeAndSimplifyString(name), MakeBackInsertFunctor(tokens), delims); + + // Finds tokens that are already present in the input query. + vector<bool> tokensMatched(tokens.size()); + bool prefixMatched = false; + bool fullPrefixMatched = false; + + for (size_t i = 0; i < tokens.size(); ++i) + { + auto const & token = tokens[i]; + + if (find(m_params.m_tokens.begin(), m_params.m_tokens.end(), token) != m_params.m_tokens.end()) + { + tokensMatched[i] = true; + } + else if (StartsWith(token, m_params.m_prefix)) + { + prefixMatched = true; + fullPrefixMatched = token.size() == m_params.m_prefix.size(); + } + } + + // When |name| does not match prefix or when prefix equals to some + // token of the |name| (for example, when user entered "Moscow" + // without space at the end), we should not suggest anything. + if (!prefixMatched || fullPrefixMatched) + return; + + GetStringPrefix(m_params.m_query, suggest); + + // Appends unmatched result's tokens to the suggestion. + for (size_t i = 0; i < tokens.size(); ++i) + { + if (tokensMatched[i]) + continue; + suggest.append(strings::ToUtf8(tokens[i])); + suggest.push_back(' '); + } +} + +void Ranker::SuggestStrings(Results & res) +{ + if (m_params.m_prefix.empty() || !m_params.m_suggestsEnabled) + return; + + string prologue; + GetStringPrefix(m_params.m_query, prologue); + + for (int i = 0; i < m_params.m_categoryLocales.size(); ++i) + MatchForSuggestions(m_params.m_prefix, m_params.m_categoryLocales[i], prologue, res); +} + +void Ranker::MatchForSuggestions(strings::UniString const & token, int8_t locale, + string const & prologue, Results & res) +{ + for (auto const & suggest : m_suggests) + { + strings::UniString const & s = suggest.m_name; + if ((suggest.m_prefixLength <= token.size()) && + (token != s) && // do not push suggestion if it already equals to token + (suggest.m_locale == locale) && // push suggestions only for needed language + StartsWith(s.begin(), s.end(), token.begin(), token.end())) + { + string const utf8Str = strings::ToUtf8(s); + Result r(utf8Str, prologue + utf8Str + " "); + MakeResultHighlight(r); + res.AddResult(move(r)); + } + } +} + +void Ranker::GetBestMatchName(FeatureType const & f, string & name) const +{ + KeywordLangMatcher::ScoreT bestScore; + auto bestNameFinder = [&](int8_t lang, string const & s) -> bool + { + auto const score = m_keywordsScorer.Score(lang, s); + if (bestScore < score) + { + bestScore = score; + name = s; + } + return true; + }; + UNUSED_VALUE(f.ForEachName(bestNameFinder)); +} + +void Ranker::ProcessSuggestions(vector<IndexedValue> & vec, Results & res) const +{ + if (m_params.m_prefix.empty() || !m_params.m_suggestsEnabled) + return; + + int added = 0; + for (auto i = vec.begin(); i != vec.end();) + { + PreResult2 const & r = **i; + + ftypes::Type const type = GetLocalityIndex(r.GetTypes()); + if ((type == ftypes::COUNTRY || type == ftypes::CITY) || r.IsStreet()) + { + string suggest; + GetSuggestion(r.GetName(), suggest); + if (!suggest.empty() && added < MAX_SUGGESTS_COUNT) + { + if (res.AddResult((Result(MakeResult(r), suggest)))) + ++added; + + i = vec.erase(i); + continue; + } + } + ++i; + } +} + void Ranker::FlushResults(Geocoder::Params const & params, Results & res, size_t resCount) { vector<IndexedValue> values; @@ -226,29 +468,28 @@ void Ranker::FlushResults(Geocoder::Params const & params, Results & res, size_t sort(values.rbegin(), values.rend(), my::LessBy(&IndexedValue::GetRank)); - m_processor.ProcessSuggestions(values, res); + ProcessSuggestions(values, res); // Emit feature results. size_t count = res.GetCount(); for (size_t i = 0; i < values.size() && count < resCount; ++i) { - if (m_processor.IsCancelled()) - break; + BailIfCancelled(); LOG(LDEBUG, (values[i])); auto const & preResult2 = *values[i]; - if (res.AddResult(m_processor.MakeResult(preResult2))) + if (res.AddResult(MakeResult(preResult2))) ++count; } } -void Ranker::FlushViewportResults(Geocoder::Params const & params, Results & res) +void Ranker::FlushViewportResults(Geocoder::Params const & geocoderParams, Results & res) { vector<IndexedValue> values; vector<FeatureID> streets; - MakePreResult2(params, values, streets); + MakePreResult2(geocoderParams, values, streets); RemoveDuplicatingLinear(values); if (values.empty()) return; @@ -257,14 +498,20 @@ void Ranker::FlushViewportResults(Geocoder::Params const & params, Results & res for (size_t i = 0; i < values.size(); ++i) { - if (m_processor.IsCancelled()) - break; + BailIfCancelled(); res.AddResultNoChecks( (*(values[i])) - .GenerateFinalResult(m_processor.m_infoGetter, &m_processor.m_categories, - &m_processor.m_prefferedTypes, m_processor.m_currentLocaleCode, + .GenerateFinalResult(m_infoGetter, &m_categories, &m_params.m_preferredTypes, + m_params.m_currentLocaleCode, nullptr /* Viewport results don't need calculated address */)); } } + +void Ranker::ClearCaches() +{ +#ifdef FIND_LOCALITY_TEST + m_locality.ClearCache(); +#endif // FIND_LOCALITY_TEST +} } // namespace search diff --git a/search/ranker.hpp b/search/ranker.hpp index 84b760acf0..b8ff40ea7c 100644 --- a/search/ranker.hpp +++ b/search/ranker.hpp @@ -1,27 +1,86 @@ #pragma once +#include "search/cancel_exception.hpp" #include "search/geocoder.hpp" #include "search/intermediate_result.hpp" +#include "search/keyword_lang_matcher.hpp" #include "search/mode.hpp" +#include "search/reverse_geocoder.hpp" +#include "search/suggest.hpp" +#include "indexer/categories_holder.hpp" #include "indexer/feature_decl.hpp" +#include "geometry/point2d.hpp" +#include "geometry/rect2d.hpp" + +#include "base/string_utils.hpp" + +#include "std/set.hpp" +#include "std/string.hpp" +#include "std/utility.hpp" #include "std/vector.hpp" +#define FIND_LOCALITY_TEST + +#ifdef FIND_LOCALITY_TEST +#include "search/locality_finder.hpp" +#endif // FIND_LOCALITY_TEST + +class CategoriesHolder; +class Index; + +namespace storage +{ +class CountryInfoGetter; +} // namespace storage + namespace search { class PreResult2Maker; -class Processor; class Ranker { public: - Ranker(PreRanker & preRanker, Processor & processor) - : m_viewportSearch(false), m_preRanker(preRanker), m_processor(processor) + struct Params + { + using TLocales = buffer_vector<int8_t, 3>; + + bool m_viewportSearch = false; + + int8_t m_currentLocaleCode = CategoriesHolder::kEnglishCode; + m2::RectD m_viewport; + m2::PointD m_position; + string m_pivotRegion; + set<uint32_t> m_preferredTypes; + bool m_suggestsEnabled = false; + + string m_query; + buffer_vector<strings::UniString, 32> m_tokens; + // Prefix of the last token in the query. + // We need it here to make suggestions. + strings::UniString m_prefix; + + TLocales m_categoryLocales; + }; + + Ranker(PreRanker & preRanker, Index const & index, storage::CountryInfoGetter const & infoGetter, + CategoriesHolder const & categories, vector<Suggest> const & suggests, + my::Cancellable const & cancellable) + : m_reverseGeocoder(index) + , m_preRanker(preRanker) + , m_cancellable(cancellable) +#ifdef FIND_LOCALITY_TEST + , m_locality(&index) +#endif // FIND_LOCALITY_TEST + , m_index(index) + , m_infoGetter(infoGetter) + , m_categories(categories) + , m_suggests(suggests) { } - inline void Init(bool viewportSearch) { m_viewportSearch = viewportSearch; } + inline void Init(bool viewportSearch) { m_params.m_viewportSearch = viewportSearch; } bool IsResultExists(PreResult2 const & p, vector<IndexedValue> const & values); @@ -29,15 +88,65 @@ public: vector<FeatureID> & streets); Result MakeResult(PreResult2 const & r) const; + void MakeResultHighlight(Result & res) const; + + void GetSuggestion(string const & name, string & suggest) const; + void SuggestStrings(Results & res); + void MatchForSuggestions(strings::UniString const & token, int8_t locale, string const & prolog, + Results & res); + void GetBestMatchName(FeatureType const & f, string & name) const; + void ProcessSuggestions(vector<IndexedValue> & vec, Results & res) const; + + void FlushResults(Geocoder::Params const & geocoderParams, Results & res, size_t resCount); + void FlushViewportResults(Geocoder::Params const & geocoderParams, Results & res); + + void SetParams(Params const & params) { m_params = params; } - void FlushResults(Geocoder::Params const & params, Results & res, size_t resCount); - void FlushViewportResults(Geocoder::Params const & params, Results & res); + void ClearCaches(); + +#ifdef FIND_LOCALITY_TEST + inline void SetLocalityFinderLanguage(int8_t code) { m_locality.SetLanguage(code); } +#endif // FIND_LOCALITY_TEST + + inline void SetLanguage(pair<int, int> const & ind, int8_t lang) + { + m_keywordsScorer.SetLanguage(ind, lang); + } + + inline int8_t GetLanguage(pair<int, int> const & ind) const + { + return m_keywordsScorer.GetLanguage(ind); + } + + inline void SetLanguages(vector<vector<int8_t>> const & languagePriorities) + { + m_keywordsScorer.SetLanguages(languagePriorities); + } + + inline void SetKeywords(KeywordMatcher::StringT const * keywords, size_t count, + KeywordMatcher::StringT const & prefix) + { + m_keywordsScorer.SetKeywords(keywords, count, prefix); + } + + inline void BailIfCancelled() { ::search::BailIfCancelled(m_cancellable); } private: - bool m_viewportSearch; + friend class PreResult2Maker; + + Params m_params; + ReverseGeocoder const m_reverseGeocoder; PreRanker & m_preRanker; + my::Cancellable const & m_cancellable; + KeywordLangMatcher m_keywordsScorer; + +#ifdef FIND_LOCALITY_TEST + mutable LocalityFinder m_locality; +#endif // FIND_LOCALITY_TEST - // todo(@m) Remove. - Processor & m_processor; + Index const & m_index; + storage::CountryInfoGetter const & m_infoGetter; + CategoriesHolder const & m_categories; + vector<Suggest> const & m_suggests; }; } // namespace search diff --git a/search/search.pro b/search/search.pro index 6be1bd7a85..eec3a48784 100644 --- a/search/search.pro +++ b/search/search.pro @@ -64,6 +64,7 @@ HEADERS += \ suggest.hpp \ token_slice.hpp \ types_skipper.hpp \ + utils.hpp \ SOURCES += \ approximate_string_match.cpp \ |