Merge pull request #3891 from ygorshenin/use-centers-table

[search] Added centers table usage.
This commit is contained in:
mpimenov 2016-07-29 15:22:15 +03:00 committed by GitHub
commit bedde4511c
22 changed files with 460 additions and 88 deletions

View file

@ -15,6 +15,7 @@
#define OFFSET_EXT ".offs"
#define ID2REL_EXT ".id2rel"
#define CENTERS_FILE_TAG "centers"
#define DATA_FILE_TAG "dat"
#define GEOMETRY_FILE_TAG "geom"
#define TRIANGLE_FILE_TAG "trg"

View file

@ -0,0 +1,69 @@
#include "generator/centers_table_builder.hpp"
#include "search/search_trie.hpp"
#include "indexer/centers_table.hpp"
#include "indexer/feature_algo.hpp"
#include "indexer/features_offsets_table.hpp"
#include "indexer/features_vector.hpp"
#include "coding/file_container.hpp"
#include "platform/mwm_traits.hpp"
#include "base/exception.hpp"
#include "defines.hpp"
namespace indexer
{
bool BuildCentersTableFromDataFile(string const & filename, bool forceRebuild)
{
try
{
search::CentersTableBuilder builder;
{
FilesContainerR rcont(filename);
if (!forceRebuild && rcont.IsExist(CENTERS_FILE_TAG))
return true;
feature::DataHeader header(rcont);
version::MwmTraits const traits(header.GetFormat());
if (!traits.HasOffsetsTable())
{
LOG(LERROR, (filename, "does not have an offsets table!"));
return false;
}
auto const table = feature::FeaturesOffsetsTable::Load(rcont);
if (!table)
{
LOG(LERROR, ("Can't load offsets table from:", filename));
return false;
}
FeaturesVector const features(rcont, header, table.get());
builder.SetCodingParams(header.GetDefCodingParams());
features.ForEach([&](FeatureType & ft, uint32_t featureId) {
builder.Put(featureId, feature::GetCenter(ft));
});
}
{
FilesContainerW writeContainer(filename, FileWriter::OP_WRITE_EXISTING);
FileWriter writer = writeContainer.GetWriter(CENTERS_FILE_TAG);
builder.Freeze(writer);
}
}
catch (RootException const & e)
{
LOG(LERROR, ("Failed to build centers table:", e.Msg()));
return false;
}
return true;
}
} // namespace indexer

View file

@ -0,0 +1,13 @@
#pragma once
#include "std/string.hpp"
class FilesContainerR;
class Writer;
namespace indexer
{
// Builds the latest version of the centers table section and writes
// it to the mwm file.
bool BuildCentersTableFromDataFile(string const & filename, bool forceRebuild = false);
} // namespace indexer

View file

@ -20,6 +20,7 @@ SOURCES += \
booking_scoring.cpp \
borders_generator.cpp \
borders_loader.cpp \
centers_table_builder.cpp \
check_model.cpp \
coastlines_generator.cpp \
dumper.cpp \
@ -47,6 +48,7 @@ HEADERS += \
booking_scoring.hpp \
borders_generator.hpp \
borders_loader.hpp \
centers_table_builder.hpp \
check_model.hpp \
coastlines_generator.hpp \
dumper.hpp \

View file

@ -1,5 +1,6 @@
#include "generator/generator_tests_support/test_mwm_builder.hpp"
#include "generator/centers_table_builder.hpp"
#include "generator/feature_builder.hpp"
#include "generator/feature_generator.hpp"
#include "generator/feature_sorter.hpp"
@ -89,6 +90,9 @@ void TestMwmBuilder::Finish()
CHECK(indexer::BuildSearchIndexFromDataFile(path, true /* forceRebuild */),
("Can't build search index."));
CHECK(indexer::BuildCentersTableFromDataFile(path, true /* forceRebuild */),
("Can't build centers table."));
CHECK(search::RankTableBuilder::CreateIfNotExists(path), ());
m_file.SyncWithDisk();

View file

@ -1,6 +1,7 @@
#include "generator/altitude_generator.hpp"
#include "generator/borders_generator.hpp"
#include "generator/borders_loader.hpp"
#include "generator/centers_table_builder.hpp"
#include "generator/check_model.hpp"
#include "generator/dumper.hpp"
#include "generator/feature_generator.hpp"
@ -213,9 +214,12 @@ int main(int argc, char ** argv)
LOG(LCRITICAL, ("Error generating search index."));
LOG(LINFO, ("Generating rank table for", datFile));
if (!search::RankTableBuilder::CreateIfNotExists(datFile))
LOG(LCRITICAL, ("Error generating rank table."));
LOG(LINFO, ("Generating centers table for", datFile));
if (!indexer::BuildCentersTableFromDataFile(datFile, true /* forceRebuild */))
LOG(LCRITICAL, ("Error generating centers table."));
}
if (!FLAGS_srtm_path.empty())

View file

@ -1,10 +1,11 @@
#include "indexer/centers_table.hpp"
#include "indexer/coding_params.hpp"
#include "indexer/feature_processor.hpp"
#include "indexer/geometry_coding.hpp"
#include "indexer/point_to_int64.hpp"
#include "coding/endianness.hpp"
#include "coding/file_container.hpp"
#include "coding/memory_region.hpp"
#include "coding/reader.hpp"
#include "coding/succinct_mapper.hpp"
@ -262,17 +263,21 @@ unique_ptr<CentersTable> CentersTable::Load(Reader & reader,
}
// CentersTableBuilder -----------------------------------------------------------------------------
CentersTableBuilder::CentersTableBuilder(Writer & writer, serial::CodingParams const & codingParams)
: m_writer(writer), m_codingParams(codingParams)
void CentersTableBuilder::Put(uint32_t featureId, m2::PointD const & center)
{
if (!m_ids.empty())
CHECK_LESS(m_ids.back(), featureId, ());
m_centers.push_back(PointD2PointU(center, m_codingParams.GetCoordBits()));
m_ids.push_back(featureId);
}
CentersTableBuilder::~CentersTableBuilder()
void CentersTableBuilder::Freeze(Writer & writer) const
{
CentersTableV0::Header header;
int64_t const startOffset = m_writer.Pos();
header.Write(m_writer);
int64_t const startOffset = writer.Pos();
header.Write(writer);
{
uint64_t const numBits = m_ids.empty() ? 0 : m_ids.back() + 1;
@ -281,7 +286,7 @@ CentersTableBuilder::~CentersTableBuilder()
for (auto const & id : m_ids)
builder.set(id, true);
coding::FreezeVisitor<Writer> visitor(m_writer);
coding::FreezeVisitor<Writer> visitor(writer);
succinct::rs_bit_vector(&builder).map(visitor);
}
@ -310,30 +315,21 @@ CentersTableBuilder::~CentersTableBuilder()
for (auto const & offset : offsets)
builder.push_back(offset);
header.m_positionsOffset = m_writer.Pos();
coding::FreezeVisitor<Writer> visitor(m_writer);
header.m_positionsOffset = writer.Pos() - startOffset;
coding::FreezeVisitor<Writer> visitor(writer);
succinct::elias_fano(&builder).map(visitor);
}
{
header.m_deltasOffset = m_writer.Pos();
m_writer.Write(deltas.data(), deltas.size());
header.m_endOffset = m_writer.Pos();
header.m_deltasOffset = writer.Pos() - startOffset;
writer.Write(deltas.data(), deltas.size());
header.m_endOffset = writer.Pos() - startOffset;
}
int64_t const endOffset = m_writer.Pos();
int64_t const endOffset = writer.Pos();
m_writer.Seek(startOffset);
header.Write(m_writer);
m_writer.Seek(endOffset);
}
void CentersTableBuilder::Put(uint32_t featureId, m2::PointD const & center)
{
if (!m_ids.empty())
CHECK_LESS(m_ids.back(), featureId, ());
m_centers.push_back(PointD2PointU(center, m_codingParams.GetCoordBits()));
m_ids.push_back(featureId);
writer.Seek(startOffset);
header.Write(writer);
writer.Seek(endOffset);
}
} // namespace search

View file

