Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/search
diff options
context:
space:
mode:
authorMaxim Pimenov <m@maps.me>2016-06-08 20:18:45 +0300
committerMaxim Pimenov <m@maps.me>2016-06-21 15:12:34 +0300
commit0f3a21406dcfa4b7edc427246fed299b0276c178 (patch)
treeb7ce14f699a54fa4fc562d133c97e5e72752a629 /search
parent0a8760da49f39a487a7ee961dde3e9abd57a5b82 (diff)
[search] Separated out ranker.
Diffstat (limited to 'search')
-rw-r--r--search/geocoder.cpp1
-rw-r--r--search/geocoder.hpp5
-rw-r--r--search/intermediate_result.cpp3
-rw-r--r--search/intermediate_result.hpp42
-rw-r--r--search/pre_ranker.cpp18
-rw-r--r--search/pre_ranker.hpp4
-rw-r--r--search/processor.cpp343
-rw-r--r--search/processor.hpp48
-rw-r--r--search/ranker.cpp270
-rw-r--r--search/ranker.hpp45
-rw-r--r--search/search.pro2
11 files changed, 410 insertions, 371 deletions
diff --git a/search/geocoder.cpp b/search/geocoder.cpp
index 5db6ec2b62..5ae222e507 100644
--- a/search/geocoder.cpp
+++ b/search/geocoder.cpp
@@ -6,6 +6,7 @@
#include "search/features_layer_matcher.hpp"
#include "search/house_numbers_matcher.hpp"
#include "search/locality_scorer.hpp"
+#include "search/pre_ranker.hpp"
#include "search/processor.hpp"
#include "search/retrieval.hpp"
#include "search/token_slice.hpp"
diff --git a/search/geocoder.hpp b/search/geocoder.hpp
index db8e905b98..0e6dd0786f 100644
--- a/search/geocoder.hpp
+++ b/search/geocoder.hpp
@@ -36,11 +36,6 @@
class MwmInfo;
class MwmValue;
-namespace coding
-{
-class CompressedBitVector;
-}
-
namespace storage
{
class CountryInfoGetter;
diff --git a/search/intermediate_result.cpp b/search/intermediate_result.cpp
index d07cb514a0..dc17072036 100644
--- a/search/intermediate_result.cpp
+++ b/search/intermediate_result.cpp
@@ -58,8 +58,6 @@ void ProcessMetadata(FeatureType const & ft, Result::Metadata & meta)
meta.m_isInitialized = true;
}
-namespace impl
-{
PreResult1::PreResult1(FeatureID const & fID, PreRankingInfo const & info) : m_id(fID), m_info(info)
{
ASSERT(m_id.IsValid(), ());
@@ -302,5 +300,4 @@ void PreResult2::RegionInfo::GetRegion(storage::CountryInfoGetter const & infoGe
else
infoGetter.GetRegionInfo(m_point, info);
}
-} // namespace search::impl
} // namespace search
diff --git a/search/intermediate_result.hpp b/search/intermediate_result.hpp
index 259abfbb67..76bb97ff43 100644
--- a/search/intermediate_result.hpp
+++ b/search/intermediate_result.hpp
@@ -20,8 +20,6 @@ namespace search
{
class ReverseGeocoder;
-namespace impl
-{
/// First pass results class. Objects are creating during search in trie.
/// Works fast without feature loading and provide ranking.
class PreResult1
@@ -153,7 +151,45 @@ inline string DebugPrint(PreResult2 const & t)
{
return t.DebugPrint();
}
-} // namespace impl
void ProcessMetadata(FeatureType const & ft, Result::Metadata & meta);
+
+class IndexedValue
+{
+ /// @todo Do not use shared_ptr for optimization issues.
+ /// Need to rewrite std::unique algorithm.
+ unique_ptr<PreResult2> m_value;
+
+ double m_rank;
+ double m_distanceToPivot;
+
+ friend string DebugPrint(IndexedValue const & value)
+ {
+ ostringstream os;
+ os << "IndexedValue [";
+ if (value.m_value)
+ os << DebugPrint(*value.m_value);
+ os << "]";
+ return os.str();
+ }
+
+public:
+ explicit IndexedValue(unique_ptr<PreResult2> value)
+ : m_value(move(value)), m_rank(0.0), m_distanceToPivot(numeric_limits<double>::max())
+ {
+ if (!m_value)
+ return;
+
+ auto const & info = m_value->GetRankingInfo();
+ m_rank = info.GetLinearModelRank();
+ m_distanceToPivot = info.m_distanceToPivot;
+ }
+
+ PreResult2 const & operator*() const { return *m_value; }
+
+ inline double GetRank() const { return m_rank; }
+
+ inline double GetDistanceToPivot() const { return m_distanceToPivot; }
+};
+
} // namespace search
diff --git a/search/pre_ranker.cpp b/search/pre_ranker.cpp
index 54e6f628fc..b5782fbbfb 100644
--- a/search/pre_ranker.cpp
+++ b/search/pre_ranker.cpp
@@ -14,7 +14,7 @@ namespace
{
struct LessFeatureID
{
- using TValue = impl::PreResult1;
+ using TValue = PreResult1;
inline bool operator()(TValue const & lhs, TValue const & rhs) const
{
@@ -28,7 +28,7 @@ struct LessFeatureID
// 3. Index of the first matched token from the query (increasing).
struct ComparePreResult1
{
- bool operator()(impl::PreResult1 const & lhs, impl::PreResult1 const & rhs) const
+ bool operator()(PreResult1 const & lhs, PreResult1 const & rhs) const
{
if (lhs.GetId() != rhs.GetId())
return lhs.GetId() < rhs.GetId();
@@ -44,19 +44,18 @@ struct ComparePreResult1
PreRanker::PreRanker(size_t limit) : m_limit(limit) {}
-void PreRanker::Add(impl::PreResult1 const & result) { m_results.push_back(result); }
+void PreRanker::Add(PreResult1 const & result) { m_results.push_back(result); }
void PreRanker::Filter(bool viewportSearch)
{
- using TSet = set<impl::PreResult1, LessFeatureID>;
+ using TSet = set<PreResult1, LessFeatureID>;
TSet theSet;
sort(m_results.begin(), m_results.end(), ComparePreResult1());
- m_results.erase(
- unique(m_results.begin(), m_results.end(), my::EqualsBy(&impl::PreResult1::GetId)),
- m_results.end());
+ m_results.erase(unique(m_results.begin(), m_results.end(), my::EqualsBy(&PreResult1::GetId)),
+ m_results.end());
- sort(m_results.begin(), m_results.end(), &impl::PreResult1::LessDistance);
+ sort(m_results.begin(), m_results.end(), &PreResult1::LessDistance);
if (m_limit != 0 && m_results.size() > m_limit)
{
@@ -96,8 +95,7 @@ void PreRanker::Filter(bool viewportSearch)
if (!viewportSearch)
{
size_t n = min(m_results.size(), m_limit);
- nth_element(m_results.begin(), m_results.begin() + n, m_results.end(),
- &impl::PreResult1::LessRank);
+ nth_element(m_results.begin(), m_results.begin() + n, m_results.end(), &PreResult1::LessRank);
theSet.insert(m_results.begin(), m_results.begin() + n);
}
diff --git a/search/pre_ranker.hpp b/search/pre_ranker.hpp
index 3e7f25f591..2bb61f6901 100644
--- a/search/pre_ranker.hpp
+++ b/search/pre_ranker.hpp
@@ -17,7 +17,7 @@ class PreRanker
public:
explicit PreRanker(size_t limit);
- void Add(impl::PreResult1 const & result);
+ void Add(PreResult1 const & result);
template <typename... TArgs>
void Emplace(TArgs &&... args)
@@ -46,7 +46,7 @@ public:
}
private:
- vector<impl::PreResult1> m_results;
+ vector<PreResult1> m_results;
size_t const m_limit;
DISALLOW_COPY_AND_MOVE(PreRanker);
diff --git a/search/processor.cpp b/search/processor.cpp
index d51bc74261..cfcc509822 100644
--- a/search/processor.cpp
+++ b/search/processor.cpp
@@ -102,62 +102,6 @@ ftypes::Type GetLocalityIndex(feature::TypesHolder const & types)
}
}
-class IndexedValue
-{
- /// @todo Do not use shared_ptr for optimization issues.
- /// Need to rewrite std::unique algorithm.
- unique_ptr<impl::PreResult2> m_value;
-
- double m_rank;
- double m_distanceToPivot;
-
- friend string DebugPrint(IndexedValue const & value)
- {
- ostringstream os;
- os << "IndexedValue [";
- if (value.m_value)
- os << impl::DebugPrint(*value.m_value);
- os << "]";
- return os.str();
- }
-
-public:
- explicit IndexedValue(unique_ptr<impl::PreResult2> value)
- : m_value(move(value)), m_rank(0.0), m_distanceToPivot(numeric_limits<double>::max())
- {
- if (!m_value)
- return;
-
- auto const & info = m_value->GetRankingInfo();
- m_rank = info.GetLinearModelRank();
- m_distanceToPivot = info.m_distanceToPivot;
- }
-
- impl::PreResult2 const & operator*() const { return *m_value; }
-
- inline double GetRank() const { return m_rank; }
-
- inline double GetDistanceToPivot() const { return m_distanceToPivot; }
-};
-
-void RemoveDuplicatingLinear(vector<IndexedValue> & indV)
-{
- impl::PreResult2::LessLinearTypesF lessCmp;
- impl::PreResult2::EqualLinearTypesF equalCmp;
-
- sort(indV.begin(), indV.end(), [&lessCmp](IndexedValue const & lhs, IndexedValue const & rhs)
- {
- return lessCmp(*lhs, *rhs);
- });
-
- indV.erase(unique(indV.begin(), indV.end(),
- [&equalCmp](IndexedValue const & lhs, IndexedValue const & rhs)
- {
- return equalCmp(*lhs, *rhs);
- }),
- indV.end());
-}
-
m2::RectD NormalizeViewport(m2::RectD viewport)
{
m2::RectD minViewport = MercatorBounds::RectByCenterXYAndSizeInMeters(
@@ -176,23 +120,6 @@ m2::RectD GetRectAroundPosition(m2::PointD const & position)
return MercatorBounds::RectByCenterXYAndSizeInMeters(position, kMaxPositionRadiusM);
}
-template <typename TSlice>
-void UpdateNameScore(string const & name, TSlice const & slice, NameScore & bestScore)
-{
- auto const score = GetNameScore(name, slice);
- if (score > bestScore)
- bestScore = score;
-}
-
-template <typename TSlice>
-void UpdateNameScore(vector<strings::UniString> const & tokens, TSlice const & slice,
- NameScore & bestScore)
-{
- auto const score = GetNameScore(tokens, slice);
- if (score > bestScore)
- bestScore = score;
-}
-
inline bool IsHashtagged(strings::UniString const & s) { return !s.empty() && s[0] == '#'; }
inline strings::UniString RemoveHashtag(strings::UniString const & s)
@@ -224,8 +151,6 @@ Processor::Processor(Index & index, CategoriesHolder const & categories,
, m_mode(Mode::Everywhere)
, m_worldSearch(true)
, m_suggestsEnabled(true)
- , m_viewportSearch(false)
- , m_keepHouseNumberInQuery(true)
, m_preRanker(kPreResultsCount)
, m_geocoder(index, infoGetter, static_cast<my::Cancellable const &>(*this))
, m_reverseGeocoder(index)
@@ -241,6 +166,8 @@ Processor::Processor(Index & index, CategoriesHolder const & categories,
m_keywordsScorer.SetLanguages(langPriorities);
SetPreferredLocale("en");
+
+ m_ranker = make_unique<Ranker>(m_preRanker, *this);
}
void Processor::Init(bool viewportSearch)
@@ -248,7 +175,7 @@ void Processor::Init(bool viewportSearch)
m_tokens.clear();
m_prefix.clear();
m_preRanker.Clear();
- m_viewportSearch = viewportSearch;
+ m_ranker->Init(viewportSearch);
}
void Processor::SetViewport(m2::RectD const & viewport, bool forceUpdate)
@@ -347,7 +274,7 @@ void Processor::SetQuery(string const & query)
// get preffered types to show in results
m_prefferedTypes.clear();
- ForEachCategoryTypes(QuerySliceOnRawStrings<decltype(m_tokens)>(m_tokens, m_prefix),
+ ForEachCategoryType(QuerySliceOnRawStrings<decltype(m_tokens)>(m_tokens, m_prefix),
[&](size_t, uint32_t t)
{
m_prefferedTypes.insert(t);
@@ -450,8 +377,8 @@ int Processor::GetCategoryLocales(int8_t(&arr)[3]) const
return count;
}
-template <class ToDo>
-void Processor::ForEachCategoryTypes(StringSliceBase const & slice, ToDo toDo) const
+void Processor::ForEachCategoryType(StringSliceBase const & slice,
+ function<void(size_t, uint32_t)> const & fn) const
{
int8_t arrLocales[3];
int const localesCount = GetCategoryLocales(arrLocales);
@@ -460,14 +387,14 @@ void Processor::ForEachCategoryTypes(StringSliceBase const & slice, ToDo toDo) c
{
auto token = RemoveHashtag(slice.Get(i));
for (int j = 0; j < localesCount; ++j)
- m_categories.ForEachTypeByName(arrLocales[j], token, bind<void>(ref(toDo), i, _1));
- ProcessEmojiIfNeeded(token, i, toDo);
+ m_categories.ForEachTypeByName(arrLocales[j], token, bind<void>(fn, i, _1));
+ ProcessEmojiIfNeeded(token, i, fn);
}
}
-template <class ToDo>
+// template <class ToDo>
void Processor::ProcessEmojiIfNeeded(strings::UniString const & token, size_t ind,
- ToDo & toDo) const
+ 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.
@@ -476,7 +403,7 @@ void Processor::ProcessEmojiIfNeeded(strings::UniString const & token, size_t in
static int8_t const enLocaleCode = CategoriesHolder::MapLocaleToInteger("en");
m_categories.ForEachTypeByName(enLocaleCode, strings::UniString(1, token[0]),
- bind<void>(ref(toDo), ind, _1));
+ bind<void>(fn, ind, _1));
}
}
@@ -495,7 +422,7 @@ void Processor::Search(Results & results, size_t limit)
m_geocoder.GoEverywhere(m_preRanker);
- FlushResults(params, results, limit);
+ m_ranker->FlushResults(params, results, limit);
}
void Processor::SearchViewportPoints(Results & results)
@@ -509,7 +436,7 @@ void Processor::SearchViewportPoints(Results & results)
m_geocoder.GoInViewport(m_preRanker);
- FlushViewportResults(params, results);
+ m_ranker->FlushViewportResults(params, results);
}
void Processor::SearchCoordinates(Results & res) const
@@ -518,234 +445,7 @@ void Processor::SearchCoordinates(Results & res) const
if (MatchLatLonDegree(m_query, lat, lon))
{
ASSERT_EQUAL(res.GetCount(), 0, ());
- res.AddResultNoChecks(MakeResult(impl::PreResult2(lat, lon)));
- }
-}
-
-namespace
-{
-bool IsResultExists(impl::PreResult2 const & p, vector<IndexedValue> const & indV)
-{
- impl::PreResult2::StrictEqualF equalCmp(p);
- // Do not insert duplicating results.
- return indV.end() != find_if(indV.begin(), indV.end(), [&equalCmp](IndexedValue const & iv)
- {
- return equalCmp(*iv);
- });
-}
-} // namespace
-
-namespace impl
-{
-class PreResult2Maker
-{
- Processor & m_processor;
- Geocoder::Params const & m_params;
-
- unique_ptr<Index::FeaturesLoaderGuard> m_pFV;
-
- // For the best performance, incoming id's should be sorted by id.first (mwm file id).
- void LoadFeature(FeatureID const & id, FeatureType & f, m2::PointD & center, string & name,
- 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->GetFeatureByIndex(id.m_index, f);
- f.SetID(id);
-
- center = feature::GetCenter(f);
-
- m_processor.GetBestMatchName(f, name);
-
- // country (region) name is a file name if feature isn't from World.mwm
- if (m_pFV->IsWorld())
- country.clear();
- else
- country = m_pFV->GetCountryFileName();
- }
-
- void InitRankingInfo(FeatureType const & ft, m2::PointD const & center,
- impl::PreResult1 const & res, search::RankingInfo & info)
- {
- auto const & preInfo = res.GetInfo();
-
- auto const & pivot = m_params.m_accuratePivotCenter;
-
- info.m_distanceToPivot = MercatorBounds::DistanceOnEarth(center, pivot);
- info.m_rank = preInfo.m_rank;
- info.m_searchType = preInfo.m_searchType;
- info.m_nameScore = NAME_SCORE_ZERO;
-
- TokenSlice slice(m_params, preInfo.m_startToken, preInfo.m_endToken);
- TokenSliceNoCategories sliceNoCategories(m_params, preInfo.m_startToken, preInfo.m_endToken);
-
- for (auto const & lang : m_params.m_langs)
- {
- string name;
- if (!ft.GetName(lang, name))
- continue;
- vector<strings::UniString> tokens;
- SplitUniString(NormalizeAndSimplifyString(name), MakeBackInsertFunctor(tokens), Delimiters());
-
- UpdateNameScore(tokens, slice, info.m_nameScore);
- UpdateNameScore(tokens, sliceNoCategories, info.m_nameScore);
- }
-
- if (info.m_searchType == SearchModel::SEARCH_TYPE_BUILDING)
- UpdateNameScore(ft.GetHouseNumber(), sliceNoCategories, info.m_nameScore);
-
- feature::TypesHolder holder(ft);
- vector<pair<size_t, size_t>> matched(slice.Size());
- m_processor.ForEachCategoryTypes(QuerySlice(slice), [&](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)
- {
- return m.first != 0;
- });
- info.m_falseCats = all_of(matched.begin(), matched.end(), [](pair<size_t, size_t> const & m)
- {
- return m.first == 0 && m.second != 0;
- });
- }
-
- uint8_t NormalizeRank(uint8_t rank, SearchModel::SearchType type, m2::PointD const & center,
- string const & country)
- {
- switch (type)
- {
- case SearchModel::SEARCH_TYPE_VILLAGE: return rank /= 1.5;
- case SearchModel::SEARCH_TYPE_CITY:
- {
- if (m_processor.GetViewport(Processor::CURRENT_V).IsPointInside(center))
- return rank * 2;
-
- storage::CountryInfo info;
- if (country.empty())
- m_processor.m_infoGetter.GetRegionInfo(center, info);
- else
- m_processor.m_infoGetter.GetRegionInfo(country, info);
- if (info.IsNotEmpty() && info.m_name == m_processor.GetPivotRegion())
- return rank *= 1.7;
- }
- case SearchModel::SEARCH_TYPE_COUNTRY:
- return rank /= 1.5;
-
- // For all other search types, rank should be zero for now.
- default: return 0;
- }
- }
-
-public:
- explicit PreResult2Maker(Processor & q, Geocoder::Params const & params)
- : m_processor(q), m_params(params)
- {
- }
-
- unique_ptr<impl::PreResult2> operator()(impl::PreResult1 const & res1)
- {
- FeatureType ft;
- m2::PointD center;
- string name;
- string country;
-
- LoadFeature(res1.GetId(), ft, center, name, country);
-
- auto res2 = make_unique<impl::PreResult2>(ft, &res1, center,
- m_processor.GetPosition() /* pivot */, name, country);
-
- search::RankingInfo info;
- InitRankingInfo(ft, center, res1, info);
- info.m_rank = NormalizeRank(info.m_rank, info.m_searchType, center, country);
- res2->SetRankingInfo(move(info));
-
- return res2;
- }
-};
-} // namespace impl
-
-template <class T>
-void Processor::MakePreResult2(Geocoder::Params const & params, vector<T> & cont,
- vector<FeatureID> & streets)
-{
- m_preRanker.Filter(m_viewportSearch);
-
- // Makes PreResult2 vector.
- impl::PreResult2Maker maker(*this, params);
- m_preRanker.ForEach(
- [&](impl::PreResult1 const & r)
- {
- auto p = maker(r);
- if (!p)
- return;
-
- if (params.m_mode == Mode::Viewport && !params.m_pivot.IsPointInside(p->GetCenter()))
- return;
-
- if (p->IsStreet())
- streets.push_back(p->GetID());
-
- if (!IsResultExists(*p, cont))
- cont.push_back(IndexedValue(move(p)));
- });
-}
-
-void Processor::FlushResults(Geocoder::Params const & params, Results & res, size_t resCount)
-{
- vector<IndexedValue> indV;
- vector<FeatureID> streets;
-
- MakePreResult2(params, indV, streets);
- RemoveDuplicatingLinear(indV);
- if (indV.empty())
- return;
-
- sort(indV.rbegin(), indV.rend(), my::LessBy(&IndexedValue::GetRank));
-
- ProcessSuggestions(indV, res);
-
- // Emit feature results.
- size_t count = res.GetCount();
- for (size_t i = 0; i < indV.size() && count < resCount; ++i)
- {
- if (IsCancelled())
- break;
-
- LOG(LDEBUG, (indV[i]));
-
- auto const & preResult2 = *indV[i];
- if (res.AddResult(MakeResult(preResult2)))
- ++count;
- }
-}
-
-void Processor::FlushViewportResults(Geocoder::Params const & params, Results & res)
-{
- vector<IndexedValue> indV;
- vector<FeatureID> streets;
-
- MakePreResult2(params, indV, streets);
- RemoveDuplicatingLinear(indV);
- if (indV.empty())
- return;
-
- sort(indV.begin(), indV.end(), my::LessBy(&IndexedValue::GetDistanceToPivot));
-
- for (size_t i = 0; i < indV.size(); ++i)
- {
- if (IsCancelled())
- break;
-
- res.AddResultNoChecks(
- (*(indV[i]))
- .GenerateFinalResult(m_infoGetter, &m_categories, &m_prefferedTypes,
- m_currentLocaleCode,
- nullptr /* Viewport results don't need calculated address */));
+ res.AddResultNoChecks(MakeResult(PreResult2(lat, lon)));
}
}
@@ -815,8 +515,7 @@ void Processor::GetSuggestion(string const & name, string & suggest) const
}
}
-template <class T>
-void Processor::ProcessSuggestions(vector<T> & vec, Results & res) const
+void Processor::ProcessSuggestions(vector<IndexedValue> & vec, Results & res) const
{
if (m_prefix.empty() || !m_suggestsEnabled)
return;
@@ -824,7 +523,7 @@ void Processor::ProcessSuggestions(vector<T> & vec, Results & res) const
int added = 0;
for (auto i = vec.begin(); i != vec.end();)
{
- impl::PreResult2 const & r = **i;
+ PreResult2 const & r = **i;
ftypes::Type const type = GetLocalityIndex(r.GetTypes());
if ((type == ftypes::COUNTRY || type == ftypes::CITY) || r.IsStreet())
@@ -844,8 +543,6 @@ void Processor::ProcessSuggestions(vector<T> & vec, Results & res) const
}
}
-namespace impl
-{
class BestNameFinder
{
KeywordLangMatcher::ScoreT m_score;
@@ -869,11 +566,10 @@ public:
return true;
}
};
-} // namespace impl
void Processor::GetBestMatchName(FeatureType const & f, string & name) const
{
- impl::BestNameFinder finder(name, m_keywordsScorer);
+ BestNameFinder finder(name, m_keywordsScorer);
UNUSED_VALUE(f.ForEachName(finder));
}
@@ -926,12 +622,11 @@ public:
void operator()(pair<uint16_t, uint16_t> const & range) { m_res.AddHighlightRange(range); }
};
-Result Processor::MakeResult(impl::PreResult2 const & r) const
+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)
{
@@ -1144,7 +839,7 @@ void Processor::InitParams(QueryParams & params)
}
}
};
- ForEachCategoryTypes(QuerySliceOnRawStrings<decltype(m_tokens)>(m_tokens, m_prefix), addSyms);
+ ForEachCategoryType(QuerySliceOnRawStrings<decltype(m_tokens)>(m_tokens, m_prefix), addSyms);
for (auto & tokens : params.m_tokens)
{
diff --git a/search/processor.hpp b/search/processor.hpp
index a568e43991..1cdadb22f1 100644
--- a/search/processor.hpp
+++ b/search/processor.hpp
@@ -3,6 +3,7 @@
#include "search/keyword_lang_matcher.hpp"
#include "search/mode.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"
@@ -21,9 +22,11 @@
#include "base/limited_priority_queue.hpp"
#include "base/string_utils.hpp"
+#include "std/function.hpp"
#include "std/map.hpp"
#include "std/string.hpp"
#include "std/unordered_set.hpp"
+#include "std/unique_ptr.hpp"
#include "std/vector.hpp"
#define FIND_LOCALITY_TEST
@@ -53,15 +56,14 @@ struct QueryParams;
class ReverseGeocoder;
class Geocoder;
+class Ranker;
+// todo(@m) Merge with Ranker.
+class PreResult2Maker;
-namespace impl
-{
class FeatureLoader;
class BestNameFinder;
-class PreResult2Maker;
class DoFindLocality;
class HouseCompFactory;
-}
class Processor : public my::Cancellable
{
@@ -128,17 +130,22 @@ protected:
friend string DebugPrint(ViewportID viewportId);
- friend class impl::FeatureLoader;
- friend class impl::BestNameFinder;
- friend class impl::PreResult2Maker;
- friend class impl::DoFindLocality;
- friend class impl::HouseCompFactory;
+ friend class FeatureLoader;
+ friend class BestNameFinder;
+ friend class DoFindLocality;
+ friend class HouseCompFactory;
+ friend class Ranker;
+ friend class PreResult2Maker;
int GetCategoryLocales(int8_t(&arr)[3]) const;
- template <class ToDo>
- void ForEachCategoryTypes(StringSliceBase const & slice, ToDo toDo) const;
- template <class ToDo>
- void ProcessEmojiIfNeeded(strings::UniString const & token, size_t ind, ToDo & toDo) 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 ind,
+ 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>>;
@@ -150,17 +157,10 @@ protected:
void SetViewportByIndex(m2::RectD const & viewport, size_t idx, bool forceUpdate);
void ClearCache(size_t ind);
- template <class T>
- void MakePreResult2(Geocoder::Params const & params, vector<T> & cont,
- vector<FeatureID> & streets);
-
- void FlushResults(Geocoder::Params const & params, Results & res, size_t resCount);
- void FlushViewportResults(Geocoder::Params const & params, Results & res);
-
void RemoveStringPrefix(string const & str, string & res) const;
void GetSuggestion(string const & name, string & suggest) const;
- template <class T>
- void ProcessSuggestions(vector<T> & vec, Results & res) const;
+
+ void ProcessSuggestions(vector<IndexedValue> & vec, Results & res) const;
void SuggestStrings(Results & res);
void MatchForSuggestionsImpl(strings::UniString const & token, int8_t locale,
@@ -168,7 +168,7 @@ protected:
void GetBestMatchName(FeatureType const & f, string & name) const;
- Result MakeResult(impl::PreResult2 const & r) const;
+ Result MakeResult(PreResult2 const & r) const;
void MakeResultHighlight(Result & res) const;
Index & m_index;
@@ -208,9 +208,9 @@ protected:
protected:
bool m_viewportSearch;
- bool m_keepHouseNumberInQuery;
PreRanker m_preRanker;
+ unique_ptr<Ranker> m_ranker;
Geocoder m_geocoder;
ReverseGeocoder const m_reverseGeocoder;
};
diff --git a/search/ranker.cpp b/search/ranker.cpp
new file mode 100644
index 0000000000..801c373dbf
--- /dev/null
+++ b/search/ranker.cpp
@@ -0,0 +1,270 @@
+#include "search/ranker.hpp"
+#include "search/processor.hpp"
+#include "search/token_slice.hpp"
+
+#include "indexer/feature_algo.hpp"
+
+#include "base/logging.hpp"
+
+#include "std/algorithm.hpp"
+
+namespace search
+{
+namespace
+{
+template <typename TSlice>
+void UpdateNameScore(string const & name, TSlice const & slice, NameScore & bestScore)
+{
+ auto const score = GetNameScore(name, slice);
+ if (score > bestScore)
+ bestScore = score;
+}
+
+template <typename TSlice>
+void UpdateNameScore(vector<strings::UniString> const & tokens, TSlice const & slice,
+ NameScore & bestScore)
+{
+ auto const score = GetNameScore(tokens, slice);
+ if (score > bestScore)
+ bestScore = score;
+}
+
+void RemoveDuplicatingLinear(vector<IndexedValue> & indV)
+{
+ PreResult2::LessLinearTypesF lessCmp;
+ PreResult2::EqualLinearTypesF equalCmp;
+
+ sort(indV.begin(), indV.end(), [&lessCmp](IndexedValue const & lhs, IndexedValue const & rhs)
+ {
+ return lessCmp(*lhs, *rhs);
+ });
+
+ indV.erase(unique(indV.begin(), indV.end(),
+ [&equalCmp](IndexedValue const & lhs, IndexedValue const & rhs)
+ {
+ return equalCmp(*lhs, *rhs);
+ }),
+ indV.end());
+}
+} // namespace
+
+class PreResult2Maker
+{
+ Processor & m_processor;
+ Geocoder::Params const & m_params;
+
+ unique_ptr<Index::FeaturesLoaderGuard> m_pFV;
+
+ // For the best performance, incoming id's should be sorted by id.first (mwm file id).
+ void LoadFeature(FeatureID const & id, FeatureType & f, m2::PointD & center, string & name,
+ 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->GetFeatureByIndex(id.m_index, f);
+ f.SetID(id);
+
+ center = feature::GetCenter(f);
+
+ m_processor.GetBestMatchName(f, name);
+
+ // country (region) name is a file name if feature isn't from World.mwm
+ if (m_pFV->IsWorld())
+ country.clear();
+ else
+ country = m_pFV->GetCountryFileName();
+ }
+
+ void InitRankingInfo(FeatureType const & ft, m2::PointD const & center, PreResult1 const & res,
+ search::RankingInfo & info)
+ {
+ auto const & preInfo = res.GetInfo();
+
+ auto const & pivot = m_params.m_accuratePivotCenter;
+
+ info.m_distanceToPivot = MercatorBounds::DistanceOnEarth(center, pivot);
+ info.m_rank = preInfo.m_rank;
+ info.m_searchType = preInfo.m_searchType;
+ info.m_nameScore = NAME_SCORE_ZERO;
+
+ TokenSlice slice(m_params, preInfo.m_startToken, preInfo.m_endToken);
+ TokenSliceNoCategories sliceNoCategories(m_params, preInfo.m_startToken, preInfo.m_endToken);
+
+ for (auto const & lang : m_params.m_langs)
+ {
+ string name;
+ if (!ft.GetName(lang, name))
+ continue;
+ vector<strings::UniString> tokens;
+ SplitUniString(NormalizeAndSimplifyString(name), MakeBackInsertFunctor(tokens), Delimiters());
+
+ UpdateNameScore(tokens, slice, info.m_nameScore);
+ UpdateNameScore(tokens, sliceNoCategories, info.m_nameScore);
+ }
+
+ if (info.m_searchType == SearchModel::SEARCH_TYPE_BUILDING)
+ UpdateNameScore(ft.GetHouseNumber(), sliceNoCategories, info.m_nameScore);
+
+ 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;
+ });
+
+ info.m_pureCats = all_of(matched.begin(), matched.end(), [](pair<size_t, size_t> const & m)
+ {
+ return m.first != 0;
+ });
+ info.m_falseCats = all_of(matched.begin(), matched.end(), [](pair<size_t, size_t> const & m)
+ {
+ return m.first == 0 && m.second != 0;
+ });
+ }
+
+ uint8_t NormalizeRank(uint8_t rank, SearchModel::SearchType type, m2::PointD const & center,
+ string const & country)
+ {
+ switch (type)
+ {
+ case SearchModel::SEARCH_TYPE_VILLAGE: return rank /= 1.5;
+ case SearchModel::SEARCH_TYPE_CITY:
+ {
+ if (m_processor.GetViewport(Processor::CURRENT_V).IsPointInside(center))
+ return rank * 2;
+
+ storage::CountryInfo info;
+ if (country.empty())
+ m_processor.m_infoGetter.GetRegionInfo(center, info);
+ else
+ m_processor.m_infoGetter.GetRegionInfo(country, info);
+ if (info.IsNotEmpty() && info.m_name == m_processor.GetPivotRegion())
+ return rank *= 1.7;
+ }
+ case SearchModel::SEARCH_TYPE_COUNTRY:
+ return rank /= 1.5;
+
+ // For all other search types, rank should be zero for now.
+ default: return 0;
+ }
+ }
+
+public:
+ explicit PreResult2Maker(Processor & q, Geocoder::Params const & params)
+ : m_processor(q), m_params(params)
+ {
+ }
+
+ unique_ptr<PreResult2> operator()(PreResult1 const & res1)
+ {
+ FeatureType ft;
+ m2::PointD center;
+ string name;
+ string country;
+
+ LoadFeature(res1.GetId(), ft, center, name, country);
+
+ auto res2 = make_unique<PreResult2>(ft, &res1, center, m_processor.GetPosition() /* pivot */,
+ name, country);
+
+ search::RankingInfo info;
+ InitRankingInfo(ft, center, res1, info);
+ info.m_rank = NormalizeRank(info.m_rank, info.m_searchType, center, country);
+ res2->SetRankingInfo(move(info));
+
+ return res2;
+ }
+};
+
+bool Ranker::IsResultExists(PreResult2 const & p, vector<IndexedValue> const & indV)
+{
+ PreResult2::StrictEqualF equalCmp(p);
+ // Do not insert duplicating results.
+ return indV.end() != find_if(indV.begin(), indV.end(), [&equalCmp](IndexedValue const & iv)
+ {
+ return equalCmp(*iv);
+ });
+}
+
+void Ranker::MakePreResult2(Geocoder::Params const & params, vector<IndexedValue> & cont,
+ vector<FeatureID> & streets)
+{
+ m_preRanker.Filter(m_viewportSearch);
+
+ // Makes PreResult2 vector.
+ PreResult2Maker maker(m_processor, params);
+ m_preRanker.ForEach(
+ [&](PreResult1 const & r)
+ {
+ auto p = maker(r);
+ if (!p)
+ return;
+
+ if (params.m_mode == Mode::Viewport && !params.m_pivot.IsPointInside(p->GetCenter()))
+ return;
+
+ if (p->IsStreet())
+ streets.push_back(p->GetID());
+
+ if (!IsResultExists(*p, cont))
+ cont.push_back(IndexedValue(move(p)));
+ });
+}
+
+void Ranker::FlushResults(Geocoder::Params const & params, Results & res, size_t resCount)
+{
+ vector<IndexedValue> indV;
+ vector<FeatureID> streets;
+
+ MakePreResult2(params, indV, streets);
+ RemoveDuplicatingLinear(indV);
+ if (indV.empty())
+ return;
+
+ sort(indV.rbegin(), indV.rend(), my::LessBy(&IndexedValue::GetRank));
+
+ m_processor.ProcessSuggestions(indV, res);
+
+ // Emit feature results.
+ size_t count = res.GetCount();
+ for (size_t i = 0; i < indV.size() && count < resCount; ++i)
+ {
+ if (m_processor.IsCancelled())
+ break;
+
+ LOG(LDEBUG, (indV[i]));
+
+ auto const & preResult2 = *indV[i];
+ if (res.AddResult(m_processor.MakeResult(preResult2)))
+ ++count;
+ }
+}
+
+void Ranker::FlushViewportResults(Geocoder::Params const & params, Results & res)
+{
+ vector<IndexedValue> indV;
+ vector<FeatureID> streets;
+
+ MakePreResult2(params, indV, streets);
+ RemoveDuplicatingLinear(indV);
+ if (indV.empty())
+ return;
+
+ sort(indV.begin(), indV.end(), my::LessBy(&IndexedValue::GetDistanceToPivot));
+
+ for (size_t i = 0; i < indV.size(); ++i)
+ {
+ if (m_processor.IsCancelled())
+ break;
+
+ res.AddResultNoChecks(
+ (*(indV[i]))
+ .GenerateFinalResult(m_processor.m_infoGetter, &m_processor.m_categories,
+ &m_processor.m_prefferedTypes, m_processor.m_currentLocaleCode,
+ nullptr /* Viewport results don't need calculated address */));
+ }
+}
+} // namespace search
diff --git a/search/ranker.hpp b/search/ranker.hpp
new file mode 100644
index 0000000000..c01dacb958
--- /dev/null
+++ b/search/ranker.hpp
@@ -0,0 +1,45 @@
+#pragma once
+
+#include "search/geocoder.hpp"
+#include "search/intermediate_result.hpp"
+#include "search/mode.hpp"
+#include "search/processor.hpp"
+
+#include "indexer/feature_decl.hpp"
+
+#include "std/vector.hpp"
+
+namespace search
+{
+class PreResult2Maker;
+class Processor;
+
+class Ranker
+{
+public:
+ Ranker(PreRanker & preRanker, Processor & processor)
+ : m_viewportSearch(false), m_preRanker(preRanker), m_processor(processor)
+ {
+ }
+
+ void Init(bool viewportSearch) { m_viewportSearch = viewportSearch; }
+
+ bool IsResultExists(PreResult2 const & p, vector<IndexedValue> const & indV);
+
+ void MakePreResult2(Geocoder::Params const & params, vector<IndexedValue> & cont,
+ vector<FeatureID> & streets);
+
+ Result MakeResult(PreResult2 const & r) const;
+
+ void FlushResults(Geocoder::Params const & params, Results & res, size_t resCount);
+ void FlushViewportResults(Geocoder::Params const & params, Results & res);
+
+private:
+ bool m_viewportSearch;
+ PreRanker & m_preRanker;
+
+ // todo(@m) Remove.
+ Processor & m_processor;
+};
+
+} // namespace search
diff --git a/search/search.pro b/search/search.pro
index 96405af26a..6be1bd7a85 100644
--- a/search/search.pro
+++ b/search/search.pro
@@ -49,6 +49,7 @@ HEADERS += \
query_params.hpp \
query_saver.hpp \
rank_table_cache.hpp \
+ ranker.hpp \
ranking_info.hpp \
ranking_utils.hpp \
region.hpp \
@@ -99,6 +100,7 @@ SOURCES += \
query_params.cpp \
query_saver.cpp \
rank_table_cache.cpp \
+ ranker.cpp \
ranking_info.cpp \
ranking_utils.cpp \
region.cpp \