[search] Working on feature's extraction.
This commit is contained in:
parent
f11b91d835
commit
5564b23098
16 changed files with 421 additions and 114 deletions
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
10
search/v2/pre_ranking_info.cpp
Normal file
10
search/v2/pre_ranking_info.cpp
Normal 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
|
27
search/v2/pre_ranking_info.hpp
Normal file
27
search/v2/pre_ranking_info.hpp
Normal 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
|
42
search/v2/ranking_info.cpp
Normal file
42
search/v2/ranking_info.cpp
Normal 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
|
44
search/v2/ranking_info.hpp
Normal file
44
search/v2/ranking_info.hpp
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Reference in a new issue