@ -1,19 +1,17 @@
#pragma once
#include "indexer/coding_params.hpp"
#include "geometry/point2d.hpp"
#include "std/cstdint.hpp"
#include "std/unique_ptr.hpp"
#include "std/vector.hpp"
class FilesContainerR;
class Reader;
class Writer;
namespace serial
{
class CodingParams;
}
namespace search
{
// A wrapper class around serialized centers-table.
@ -64,15 +62,16 @@ private:
class CentersTableBuilder
{
public:
CentersTableBuilder(Writer & writer, serial::CodingParams const & codingParams);
~CentersTableBuilder();
inline void SetCodingParams(serial::CodingParams const & codingParams)
{
m_codingParams = codingParams;
}
void Put(uint32_t featureId, m2::PointD const & center);
void Freeze(Writer & writer) const;
private:
Writer & m_writer;
serial::CodingParams const & m_codingParams;
serial::CodingParams m_codingParams;
vector<m2::PointU> m_centers;
vector<uint32_t> m_ids;

View file

@ -43,11 +43,14 @@ UNIT_CLASS_TEST(CentersTableTest, Smoke)
TBuffer buffer;
{
MemWriter<TBuffer> writer(buffer);
CentersTableBuilder builder(writer, codingParams);
CentersTableBuilder builder;
builder.SetCodingParams(codingParams);
fv.GetVector().ForEach(
[&](FeatureType & ft, uint32_t id) { builder.Put(id, feature::GetCenter(ft)); });
MemWriter<TBuffer> writer(buffer);
builder.Freeze(writer);
}
{
@ -75,10 +78,14 @@ UNIT_CLASS_TEST(CentersTableTest, Subset)
TBuffer buffer;
{
MemWriter<TBuffer> writer(buffer);
CentersTableBuilder builder(writer, codingParams);
CentersTableBuilder builder;
builder.SetCodingParams(codingParams);
for (auto const & feature : features)
builder.Put(feature.first, feature.second);
MemWriter<TBuffer> writer(buffer);
builder.Freeze(writer);
}
{

View file

@ -20,6 +20,8 @@ MwmTraits::HouseToStreetTableFormat MwmTraits::GetHouseToStreetTableFormat() con
return HouseToStreetTableFormat::Fixed3BitsDDVector;
}
bool MwmTraits::HasOffsetsTable() const { return m_versionFormat >= version::Format::v6; }
string DebugPrint(MwmTraits::SearchIndexFormat format)
{
switch (format)

View file

@ -44,6 +44,8 @@ public:
HouseToStreetTableFormat GetHouseToStreetTableFormat() const;
bool HasOffsetsTable() const;
private:
version::Format m_versionFormat;
};

View file

@ -0,0 +1,48 @@
#include "search/lazy_centers_table.hpp"
#include "indexer/index.hpp"
#include "defines.hpp"
namespace search
{
LazyCentersTable::LazyCentersTable(MwmValue & value)
: m_value(value)
, m_state(STATE_NOT_LOADED)
, m_reader(unique_ptr<ModelReader>())
{
}
void LazyCentersTable::EnsureTableLoaded()
{
if (m_state != STATE_NOT_LOADED)
return;
if (!m_value.m_cont.IsExist(CENTERS_FILE_TAG))
{
m_state = STATE_FAILED;
return;
}
m_reader = m_value.m_cont.GetReader(CENTERS_FILE_TAG);
if (!m_reader.GetPtr())
{
m_state = STATE_FAILED;
return;
}
m_table = CentersTable::Load(*m_reader.GetPtr(), m_value.GetHeader().GetDefCodingParams());
if (m_table)
m_state = STATE_LOADED;
else
m_state = STATE_FAILED;
}
bool LazyCentersTable::Get(uint32_t id, m2::PointD & center)
{
EnsureTableLoaded();
if (m_state != STATE_LOADED)
return false;
return m_table->Get(id, center);
}
} // namespace search

View file

@ -0,0 +1,40 @@
#pragma once
#include "indexer/centers_table.hpp"
#include "coding/file_container.hpp"
#include "geometry/point2d.hpp"
#include "std/unique_ptr.hpp"
class MwmValue;
namespace search
{
class LazyCentersTable
{
public:
enum State
{
STATE_NOT_LOADED,
STATE_LOADED,
STATE_FAILED
};
explicit LazyCentersTable(MwmValue & value);
inline State GetState() const { return m_state; }
void EnsureTableLoaded();
bool Get(uint32_t id, m2::PointD & center);
private:
MwmValue & m_value;
State m_state;
FilesContainerR::TReader m_reader;
unique_ptr<CentersTable> m_table;
};
} // namespace search

View file

@ -14,6 +14,7 @@ MwmContext::MwmContext(MwmSet::MwmHandle handle)
, m_value(*m_handle.GetValue<MwmValue>())
, m_vector(m_value.m_cont, m_value.GetHeader(), m_value.m_table.get())
, m_index(m_value.m_cont.GetReader(INDEX_FILE_TAG), m_value.m_factory)
, m_centers(m_value)
{
}
@ -44,5 +45,4 @@ bool MwmContext::GetStreetIndex(uint32_t houseId, uint32_t & streetId)
}
return m_houseToStreetTable->Get(houseId, streetId);
}
} // namespace search

