forked from organicmaps/organicmaps
Merge pull request #3891 from ygorshenin/use-centers-table
[search] Added centers table usage.
This commit is contained in:
commit
bedde4511c
22 changed files with 460 additions and 88 deletions
|
@ -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"
|
||||
|
|
69
generator/centers_table_builder.cpp
Normal file
69
generator/centers_table_builder.cpp
Normal 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
|
13
generator/centers_table_builder.hpp
Normal file
13
generator/centers_table_builder.hpp
Normal 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
|
|
@ -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 \
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -44,6 +44,8 @@ public:
|
|||
|
||||
HouseToStreetTableFormat GetHouseToStreetTableFormat() const;
|
||||
|
||||
bool HasOffsetsTable() const;
|
||||
|
||||
private:
|
||||
version::Format m_versionFormat;
|
||||
};
|
||||
|
|
48
search/lazy_centers_table.cpp
Normal file
48
search/lazy_centers_table.cpp
Normal 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
|
40
search/lazy_centers_table.hpp
Normal file
40
search/lazy_centers_table.hpp
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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 \
|
||||
|
|
171
search/search_integration_tests/pre_ranker_test.cpp
Normal file
171
search/search_integration_tests/pre_ranker_test.cpp
Normal 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
|
|
@ -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;
|
||||
|
|
|
@ -21,6 +21,7 @@ SOURCES += \
|
|||
../../testing/testingmain.cpp \
|
||||
generate_tests.cpp \
|
||||
helpers.cpp \
|
||||
pre_ranker_test.cpp \
|
||||
processor_test.cpp \
|
||||
smoke_test.cpp \
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue