[search] Working on feature's extraction.

This commit is contained in:
Yuri Gorshenin 2016-03-01 20:20:53 +03:00 committed by Sergey Yershov
parent f11b91d835
commit 5564b23098
16 changed files with 421 additions and 114 deletions

View file

@ -55,8 +55,9 @@ void ProcessMetadata(FeatureType const & ft, Result::Metadata & meta)
namespace impl
{
PreResult1::PreResult1(FeatureID const & fID, uint8_t rank, double priority, int8_t viewportID)
: m_id(fID), m_priority(priority), m_rank(rank), m_viewportID(viewportID)
PreResult1::PreResult1(FeatureID const & fID, double priority, int8_t viewportID,
v2::PreRankingInfo const & info)
: m_id(fID), m_priority(priority), m_viewportID(viewportID), m_info(info)
{
ASSERT(m_id.IsValid(), ());
}
@ -66,8 +67,8 @@ PreResult1::PreResult1(double priority) : m_priority(priority) {}
// static
bool PreResult1::LessRank(PreResult1 const & r1, PreResult1 const & r2)
{
if (r1.m_rank != r2.m_rank)
return r1.m_rank > r2.m_rank;
if (r1.m_info.m_rank != r2.m_info.m_rank)
return r1.m_info.m_rank > r2.m_info.m_rank;
return r1.m_priority < r2.m_priority;
}
@ -76,7 +77,7 @@ bool PreResult1::LessPriority(PreResult1 const & r1, PreResult1 const & r2)
{
if (r1.m_priority != r2.m_priority)
return r1.m_priority < r2.m_priority;
return r1.m_rank > r2.m_rank;
return r1.m_info.m_rank > r2.m_info.m_rank;
}
// static
@ -98,8 +99,6 @@ PreResult2::PreResult2(FeatureType const & f, PreResult1 const * p, m2::PointD c
m_types.SortBySpec();
m_rank = p ? p->GetRank() : 0;
m2::PointD fCenter;
fCenter = f.GetLimitRect(FeatureType::WORST_GEOMETRY).Center();
@ -181,7 +180,7 @@ Result PreResult2::GenerateFinalResult(storage::CountryInfoGetter const & infoGe
case RESULT_FEATURE:
return Result(m_id, GetCenter(), m_str, regionName, pCat->GetReadableFeatureType(type, locale)
#ifdef DEBUG
+ ' ' + strings::to_string(int(m_rank))
+ ' ' + strings::to_string(int(m_info.m_rank))
#endif
, type, m_metadata);
@ -206,8 +205,8 @@ Result PreResult2::GeneratePointResult(storage::CountryInfoGetter const & infoGe
// static
bool PreResult2::LessRank(PreResult2 const & r1, PreResult2 const & r2)
{
if (r1.m_rank != r2.m_rank)
return r1.m_rank > r2.m_rank;
if (r1.m_info.m_rank != r2.m_info.m_rank)
return r1.m_info.m_rank > r2.m_info.m_rank;
return r1.m_distance < r2.m_distance;
}
@ -216,7 +215,7 @@ bool PreResult2::LessDistance(PreResult2 const & r1, PreResult2 const & r2)
{
if (r1.m_distance != r2.m_distance)
return r1.m_distance < r2.m_distance;
return r1.m_rank > r2.m_rank;
return r1.m_info.m_rank > r2.m_info.m_rank;
}
bool PreResult2::StrictEqualF::operator() (PreResult2 const & r) const
@ -275,7 +274,7 @@ string PreResult2::DebugPrint() const
ss << "{ IntermediateResult: " <<
"Name: " << m_str <<
"; Type: " << GetBestType() <<
"; Rank: " << int(m_rank) <<
"; Rank: " << static_cast<int>(m_info.m_rank) <<
"; Distance: " << m_distance << " }";
return ss.str();
}

View file

@ -1,9 +1,11 @@
#pragma once
#include "result.hpp"
#include "search/result.hpp"
#include "search/v2/pre_ranking_info.hpp"
#include "search/v2/ranking_info.hpp"
#include "search/v2/ranking_utils.hpp"
#include "indexer/feature_data.hpp"
class FeatureType;
class CategoriesHolder;
@ -25,11 +27,13 @@ class PreResult1
FeatureID m_id;
double m_priority;
uint8_t m_rank;
int8_t m_viewportID;
v2::PreRankingInfo m_info;
public:
PreResult1(FeatureID const & fID, uint8_t rank, double priority, int8_t viewportID);
PreResult1(FeatureID const & fID, double priority, int8_t viewportID,
v2::PreRankingInfo const & info);
explicit PreResult1(double priority);
@ -38,8 +42,9 @@ public:
static bool LessPointsForViewport(PreResult1 const & r1, PreResult1 const & r2);
inline FeatureID GetID() const { return m_id; }
inline uint8_t GetRank() const { return m_rank; }
inline uint8_t GetRank() const { return m_info.m_rank; }
inline int8_t GetViewportID() const { return m_viewportID; }
inline v2::PreRankingInfo const & GetInfo() const { return m_info; }
};
@ -67,6 +72,14 @@ public:
/// For RESULT_BUILDING.
PreResult2(m2::PointD const & pt, string const & str, uint32_t type);
inline search::v2::RankingInfo const & GetRankingInfo() const { return m_info; }
template <typename TInfo>
inline void SetRankingInfo(TInfo && info)
{
m_info = forward<TInfo>(info);
}
/// @param[in] infoGetter Need to get region for result.
/// @param[in] pCat Categories need to display readable type string.
/// @param[in] pTypes Set of preffered types that match input tokens by categories.
@ -143,7 +156,7 @@ private:
double m_distance;
ResultType m_resultType;
uint8_t m_rank;
v2::RankingInfo m_info;
feature::EGeomType m_geomType;
Result::Metadata m_metadata;

View file

@ -1,4 +1,6 @@
#pragma once
#include "search/v2/ranking_info.hpp"
#include "indexer/feature_decl.hpp"
#include "editor/yes_no_unknown.hpp"
@ -97,6 +99,14 @@ public:
int32_t GetPositionInResults() const { return m_positionInResults; }
void SetPositionInResults(int32_t pos) { m_positionInResults = pos; }
inline v2::RankingInfo const & GetRankingInfo() const { return m_info; }
template <typename TInfo>
inline void SetRankingInfo(TInfo && info)
{
m_info = forward<TInfo>(info);
}
// Returns a representation of this result that is
// sent to the statistics servers and later used to measure
// the quality of our search engine.
@ -112,6 +122,8 @@ private:
string m_suggestionStr;
buffer_vector<pair<uint16_t, uint16_t>, 4> m_hightlightRanges;
v2::RankingInfo m_info;
// The position that this result occupied in the vector returned
// by a search query. -1 if undefined.
int32_t m_positionInResults = -1;

View file

@ -52,7 +52,9 @@ HEADERS += \
v2/intersection_result.hpp \
v2/locality_scorer.hpp \
v2/mwm_context.hpp \
v2/pre_ranking_info.hpp \
v2/rank_table_cache.hpp \
v2/ranking_info.hpp \
v2/ranking_utils.hpp \
v2/search_model.hpp \
v2/search_query_v2.hpp \
@ -92,7 +94,9 @@ SOURCES += \
v2/intersection_result.cpp \
v2/locality_scorer.cpp \
v2/mwm_context.cpp \
v2/pre_ranking_info.cpp \
v2/rank_table_cache.cpp \
v2/ranking_info.cpp \
v2/ranking_utils.cpp \
v2/search_model.cpp \
v2/search_query_v2.cpp \

View file

@ -14,6 +14,7 @@
#include "search/result.hpp"
#include "search/search_tests_support/test_search_engine.hpp"
#include "search/search_tests_support/test_search_request.hpp"
#include "search/v2/ranking_info.hpp"
#include "platform/country_file.hpp"
#include "platform/local_country_file.hpp"
@ -59,6 +60,7 @@ DEFINE_string(queries_path, "", "Path to the file with queries");
DEFINE_int32(top, 1, "Number of top results to show for every query");
DEFINE_string(viewport, "", "Viewport to use when searching (default, moscow, london, zurich)");
DEFINE_string(check_completeness, "", "Path to the file with completeness data");
DEFINE_string(ranking_csv_file, "", "File ranking info will be exported to");
map<string, m2::RectD> const kViewports = {
{"default", m2::RectD(m2::PointD(0.0, 0.0), m2::PointD(1.0, 1.0))},
@ -440,6 +442,22 @@ int main(int argc, char * argv[])
engine, MakePrefixFree(queries[i]), FLAGS_locale, search::Mode::Everywhere, viewport));
}
ofstream csv;
bool dumpCSV = false;
if (!FLAGS_ranking_csv_file.empty())
{
ofstream os(FLAGS_ranking_csv_file);
csv.swap(os);
if (csv.is_open())
dumpCSV = true;
}
if (dumpCSV)
{
search::v2::RankingInfo::PrintCSVHeader(csv);
csv << endl;
}
vector<double> responseTimes(queries.size());
for (size_t i = 0; i < queries.size(); ++i)
{
@ -448,6 +466,15 @@ int main(int argc, char * argv[])
responseTimes[i] = static_cast<double>(rt) / 1000;
PrintTopResults(MakePrefixFree(queries[i]), requests[i]->Results(), FLAGS_top,
responseTimes[i]);
if (dumpCSV)
{
for (auto const & result : requests[i]->Results())
{
result.GetRankingInfo().ToCSV(csv);
csv << endl;
}
}
}
double averageTime;