View file

@ -1,6 +1,7 @@
#pragma once
#include "search/house_to_street_table.hpp"
#include "search/lazy_centers_table.hpp"
#include "indexer/features_vector.hpp"
#include "indexer/index.hpp"
@ -8,6 +9,8 @@
#include "base/macros.hpp"
#include "std/shared_ptr.hpp"
#include "std/string.hpp"
#include "std/unique_ptr.hpp"
class MwmValue;
@ -20,19 +23,9 @@ void CoverRect(m2::RectD const & rect, int scale, covering::IntervalsT & result)
/// Now it duplicates "Index" functionality.
class MwmContext
{
public:
MwmSet::MwmHandle m_handle;
MwmValue & m_value;
private:
FeaturesVector m_vector;
ScaleIndex<ModelReaderPtr> m_index;
unique_ptr<HouseToStreetTable> m_houseToStreetTable;
public:
explicit MwmContext(MwmSet::MwmHandle handle);
inline bool IsAlive() const { return m_handle.IsAlive(); }
inline MwmSet::MwmId const & GetId() const { return m_handle.GetId(); }
inline string const & GetName() const { return GetInfo()->GetCountryName(); }
inline shared_ptr<MwmInfo> const & GetInfo() const { return GetId().GetInfo(); }
@ -78,6 +71,14 @@ public:
bool GetStreetIndex(uint32_t houseId, uint32_t & streetId);
inline bool GetCenter(uint32_t index, m2::PointD & center)
{
return m_centers.Get(index, center);
}
MwmSet::MwmHandle m_handle;
MwmValue & m_value;
private:
osm::Editor::FeatureStatus GetEditedStatus(uint32_t index) const
{
@ -98,6 +99,11 @@ private:
i.first, i.second, scale);
}
FeaturesVector m_vector;
ScaleIndex<ModelReaderPtr> m_index;
unique_ptr<HouseToStreetTable> m_houseToStreetTable;
LazyCentersTable m_centers;
DISALLOW_COPY_AND_MOVE(MwmContext);
};
} // namespace search

View file