View file

@ -11,8 +11,12 @@
#include "search/search_index_values.hpp"
#include "search/search_query_params.hpp"
#include "search/search_string_intersection.hpp"
#include "search/v2/pre_ranking_info.hpp"
#include "search/v2/ranking_info.hpp"
#include "search/v2/ranking_utils.hpp"
#include "storage/country_info_getter.hpp"
#include "storage/index.hpp"
#include "indexer/categories_holder.hpp"
#include "indexer/classificator.hpp"
@ -129,7 +133,7 @@ class IndexedValue : public search::IndexedValueBase<Query::kQueuesCount>
shared_ptr<impl::PreResult2> m_val;
public:
explicit IndexedValue(impl::PreResult2 * v) : m_val(v) {}
explicit IndexedValue(unique_ptr<impl::PreResult2> v) : m_val(move(v)) {}
impl::PreResult2 const & operator*() const { return *m_val; }
};
@ -500,7 +504,10 @@ void Query::Search(Results & res, size_t resCount)
LONG_OP(SearchAddress(res));
LONG_OP(SearchFeatures());
LONG_OP(FlushResults(res, false /* allMWMs */, resCount, true /* oldHouseSearch */));
// TODO (@y): this code is not working and will gone away.
v2::Geocoder::Params params;
LONG_OP(FlushResults(params, res, false /* allMWMs */, resCount, true /* oldHouseSearch */));
}
void Query::SearchViewportPoints(Results & res)
@ -508,15 +515,18 @@ void Query::SearchViewportPoints(Results & res)
LONG_OP(SearchAddress(res));
LONG_OP(SearchFeaturesInViewport(CURRENT_V));
FlushViewportResults(res, true /* oldHouseSearch */);
// TODO (@y): this code is not working and will gone away.
v2::Geocoder::Params params;
FlushViewportResults(params, res, true /* oldHouseSearch */);
}
void Query::FlushViewportResults(Results & res, bool oldHouseSearch)
void Query::FlushViewportResults(v2::Geocoder::Params const & params, Results & res,
bool oldHouseSearch)
{
vector<IndexedValue> indV;
vector<FeatureID> streets;
MakePreResult2(indV, streets);
MakePreResult2(params, indV, streets);
if (indV.empty())
return;
@ -583,9 +593,9 @@ public:
bool operator()(ValueT const & r) const { return (m_val.GetID() == r.GetID()); }
};
bool IsResultExists(impl::PreResult2 const * p, vector<IndexedValue> const & indV)
bool IsResultExists(impl::PreResult2 const & p, vector<IndexedValue> const & indV)
{
impl::PreResult2::StrictEqualF equalCmp(*p);
impl::PreResult2::StrictEqualF equalCmp(p);
// Do not insert duplicating results.
return indV.end() != find_if(indV.begin(), indV.end(), [&equalCmp](IndexedValue const & iv)
{
@ -599,6 +609,9 @@ namespace impl
class PreResult2Maker
{
Query & m_query;
storage::CountryInfoGetter const & m_infoGetter;
v2::Geocoder::Params const & m_params;
string m_positionCountry;
unique_ptr<Index::FeaturesLoaderGuard> m_pFV;
@ -628,18 +641,71 @@ class PreResult2Maker
country = m_pFV->GetCountryFileName();
}
public:
explicit PreResult2Maker(Query & q) : m_query(q) {}
void InitRankingInfo(FeatureType const & ft, impl::PreResult1 const & result,
search::v2::RankingInfo & info)
{
auto const & preInfo = result.GetInfo();
auto const & viewport = m_params.m_viewport;
auto const & position = m_params.m_position;
impl::PreResult2 * operator()(impl::PreResult1 const & res)
info.m_distanceToViewport = viewport.IsEmptyInterior()
? v2::PreRankingInfo::kMaxDistMeters
: feature::GetMinDistanceMeters(ft, viewport.Center());
info.m_distanceToPosition = feature::GetMinDistanceMeters(ft, position);
info.m_rank = preInfo.m_rank;
info.m_searchType = v2::SearchModel::Instance().GetSearchType(ft);
info.m_nameScore = v2::NAME_SCORE_ZERO;
for (auto const & lang : m_params.m_langs)
{
string name;
if (!ft.GetName(lang, name))
continue;
auto score = GetNameScore(name, m_params, preInfo.m_startToken, preInfo.m_endToken);
if (score > info.m_nameScore)
info.m_nameScore = score;
}
if (info.m_searchType == v2::SearchModel::SEARCH_TYPE_BUILDING)
{
string houseNumber = ft.GetHouseNumber();
auto score = GetNameScore(houseNumber, m_params, preInfo.m_startToken, preInfo.m_endToken);
if (score > info.m_nameScore)
info.m_nameScore = score;
}
auto const featureCountry = m_infoGetter.GetRegionCountryId(feature::GetCenter(ft));
// TODO (@y, @m, @vng): exact check is too restrictive, as we
// switched to small mwms. Probably it's worth here to find a
// Least-Common-Ancestor for feature center and user position in
// the country tree, and use level (distance to root) of the
// result here.
info.m_sameCountry = (featureCountry == m_positionCountry);
info.m_positionInViewport = viewport.IsPointInside(position);
}
public:
explicit PreResult2Maker(Query & q, v2::Geocoder::Params const & params)
: m_query(q), m_infoGetter(m_query.GetCountryInfoGetter()), m_params(params)
{
m_positionCountry = m_infoGetter.GetRegionCountryId(m_params.m_position);
}
unique_ptr<impl::PreResult2> operator()(impl::PreResult1 const & res)
{
FeatureType feature;
string name, country;
LoadFeature(res.GetID(), feature, name, country);
Query::ViewportID const viewportID = static_cast<Query::ViewportID>(res.GetViewportID());
impl::PreResult2 * res2 =
new impl::PreResult2(feature, &res, m_query.GetPosition(viewportID), name, country);
auto res2 = make_unique<impl::PreResult2>(feature, &res, m_query.GetPosition(viewportID), name,
country);
search::v2::RankingInfo info;
InitRankingInfo(feature, res, info);
res2->SetRankingInfo(move(info));
/// @todo: add exluding of states (without USA states), continents
using namespace ftypes;
@ -647,22 +713,22 @@ public:
switch (tp)
{
case COUNTRY:
res2->m_rank /= 1.5;
res2->m_info.m_rank /= 1.5;
break;
case CITY:
case TOWN:
if (m_query.GetViewport(Query::CURRENT_V).IsPointInside(res2->GetCenter()))
res2->m_rank *= 2;
res2->m_info.m_rank *= 2;
else
{
storage::CountryInfo ci;
res2->m_region.GetRegion(m_query.m_infoGetter, ci);
if (ci.IsNotEmpty() && ci.m_name == m_query.GetPivotRegion())
res2->m_rank *= 1.7;
res2->m_info.m_rank *= 1.7;
}
break;
case VILLAGE:
res2->m_rank /= 1.5;
res2->m_info.m_rank /= 1.5;
break;
default:
break;
@ -670,18 +736,6 @@ public:
return res2;
}
impl::PreResult2 * operator()(FeatureID const & id)
{
FeatureType feature;
string name, country;
LoadFeature(id, feature, name, country);
if (!name.empty() && !country.empty())
return new impl::PreResult2(feature, 0, m_query.GetPosition(), name, country);
else
return 0;
}
};
class HouseCompFactory
@ -715,7 +769,8 @@ public:
} // namespace impl
template <class T>
void Query::MakePreResult2(vector<T> & cont, vector<FeatureID> & streets)
void Query::MakePreResult2(v2::Geocoder::Params const & params, vector<T> & cont,
vector<FeatureID> & streets)
{
// make unique set of PreResult1
using TPreResultSet = set<impl::PreResult1, LessFeatureID>;
@ -727,21 +782,19 @@ void Query::MakePreResult2(vector<T> & cont, vector<FeatureID> & streets)
m_results[i].clear();
}
// make PreResult2 vector
impl::PreResult2Maker maker(*this);
// Makes PreResult2 vector.
impl::PreResult2Maker maker(*this, params);
for (auto const & r : theSet)
{
impl::PreResult2 * p = maker(r);
if (p == 0)
auto p = maker(r);
if (!p)
continue;
if (p->IsStreet())
streets.push_back(p->GetID());
if (IsResultExists(p, cont))
delete p;
else
cont.push_back(IndexedValue(p));
if (!IsResultExists(*p, cont))
cont.push_back(IndexedValue(move(p)));
}
}
@ -774,12 +827,13 @@ void Query::FlushHouses(Results & res, bool allMWMs, vector<FeatureID> const & s
}
}
void Query::FlushResults(Results & res, bool allMWMs, size_t resCount, bool oldHouseSearch)
void Query::FlushResults(v2::Geocoder::Params const & params, Results & res, bool allMWMs,
size_t resCount, bool oldHouseSearch)
{
vector<IndexedValue> indV;
vector<FeatureID> streets;
MakePreResult2(indV, streets);
MakePreResult2(params, indV, streets);
if (indV.empty())
return;
@ -806,7 +860,8 @@ void Query::FlushResults(Results & res, bool allMWMs, size_t resCount, bool oldH
LOG(LDEBUG, (indV[i]));
if (res.AddResult(MakeResult(*(indV[i]))))
auto const & preResult2 = *indV[i];
if (res.AddResult(MakeResult(preResult2)))
++count;
}
}
@ -907,10 +962,10 @@ void Query::ProcessSuggestions(vector<T> & vec, Results & res) const
}
}
void Query::AddPreResult1(MwmSet::MwmId const & mwmId, uint32_t featureId, uint8_t rank,
double priority, ViewportID viewportId /*= DEFAULT_V*/)
void Query::AddPreResult1(MwmSet::MwmId const & mwmId, uint32_t featureId, double priority,
v2::PreRankingInfo const & info, ViewportID viewportId /* = DEFAULT_V */)
{
impl::PreResult1 res(FeatureID(mwmId, featureId), rank, priority, viewportId);
impl::PreResult1 res(FeatureID(mwmId, featureId), priority, viewportId, info);
for (size_t i = 0; i < m_queuesCount; ++i)
{
@ -1026,6 +1081,8 @@ Result Query::MakeResult(impl::PreResult2 const & r) const
}
#endif
res.SetRankingInfo(r.GetRankingInfo());
return res;
}
@ -1294,7 +1351,13 @@ void Query::SearchAddress(Results & res)
else
{
// Add found locality as a result if nothing left to match.
AddPreResult1(mwmId, city.m_featureId, city.m_rank, 1.0 /* priority */);
// TODO (@y): for backward compatibility with old search
// algorithm carefully fill |info| here.
v2::PreRankingInfo info;
info.m_rank = city.m_rank;
AddPreResult1(mwmId, city.m_featureId, 1.0 /* priority */, info);
}
}
else if (region.IsValid())

View file

@ -4,6 +4,7 @@
#include "search/mode.hpp"
#include "search/search_trie.hpp"
#include "search/suggest.hpp"
#include "search/v2/geocoder.hpp"
#include "search/v2/rank_table_cache.hpp"
#include "indexer/ftypes_matcher.hpp"
@ -63,6 +64,11 @@ namespace impl
class HouseCompFactory;
}
namespace v2
{
struct PreRankingInfo;
}
// TODO (@y): rename this class to QueryProcessor.
class Query : public my::Cancellable
{
@ -97,6 +103,8 @@ public:
void SetQuery(string const & query);
inline bool IsEmptyQuery() const { return (m_prefix.empty() && m_tokens.empty()); }
inline storage::CountryInfoGetter const & GetCountryInfoGetter() const { return m_infoGetter; }
/// @name Different search functions.
//@{
virtual void Search(Results & res, size_t resCount);
@ -151,18 +159,21 @@ protected:
bool forceUpdate);
void ClearCache(size_t ind);
void AddPreResult1(MwmSet::MwmId const & mwmId, uint32_t featureId, uint8_t rank, double priority,
ViewportID viewportId = DEFAULT_V);
void AddPreResult1(MwmSet::MwmId const & mwmId, uint32_t featureId, double priority,
v2::PreRankingInfo const & info, ViewportID viewportId = DEFAULT_V);
template <class T> void MakePreResult2(vector<T> & cont, vector<FeatureID> & streets);
template <class T>
void MakePreResult2(v2::Geocoder::Params const & params, vector<T> & cont,
vector<FeatureID> & streets);
/// @param allMWMs Deprecated, need to support old search algorithm.
/// @param oldHouseSearch Deprecated, need to support old search algorithm.
//@{
void FlushHouses(Results & res, bool allMWMs, vector<FeatureID> const & streets);
void FlushResults(Results & res, bool allMWMs, size_t resCount, bool oldHouseSearch);
void FlushViewportResults(Results & res, bool oldHouseSearch);
void FlushResults(v2::Geocoder::Params const & params, Results & res, bool allMWMs, size_t resCount,
bool oldHouseSearch);
void FlushViewportResults(v2::Geocoder::Params const & params, Results & res, bool oldHouseSearch);
//@}
void RemoveStringPrefix(string const & str, string & res) const;

View file

@ -12,7 +12,6 @@
#include "indexer/feature_impl.hpp"
#include "indexer/ftypes_matcher.hpp"
#include "indexer/index.hpp"
#include "indexer/mwm_set.hpp"
#include "indexer/rank_table.hpp"
#include "indexer/search_delimiters.hpp"
#include "indexer/search_string_utils.hpp"
@ -387,6 +386,11 @@ void UniteCBVs(vector<unique_ptr<coding::CompressedBitVector>> & cbvs)
cbvs.resize(i);
}
}
bool SameMwm(Geocoder::TResult const & lhs, Geocoder::TResult const & rhs)
{
return lhs.first.m_mwmId == rhs.first.m_mwmId;
}
} // namespace
// Geocoder::Params --------------------------------------------------------------------------------
@ -453,7 +457,7 @@ void Geocoder::SetParams(Params const & params)
LOG(LDEBUG, ("Languages =", m_params.m_langs));
}
void Geocoder::GoEverywhere(vector<FeatureID> & results)
void Geocoder::GoEverywhere(TResultList & results)
{
// TODO (@y): remove following code as soon as Geocoder::Go() will
// work fast for most cases (significantly less than 1 second).
@ -480,7 +484,7 @@ void Geocoder::GoEverywhere(vector<FeatureID> & results)
GoImpl(infos, false /* inViewport */);
}
void Geocoder::GoInViewport(vector<FeatureID> & results)
void Geocoder::GoInViewport(TResultList & results)
{
if (m_numTokens == 0)
return;
@ -608,6 +612,9 @@ void Geocoder::GoImpl(vector<shared_ptr<MwmInfo>> & infos, bool inViewport)
catch (CancelException & e)
{
}
// Fill results ranks, as they were missed.
FillResultRanks();
}
void Geocoder::ClearCaches()
@ -895,7 +902,7 @@ void Geocoder::MatchRegions(RegionType type)
if (AllTokensUsed())
{
// Region matches to search query, we need to emit it as is.
EmitResult(m_worldId, region.m_featureId);
EmitResult(m_worldId, region.m_featureId, startToken, endToken);
continue;
}
@ -941,7 +948,7 @@ void Geocoder::MatchCities()
if (AllTokensUsed())
{
// City matches to search query.
EmitResult(city.m_countryId, city.m_featureId);
EmitResult(city.m_countryId, city.m_featureId, startToken, endToken);
continue;
}
@ -1236,19 +1243,68 @@ void Geocoder::FindPaths()
sortedLayers.push_back(&layer);
sort(sortedLayers.begin(), sortedLayers.end(), my::CompareBy(&FeaturesLayer::m_type));
auto startToken = sortedLayers.front()->m_startToken;
auto endToken = sortedLayers.front()->m_endToken;
m_finder.ForEachReachableVertex(*m_matcher, sortedLayers,
[this](IntersectionResult const & result)
{
[this, startToken, endToken](IntersectionResult const & result)
{
ASSERT(result.IsValid(), ());
// TODO(@y, @m, @vng): use rest fields of IntersectionResult for
// better scoring.
EmitResult(m_context->GetId(), result.InnermostResult());
EmitResult(m_context->GetId(), result.InnermostResult(), startToken, endToken);
});
}
void Geocoder::EmitResult(MwmSet::MwmId const & mwmId, uint32_t featureId)
void Geocoder::EmitResult(MwmSet::MwmId const & mwmId, uint32_t ftId, size_t startToken,
size_t endToken)
{
m_results->emplace_back(mwmId, featureId);
FeatureID id(mwmId, ftId);
PreRankingInfo info;
info.m_startToken = startToken;
info.m_endToken = endToken;
if (auto const & mwmInfo = mwmId.GetInfo())
{
auto const center = mwmInfo->m_limitRect.Center();
info.m_mwmDistanceToViewport =
MercatorBounds::DistanceOnEarth(center, m_params.m_viewport.Center());
info.m_mwmDistanceToPosition = MercatorBounds::DistanceOnEarth(center, m_params.m_position);
}
// info.m_ranks will be filled at the end, at once.
m_results->emplace_back(move(id), move(info));
}
void Geocoder::FillResultRanks()
{
sort(m_results->begin(), m_results->end(), my::CompareBy(&TResult::first));
auto ib = m_results->begin();
while (ib != m_results->end())
{
auto ie = ib;
while (ie != m_results->end() && SameMwm(*ib, *ie))
++ie;
/// @todo Add RankTableCache here?
MwmSet::MwmHandle handle = m_index.GetMwmHandleById(ib->first.m_mwmId);
if (handle.IsAlive())
{
auto rankTable = RankTable::Load(handle.GetValue<MwmValue>()->m_cont);
if (!rankTable.get())
rankTable.reset(new DummyRankTable());
for (auto ii = ib; ii != ie; ++ii)
{
auto const & id = ii->first;
auto & info = ii->second;
info.m_rank = rankTable->Get(id.m_index);
}
}
ib = ie;
}
}
void Geocoder::MatchUnclassified(size_t curToken)
@ -1268,6 +1324,7 @@ void Geocoder::MatchUnclassified(size_t curToken)
CBVPtr allFeatures;
allFeatures.SetFull();
auto startToken = curToken;
for (curToken = SkipUsedTokens(curToken); curToken < m_numTokens && !m_usedTokens[curToken];
++curToken)
{
@ -1283,7 +1340,7 @@ void Geocoder::MatchUnclassified(size_t curToken)
auto emitUnclassified = [&](uint32_t featureId)
{
if (GetSearchTypeInGeocoding(featureId) == SearchModel::SEARCH_TYPE_UNCLASSIFIED)
EmitResult(m_context->GetId(), featureId);
EmitResult(m_context->GetId(), featureId, startToken, curToken);
};
coding::CompressedBitVectorEnumerator::ForEach(*allFeatures, emitUnclassified);
}

View file

@ -6,9 +6,12 @@
#include "search/v2/features_layer.hpp"
#include "search/v2/features_layer_path_finder.hpp"
#include "search/v2/mwm_context.hpp"
#include "search/v2/pre_ranking_info.hpp"
#include "search/v2/ranking_utils.hpp"
#include "search/v2/search_model.hpp"
#include "indexer/index.hpp"
#include "indexer/mwm_set.hpp"
#include "storage/country_info_getter.hpp"
@ -21,6 +24,7 @@
#include "base/macros.hpp"
#include "base/string_utils.hpp"
#include "std/limits.hpp"
#include "std/set.hpp"
#include "std/string.hpp"
#include "std/unique_ptr.hpp"
@ -123,17 +127,20 @@ public:
m2::RectD m_rect;
};
using TResult = pair<FeatureID, PreRankingInfo>;
using TResultList = vector<pair<FeatureID, PreRankingInfo>>;
Geocoder(Index & index, storage::CountryInfoGetter const & infoGetter);
~Geocoder() override;
// Sets search query params.
// Sets/Gets search query params.
void SetParams(Params const & params);
// Starts geocoding, retrieved features will be appended to
// |results|.
void GoEverywhere(vector<FeatureID> & results);
void GoInViewport(vector<FeatureID> & results);
void GoEverywhere(TResultList & results);
void GoInViewport(TResultList & results);
void ClearCaches();
@ -215,7 +222,9 @@ private:
// the lowest layer.
void FindPaths();
void EmitResult(MwmSet::MwmId const & mwmId, uint32_t featureId);
void EmitResult(MwmSet::MwmId const & mwmId, uint32_t ftId, size_t startToken, size_t endToken);
void FillResultRanks();
// Tries to match unclassified objects from lower layers, like
// parks, forests, lakes, rivers, etc. This method finds all
@ -326,7 +335,7 @@ private:
vector<FeaturesLayer> m_layers;
// Non-owning pointer to a vector of results.
vector<FeatureID> * m_results;
TResultList * m_results;
};
string DebugPrint(Geocoder::Locality const & locality);

View file

@ -0,0 +1,10 @@
#include "search/v2/pre_ranking_info.hpp"
namespace search
{
namespace v2
{
// static
double const PreRankingInfo::kMaxDistMeters = 1000000000;
} // namespace v2
} // namespace search

View file

@ -0,0 +1,27 @@
#pragma once
#include "std/cstdint.hpp"
namespace search
{
namespace v2
{
struct PreRankingInfo
{
static double const kMaxDistMeters;
// Distance from the mwm center to the current viewport's center.
double m_mwmDistanceToViewport = kMaxDistMeters;
// Distance from the feature to the current user's position.
double m_mwmDistanceToPosition = kMaxDistMeters;
// Tokens [m_startToken, m_endToken) match to the query.
size_t m_startToken = 0;
size_t m_endToken = 0;
// Rank of the feature.
uint8_t m_rank = 0;
};
} // namespace v2
} // namespace search

View file

@ -0,0 +1,42 @@
#include "search/v2/ranking_info.hpp"
namespace search
{
namespace v2
{
// static
void RankingInfo::PrintCSVHeader(ostream & os)
{
os << "DistanceToViewport"
<< ",DistanceToPosition"
<< ",Rank"
<< ",NameScore"
<< ",SearchType"
<< ",SameCountry"
<< ",PositionInViewport";
}
string DebugPrint(RankingInfo const & info)
{
ostringstream os;
os << "RankingInfo [";
os << "m_distanceToViewport:" << info.m_distanceToViewport << ",";
os << "m_distanceToPosition:" << info.m_distanceToPosition << ",";
os << "m_rank:" << static_cast<int>(info.m_rank) << ",";
os << "m_nameScore:" << DebugPrint(info.m_nameScore) << ",";
os << "m_searchType:" << DebugPrint(info.m_searchType) << ",";
os << "m_sameCountry:" << info.m_sameCountry << ",";
os << "m_positionInViewport:" << info.m_positionInViewport;
os << "]";
return os.str();
}
void RankingInfo::ToCSV(ostream & os) const
{
os << fixed;
os << m_distanceToViewport << "," << m_distanceToPosition << "," << static_cast<int>(m_rank)
<< "," << DebugPrint(m_nameScore) << "," << DebugPrint(m_searchType) << "," << m_sameCountry
<< "," << m_positionInViewport;
}
} // namespace v2
} // namespace search

View file

@ -0,0 +1,44 @@
#pragma once
#include "search/v2/geocoder.hpp"
#include "search/v2/pre_ranking_info.hpp"
#include "search/v2/ranking_utils.hpp"
#include "search/v2/search_model.hpp"
class FeatureType;
namespace search
{
namespace v2
{
struct RankingInfo
{
// Distance from the feature to the current viewport's center.
double m_distanceToViewport = PreRankingInfo::kMaxDistMeters;
// Distance from the feature to the current user's position.
double m_distanceToPosition = PreRankingInfo::kMaxDistMeters;
// Rank of the feature.
uint8_t m_rank = 0;
// Score for the feature's name.
NameScore m_nameScore = NAME_SCORE_ZERO;
// Search type for the feature.
SearchModel::SearchType m_searchType = SearchModel::SEARCH_TYPE_COUNT;
// True if feature is located in the same country as the user.
bool m_sameCountry = false;
// True if user's position is in viewport.
bool m_positionInViewport = false;
static void PrintCSVHeader(ostream & os);
void ToCSV(ostream & os) const;
};
string DebugPrint(RankingInfo const & info);
} // namespace v2
} // namespace search

View file

@ -1,6 +1,10 @@
#pragma once
#include "search/v2/geocoder.hpp"
#include "search/v2/search_model.hpp"
#include "std/cstdint.hpp"
#include "std/limits.hpp"
#include "std/string.hpp"
namespace search

View file

@ -43,11 +43,11 @@ void SearchQueryV2::Search(Results & res, size_t resCount)
params.m_maxNumResults = max(resCount, kPreResultsCount);
m_geocoder.SetParams(params);
vector<FeatureID> results;
Geocoder::TResultList results;
m_geocoder.GoEverywhere(results);
AddPreResults1(results);
AddPreResults1(results, false /* viewportSearch */);
FlushResults(res, false /* allMWMs */, resCount, false /* oldHouseSearch */);
FlushResults(params, res, false /* allMWMs */, resCount, false /* oldHouseSearch */);
}
void SearchQueryV2::SearchViewportPoints(Results & res)
@ -59,11 +59,11 @@ void SearchQueryV2::SearchViewportPoints(Results & res)
params.m_maxNumResults = kPreResultsCount;
m_geocoder.SetParams(params);
vector<FeatureID> results;
Geocoder::TResultList results;
m_geocoder.GoInViewport(results);
AddPreResults1(results);
AddPreResults1(results, true /* viewportSearch */);
FlushViewportResults(res, false /* oldHouseSearch */);
FlushViewportResults(params, res, false /* oldHouseSearch */);
}
void SearchQueryV2::ClearCaches()
@ -72,32 +72,16 @@ void SearchQueryV2::ClearCaches()
m_geocoder.ClearCaches();
}
void SearchQueryV2::AddPreResults1(vector<FeatureID> & results)
void SearchQueryV2::AddPreResults1(Geocoder::TResultList & results, bool viewportSearch)
{
// Group all features by MwmId and add them as PreResult1.
sort(results.begin(), results.end());
auto ib = results.begin();
while (ib != results.end())
for (auto const & result : results)
{
auto ie = ib;
while (ie != results.end() && ie->m_mwmId == ib->m_mwmId)
++ie;
/// @todo Add RankTableCache here?
MwmSet::MwmHandle handle = m_index.GetMwmHandleById(ib->m_mwmId);
if (handle.IsAlive())
{
auto rankTable = RankTable::Load(handle.GetValue<MwmValue>()->m_cont);
if (!rankTable.get())
rankTable.reset(new DummyRankTable());
/// @todo Do final results processing without Query::AddPreResult1.
/// At least, priority and it's queue is an overhead now.
for (auto ii = ib; ii != ie; ++ii)
AddPreResult1(ii->m_mwmId, ii->m_index, rankTable->Get(ii->m_index), 0.0 /* priority */);
}
ib = ie;
auto const & id = result.first;
auto const & info = result.second;
if (viewportSearch)
AddPreResult1(id.m_mwmId, id.m_index, info.m_mwmDistanceToViewport /* priority */, info);
else
AddPreResult1(id.m_mwmId, id.m_index, info.m_mwmDistanceToPosition /* priority */, info);
}
}
} // namespace v2

View file

@ -24,7 +24,8 @@ public:
protected:
// Adds a bunch of features as PreResult1.
void AddPreResults1(vector<FeatureID> & results);
void AddPreResults1(Geocoder::TResultList & results,
bool viewportSearch);
Geocoder m_geocoder;
};