@ -1,6 +1,7 @@
#include "search/pre_ranker.hpp"
#include "search/dummy_rank_table.hpp"
#include "search/lazy_centers_table.hpp"
#include "search/pre_ranking_info.hpp"
#include "indexer/mwm_set.hpp"
@ -16,8 +17,6 @@ namespace search
{
namespace
{
size_t const kBatchSize = 100;
struct LessFeatureID
{
using TValue = PreResult1;
@ -64,7 +63,13 @@ void PreRanker::FillMissingFieldsInPreResults()
{
MwmSet::MwmId mwmId;
MwmSet::MwmHandle mwmHandle;
unique_ptr<RankTable> rankTable = make_unique<DummyRankTable>();
unique_ptr<RankTable> ranks = make_unique<DummyRankTable>();
unique_ptr<LazyCentersTable> centers;
bool const fillCenters = (Size() > BatchSize());
if (fillCenters)
m_pivotFeatures.SetPosition(m_params.m_accuratePivotCenter, m_params.m_scale);
ForEach([&](PreResult1 & r) {
FeatureID const & id = r.GetId();
@ -73,27 +78,32 @@ void PreRanker::FillMissingFieldsInPreResults()
{
mwmId = id.m_mwmId;
mwmHandle = m_index.GetMwmHandleById(mwmId);
rankTable.reset();
ranks.reset();
centers.reset();
if (mwmHandle.IsAlive())
{
rankTable = RankTable::Load(mwmHandle.GetValue<MwmValue>()->m_cont);
ranks = RankTable::Load(mwmHandle.GetValue<MwmValue>()->m_cont);
centers = make_unique<LazyCentersTable>(*mwmHandle.GetValue<MwmValue>());
}
if (!rankTable)
rankTable = make_unique<DummyRankTable>();
if (!ranks)
ranks = make_unique<DummyRankTable>();
}
info.m_rank = rankTable->Get(id.m_index);
});
info.m_rank = ranks->Get(id.m_index);
if (Size() <= kBatchSize)
return;
m_pivotFeatures.SetPosition(m_params.m_accuratePivotCenter, m_params.m_scale);
ForEach([&](PreResult1 & r) {
FeatureID const & id = r.GetId();
PreRankingInfo & info = r.GetInfo();
info.m_distanceToPivot = m_pivotFeatures.GetDistanceToFeatureMeters(id);
if (fillCenters)
{
m2::PointD center;
if (centers && centers->Get(id.m_index, center))
{
info.m_distanceToPivot =
MercatorBounds::DistanceOnEarth(m_params.m_accuratePivotCenter, center);
}
else
{
info.m_distanceToPivot = m_pivotFeatures.GetDistanceToFeatureMeters(id);
}
}
});
}
@ -108,7 +118,7 @@ void PreRanker::Filter(bool viewportSearch)
sort(m_results.begin(), m_results.end(), &PreResult1::LessDistance);
if (m_results.size() > kBatchSize)
if (m_results.size() > BatchSize())
{
// Priority is some kind of distance from the viewport or
// position, therefore if we have a bunch of results with the same
@ -117,15 +127,15 @@ void PreRanker::Filter(bool viewportSearch)
// feature id) this code randomly selects tail of the
// sorted-by-priority list of pre-results.
double const last = m_results[kBatchSize - 1].GetDistance();
double const last = m_results[BatchSize()].GetDistance();
auto b = m_results.begin() + kBatchSize - 1;
auto b = m_results.begin() + BatchSize();
for (; b != m_results.begin() && b->GetDistance() == last; --b)
;
if (b->GetDistance() != last)
++b;
auto e = m_results.begin() + kBatchSize;
auto e = m_results.begin() + BatchSize();
for (; e != m_results.end() && e->GetDistance() == last; ++e)
;
@ -141,11 +151,11 @@ void PreRanker::Filter(bool viewportSearch)
minstd_rand engine;
shuffle(b, e, engine);
}
filtered.insert(m_results.begin(), m_results.begin() + min(m_results.size(), kBatchSize));
filtered.insert(m_results.begin(), m_results.begin() + min(m_results.size(), BatchSize()));
if (!viewportSearch)
{
size_t n = min(m_results.size(), kBatchSize);
size_t n = min(m_results.size(), BatchSize());
nth_element(m_results.begin(), m_results.begin() + n, m_results.end(), &PreResult1::LessRank);
filtered.insert(m_results.begin(), m_results.begin() + n);
}

View file

@ -32,6 +32,8 @@ public:
// compute the distance from a feature to the pivot.
m2::PointD m_accuratePivotCenter = m2::PointD(0, 0);
int m_scale = 0;
size_t m_batchSize = 100;
};
PreRanker(Index const & index, Ranker & ranker, size_t limit);
@ -39,10 +41,6 @@ public:
void Init(Params const & params);
inline void SetViewportSearch(bool viewportSearch) { m_viewportSearch = viewportSearch; }
inline void SetAccuratePivotCenter(m2::PointD const & center)
{
m_params.m_accuratePivotCenter = center;
}
template <typename... TArgs>
void Emplace(TArgs &&... args)
@ -63,6 +61,7 @@ public:
void UpdateResults(bool lastUpdate);
inline size_t Size() const { return m_results.size(); }
inline size_t BatchSize() const { return m_params.m_batchSize; }
inline size_t NumSentResults() const { return m_numSentResults; }
inline size_t Limit() const { return m_limit; }

View file

@ -70,14 +70,10 @@ public:
Ranker(Index const & index, storage::CountryInfoGetter const & infoGetter,
CategoriesHolder const & categories, vector<Suggest> const & suggests,
my::Cancellable const & cancellable);
virtual ~Ranker() = default;
void Init(Params const & params, Geocoder::Params const & geocoderParams);
inline void SetAccuratePivotCenter(m2::PointD const & center)
{
m_params.m_accuratePivotCenter = center;
}
bool IsResultExists(PreResult2 const & p, vector<IndexedValue> const & values);
void MakePreResult2(Geocoder::Params const & params, vector<IndexedValue> & cont,
@ -93,11 +89,12 @@ public:
void GetBestMatchName(FeatureType const & f, string & name) const;
void ProcessSuggestions(vector<IndexedValue> & vec, Results & res) const;
Results & GetResults() { return m_results; }
void UpdateResults(bool lastUpdate);
virtual void SetPreResults1(vector<PreResult1> && preResults1) { m_preResults1 = move(preResults1); }
virtual void UpdateResults(bool lastUpdate);
inline Results & GetResults() { return m_results; }
inline void FlushResults() { UpdateResults(true /* lastUpdate */); }
void SetPreResults1(vector<PreResult1> && preResults1) { m_preResults1 = move(preResults1); }
void ClearCaches();
inline void SetLocalityFinderLanguage(int8_t code) { m_locality.SetLanguage(code); }

View file

@ -34,6 +34,7 @@ HEADERS += \
keyword_lang_matcher.hpp \
keyword_matcher.hpp \
latlon_match.hpp \
lazy_centers_table.hpp \
locality.hpp \
locality_finder.hpp \
locality_scorer.hpp \
@ -89,6 +90,7 @@ SOURCES += \
keyword_lang_matcher.cpp \
keyword_matcher.cpp \
latlon_match.cpp \
lazy_centers_table.cpp \
locality.cpp \
locality_finder.cpp \
locality_scorer.cpp \

View file

@ -0,0 +1,171 @@
#include "testing/testing.hpp"
#include "search/intermediate_result.hpp"
#include "search/model.hpp"
#include "search/pre_ranker.hpp"
#include "search/ranker.hpp"
#include "search/search_integration_tests/helpers.hpp"
#include "search/search_tests_support/test_search_engine.hpp"
#include "search/suggest.hpp"
#include "indexer/categories_holder.hpp"
#include "indexer/feature_algo.hpp"
#include "indexer/features_vector.hpp"
#include "indexer/mwm_set.hpp"
#include "indexer/scales.hpp"
#include "generator/generator_tests_support/test_feature.hpp"
#include "generator/generator_tests_support/test_mwm_builder.hpp"
#include "geometry/mercator.hpp"
#include "platform/country_defines.hpp"
#include "platform/local_country_file.hpp"
#include "base/assert.hpp"
#include "base/cancellable.hpp"
#include "base/limited_priority_queue.hpp"
#include "base/math.hpp"
#include "base/stl_add.hpp"
#include "std/algorithm.hpp"
#include "std/iterator.hpp"
#include "std/vector.hpp"
using namespace generator::tests_support;
using namespace search::tests_support;
namespace search
{
namespace
{
// Returns the boundary such that at least |size| elements from
// |distance| are less than or equal to the boundary.
double GetBoundary(vector<double> const & distances, size_t size)
{
CHECK_LESS_OR_EQUAL(size, distances.size(), ());
my::limited_priority_queue<double> queue(size);
for (auto const & distance : distances)
queue.push(distance);
return queue.empty() ? 0.0 : queue.top();
}
class TestRanker : public Ranker
{
public:
TestRanker(TestSearchEngine & engine, vector<Suggest> const & suggests,
my::Cancellable const & cancellable, vector<PreResult1> & results)
: Ranker(static_cast<Index const &>(engine), engine.GetCountryInfoGetter(),
GetDefaultCategories(), suggests, cancellable)
, m_results(results)
{
}
inline bool Finished() const { return m_finished; }
// Ranker overrides:
void SetPreResults1(vector<PreResult1> && preResults1) override
{
CHECK(!Finished(), ());
move(preResults1.begin(), preResults1.end(), back_inserter(m_results));
preResults1.clear();
}
void UpdateResults(bool lastUpdate) override
{
CHECK(!Finished(), ());
if (lastUpdate)
m_finished = true;
}
private:
vector<PreResult1> & m_results;
bool m_finished = false;
};
class PreRankerTest : public SearchTest
{
public:
vector<Suggest> m_suggests;
my::Cancellable m_cancellable;
};
UNIT_CLASS_TEST(PreRankerTest, Smoke)
{
// Tests that PreRanker correctly computes distances to pivot when
// number of results is larger than batch size, and that PreRanker
// emits results nearest to the pivot.
m2::PointD const kPivot(0.5, 0.5);
size_t const kBatchSize = 50;
vector<TestPOI> pois;
for (int x = -5; x <= 5; ++x)
{
for (int y = -5; y <= 5; ++y)
{
pois.emplace_back(m2::PointD(x, y), "cafe", "en");
pois.back().SetTypes({{"amenity", "cafe"}});
}
}
TEST_LESS(kBatchSize, pois.size(), ());
auto mwmId = BuildCountry("Cafeland", [&](TestMwmBuilder & builder) {
for (auto const & poi : pois)
builder.Add(poi);
});
vector<PreResult1> results;
TestRanker ranker(m_engine, m_suggests, m_cancellable, results);
PreRanker preRanker(m_engine, ranker, pois.size());
PreRanker::Params params;
params.m_accuratePivotCenter = kPivot;
params.m_scale = scales::GetUpperScale();
params.m_batchSize = kBatchSize;
preRanker.Init(params);
preRanker.SetViewportSearch(true);
vector<double> distances(pois.size());
vector<bool> emit(pois.size());
FeaturesVectorTest fv(mwmId.GetInfo()->GetLocalFile().GetPath(MapOptions::Map));
fv.GetVector().ForEach([&](FeatureType & ft, uint32_t index) {
FeatureID id(mwmId, index);
PreRankingInfo info;
info.m_startToken = 0;
info.m_endToken = 1;
info.m_searchType = SearchModel::SEARCH_TYPE_POI;
preRanker.Emplace(id, info);
TEST_LESS(index, pois.size(), ());
distances[index] = MercatorBounds::DistanceOnEarth(feature::GetCenter(ft), kPivot);
emit[index] = true;
});
preRanker.UpdateResults(true /* lastUpdate */);
TEST(all_of(emit.begin(), emit.end(), IdFunctor()), (emit));
TEST(ranker.Finished(), ());
TEST_EQUAL(results.size(), kBatchSize, ());
double const boundary = GetBoundary(distances, kBatchSize);
vector<bool> checked(pois.size());
for (size_t i = 0; i < results.size(); ++i)
{
size_t const index = results[i].GetId().m_index;
TEST_LESS(index, pois.size(), ());
TEST(!checked[index], (index));
TEST_LESS_OR_EQUAL(results[i].GetDistance(), boundary, ());
TEST(my::AlmostEqualAbs(distances[index], results[i].GetDistance(), 1e-3),
(distances[index], results[i].GetDistance()));
checked[index] = true;
}
}
} // namespace
} // namespace search

View file

@ -492,7 +492,6 @@ UNIT_CLASS_TEST(ProcessorTest, TestPostcodes)
// Tests that postcode is added to the search index.
{
MwmContext context(m_engine.GetMwmHandleById(countryId));
TEST(context.IsAlive(), ());
my::Cancellable cancellable;
QueryParams params;

View file

@ -21,6 +21,7 @@ SOURCES += \
../../testing/testingmain.cpp \
generate_tests.cpp \
helpers.cpp \
pre_ranker_test.cpp \
processor_test.cpp \
smoke_test.cpp \