[search] Take into account user’s edits.

This commit is contained in:
vng 2016-03-01 18:21:23 +03:00 committed by Sergey Yershov
parent d584749945
commit b85fe49049
7 changed files with 158 additions and 102 deletions

View file

@ -6,6 +6,8 @@
#include "search_index_values.hpp"
#include "search_trie.hpp"
#include "v2/mwm_context.hpp"
#include "indexer/feature.hpp"
#include "indexer/feature_algo.hpp"
#include "indexer/index.hpp"
@ -50,13 +52,6 @@ unique_ptr<coding::CompressedBitVector> SortFeaturesAndBuildCBV(vector<uint64_t>
return coding::CompressedBitVectorBuilder::FromBitPositions(move(features));
}
void CoverRect(m2::RectD const & rect, int scale, covering::IntervalsT & result)
{
covering::CoveringGetter covering(rect, covering::ViewportWithLowLevels);
auto const & intervals = covering.Get(scale);
result.insert(result.end(), intervals.begin(), intervals.end());
}
bool MatchFeatureByName(FeatureType const & ft, SearchQueryParams const & params)
{
bool matched = false;
@ -147,27 +142,19 @@ unique_ptr<coding::CompressedBitVector> RetrieveAddressFeaturesImpl(
// Retrieves from the geometry index corresponding to handle all
// features from |coverage|.
unique_ptr<coding::CompressedBitVector> RetrieveGeometryFeaturesImpl(
MwmSet::MwmId const & id, MwmValue & value, my::Cancellable const & cancellable,
v2::MwmContext const & context, my::Cancellable const & cancellable,
covering::IntervalsT const & coverage, int scale)
{
// TODO(AlexZ): Also add created features.
auto const deleted = Editor::Instance().GetFeaturesByStatus(id, Editor::FeatureStatus::Deleted);
// TODO (@y, @m): remove this code as soon as geometry index will
// have native support for bit vectors.
vector<uint64_t> features;
uint32_t counter = 0;
auto const collector = [&](uint64_t featureId)
vector<uint64_t> features;
context.ForEachIndex(coverage, scale, [&](uint64_t featureId)
{
if (binary_search(deleted.begin(), deleted.end(), static_cast<uint32_t>(featureId)))
return;
if ((++counter & 0xFF) == 0)
BailIfCancelled(cancellable);
features.push_back(featureId);
};
});
ScaleIndex<ModelReaderPtr> index(value.m_cont.GetReader(INDEX_FILE_TAG), value.m_factory);
for (auto const & interval : coverage)
index.ForEachInIntervalAndScale(collector, interval.first, interval.second, scale);
return SortFeaturesAndBuildCBV(move(features));
}
@ -295,10 +282,14 @@ public:
if (m_prevScale < 0)
{
covering::IntervalsT coverage;
CoverRect(currViewport, m_coverageScale, coverage);
geometryFeatures =
RetrieveGeometryFeaturesImpl(m_handle.GetId(), *m_handle.GetValue<MwmValue>(),
cancellable, coverage, m_coverageScale);
v2::CoverRect(currViewport, m_coverageScale, coverage);
/// @todo I didn't find a better solution for now to share MwmHandle.
v2::MwmContext context(move(m_handle));
geometryFeatures = RetrieveGeometryFeaturesImpl(context, cancellable,
coverage, m_coverageScale);
m_handle = move(context.m_handle);
for (auto const & interval : coverage)
m_visited.Add(interval);
}
@ -313,10 +304,10 @@ public:
m2::RectD d(a.LeftBottom(), c.LeftBottom());
covering::IntervalsT coverage;
CoverRect(a, m_coverageScale, coverage);
CoverRect(b, m_coverageScale, coverage);
CoverRect(c, m_coverageScale, coverage);
CoverRect(d, m_coverageScale, coverage);
v2::CoverRect(a, m_coverageScale, coverage);
v2::CoverRect(b, m_coverageScale, coverage);
v2::CoverRect(c, m_coverageScale, coverage);
v2::CoverRect(d, m_coverageScale, coverage);
my::SortUnique(coverage);
coverage = covering::SortAndMergeIntervals(coverage);
@ -331,9 +322,11 @@ public:
for (auto const & interval : coverage)
m_visited.SubtractFrom(interval, reducedCoverage);
geometryFeatures =
RetrieveGeometryFeaturesImpl(m_handle.GetId(), *m_handle.GetValue<MwmValue>(),
cancellable, reducedCoverage, m_coverageScale);
/// @todo I didn't find a better solution for now to share MwmHandle.
v2::MwmContext context(move(m_handle));
geometryFeatures = RetrieveGeometryFeaturesImpl(context, cancellable,
reducedCoverage, m_coverageScale);
m_handle = move(context.m_handle);
for (auto const & interval : reducedCoverage)
m_visited.Add(interval);
@ -454,12 +447,12 @@ unique_ptr<coding::CompressedBitVector> Retrieval::RetrieveAddressFeatures(
// static
unique_ptr<coding::CompressedBitVector> Retrieval::RetrieveGeometryFeatures(
MwmSet::MwmId const & id, MwmValue & value, my::Cancellable const & cancellable,
v2::MwmContext const & context, my::Cancellable const & cancellable,
m2::RectD const & rect, int scale)
{
covering::IntervalsT coverage;
CoverRect(rect, scale, coverage);
return RetrieveGeometryFeaturesImpl(id, value, cancellable, coverage, scale);
v2::CoverRect(rect, scale, coverage);
return RetrieveGeometryFeaturesImpl(context, cancellable, coverage, scale);
}
void Retrieval::Init(Index & index, vector<shared_ptr<MwmInfo>> const & infos,

View file

@ -23,6 +23,8 @@ class CompressedBitVector;
namespace search
{
namespace v2 { struct MwmContext; }
class Retrieval : public my::Cancellable
{
public:
@ -112,7 +114,7 @@ public:
// Retrieves from the geometry index corresponding to |value| all features belonging to |rect|.
WARN_UNUSED_RESULT static unique_ptr<coding::CompressedBitVector> RetrieveGeometryFeatures(
MwmSet::MwmId const & id, MwmValue & value, my::Cancellable const & cancellable,
v2::MwmContext const & context, my::Cancellable const & cancellable,
m2::RectD const & rect, int scale);
// Initializes retrieval process, sets up internal state, takes all

View file

@ -46,78 +46,97 @@ void FeaturesLayerMatcher::OnQueryFinished()
uint32_t FeaturesLayerMatcher::GetMatchingStreet(uint32_t houseId)
{
auto entry = m_matchingStreetsCache.Get(houseId);
if (!entry.second)
return entry.first;
FeatureType houseFeature;
GetByIndex(houseId, houseFeature);
entry.first = GetMatchingStreetImpl(houseId, houseFeature);
return entry.first;
FeatureType feature;
return GetMatchingStreetImpl(houseId, feature);
}
uint32_t FeaturesLayerMatcher::GetMatchingStreet(uint32_t houseId, FeatureType & houseFeature)
{
auto entry = m_matchingStreetsCache.Get(houseId);
if (!entry.second)
return entry.first;
entry.first = GetMatchingStreetImpl(houseId, houseFeature);
return entry.first;
return GetMatchingStreetImpl(houseId, houseFeature);
}
FeaturesLayerMatcher::TStreets const &
FeaturesLayerMatcher::GetNearbyStreets(uint32_t featureId)
{
auto entry = m_nearbyStreetsCache.Get(featureId);
if (!entry.second)
return entry.first;
FeatureType feature;
GetByIndex(featureId, feature);
GetNearbyStreetsImpl(feature, entry.first);
return entry.first;
return GetNearbyStreetsImpl(featureId, feature);
}
FeaturesLayerMatcher::TStreets const &
FeaturesLayerMatcher::GetNearbyStreets(uint32_t featureId, FeatureType & feature)
{
return GetNearbyStreetsImpl(featureId, feature);
}
FeaturesLayerMatcher::TStreets const &
FeaturesLayerMatcher::GetNearbyStreetsImpl(uint32_t featureId, FeatureType & feature)
{
auto entry = m_nearbyStreetsCache.Get(featureId);
if (!entry.second)
return entry.first;
GetNearbyStreetsImpl(feature, entry.first);
return entry.first;
}
if (!feature.GetID().IsValid())
GetByIndex(featureId, feature);
void FeaturesLayerMatcher::GetNearbyStreetsImpl(FeatureType & feature, TStreets & streets)
{
auto & streets = entry.first;
m_reverseGeocoder.GetNearbyStreets(feature, streets);
for (size_t i = 0; i < streets.size(); ++i)
{
if (streets[i].m_distanceMeters > ReverseGeocoder::kLookupRadiusM)
{
streets.resize(i);
return;
break;
}
}
return streets;
}
uint32_t FeaturesLayerMatcher::GetMatchingStreetImpl(uint32_t houseId, FeatureType & houseFeature)
{
auto const & streets = GetNearbyStreets(houseId, houseFeature);
// Check if this feature is modified - the logic will be different.
string streetName;
bool const edited = osm::Editor::Instance().GetEditedFeatureStreet(houseFeature.GetID(), streetName);
uint32_t index;
if (m_houseToStreetTable->Get(houseId, index) && index < streets.size())
return streets[index].m_id.m_index;
// Check the cached result value.
auto entry = m_matchingStreetsCache.Get(houseId);
if (!edited && !entry.second)
return entry.first;
// Load feature if needed.
if (!houseFeature.GetID().IsValid())
GetByIndex(houseId, houseFeature);
// Get nearby streets and calculate the resulting index.
auto const & streets = GetNearbyStreets(houseId, houseFeature);
uint32_t & result = entry.first;
result = kInvalidId;
if (edited)
{
auto ret = find_if(streets.begin(), streets.end(), [&streetName](TStreet const & st)
{
return st.m_name == streetName;
});
if (ret != streets.end())
result = ret->m_id.m_index;
}
else
{
uint32_t index;
if (m_houseToStreetTable->Get(houseId, index) && index < streets.size())
result = streets[index].m_id.m_index;
}
// If there is no saved street for feature, assume that it's a nearest street if it's too close.
if (!streets.empty() && streets[0].m_distanceMeters < kMaxApproxStreetDistanceM)
return streets[0].m_id.m_index;
if (result == kInvalidId &&
!streets.empty() &&
streets[0].m_distanceMeters < kMaxApproxStreetDistanceM)
{
result = streets[0].m_id.m_index;
}
return kInvalidId;
return result;
}
} // namespace v2

View file

@ -325,11 +325,12 @@ private:
uint32_t GetMatchingStreet(uint32_t houseId, FeatureType & houseFeature);
uint32_t GetMatchingStreetImpl(uint32_t houseId, FeatureType & houseFeature);
using TStreets = vector<ReverseGeocoder::Street>;
using TStreet = ReverseGeocoder::Street;
using TStreets = vector<TStreet>;
TStreets const & GetNearbyStreets(uint32_t featureId);
TStreets const & GetNearbyStreets(uint32_t featureId, FeatureType & feature);
void GetNearbyStreetsImpl(FeatureType & feature, TStreets & streets);
TStreets const & GetNearbyStreetsImpl(uint32_t featureId, FeatureType & feature);
inline void GetByIndex(uint32_t id, FeatureType & ft) const
{

View file

@ -570,9 +570,8 @@ void Geocoder::GoImpl(vector<shared_ptr<MwmInfo>> & infos, bool inViewport)
unique_ptr<coding::CompressedBitVector> viewportCBV;
if (inViewport)
{
viewportCBV =
Retrieval::RetrieveGeometryFeatures(m_context->GetId(), m_context->m_value, cancellable,
m_params.m_viewport, m_params.m_scale);
viewportCBV = Retrieval::RetrieveGeometryFeatures(*m_context, cancellable,
m_params.m_viewport, m_params.m_scale);
}
PrepareAddressFeatures();
@ -1358,9 +1357,7 @@ coding::CompressedBitVector const * Geocoder::RetrieveGeometryFeatures(MwmContex
return v.m_cbv.get();
}
auto cbv = Retrieval::RetrieveGeometryFeatures(context.GetId(), context.m_value,
static_cast<my::Cancellable const &>(*this), rect,
m_params.m_scale);
auto cbv = Retrieval::RetrieveGeometryFeatures(context, *this, rect, m_params.m_scale);
auto const * result = cbv.get();
features.push_back({m2::Inflate(rect, kComparePoints, kComparePoints), move(cbv), id});

View file

@ -5,6 +5,14 @@ namespace search
{
namespace v2
{
void CoverRect(m2::RectD const & rect, int scale, covering::IntervalsT & result)
{
covering::CoveringGetter covering(rect, covering::ViewportWithLowLevels);
auto const & intervals = covering.Get(scale);
result.insert(result.end(), intervals.begin(), intervals.end());
}
MwmContext::MwmContext(MwmSet::MwmHandle handle)
: m_handle(move(handle))
, m_value(*m_handle.GetValue<MwmValue>())
@ -13,5 +21,11 @@ MwmContext::MwmContext(MwmSet::MwmHandle handle)
{
}
void MwmContext::GetFeature(uint32_t index, FeatureType & ft) const
{
m_vector.GetByIndex(index, ft);
ft.SetID(FeatureID(GetId(), index));
}
} // namespace v2
} // namespace search

View file

@ -12,9 +12,14 @@ namespace search
{
namespace v2
{
void CoverRect(m2::RectD const & rect, int scale, covering::IntervalsT & result);
/// @todo Move this class into "index" library and make it more generic.
/// Now it duplicates "Index" functionality.
struct MwmContext
{
MwmContext(MwmSet::MwmHandle handle);
explicit MwmContext(MwmSet::MwmHandle handle);
MwmSet::MwmHandle m_handle;
MwmValue & m_value;
@ -25,33 +30,58 @@ struct MwmContext
inline string const & GetName() const { return GetInfo()->GetCountryName(); }
inline shared_ptr<MwmInfo> const & GetInfo() const { return GetId().GetInfo(); }
template <class TFn> void ForEachFeature(m2::RectD const & rect, TFn && fn)
template <class TFn> void ForEachIndex(covering::IntervalsT const & intervals,
uint32_t scale, TFn && fn) const
{
feature::DataHeader const & header = m_value.GetHeader();
covering::CoveringGetter covering(rect, covering::ViewportWithLowLevels);
uint32_t const scale = header.GetLastScale();
covering::IntervalsT const & interval = covering.Get(scale);
CheckUniqueIndexes checkUnique(header.GetFormat() >= version::Format::v5);
for (auto const & i : interval)
ForEachIndexImpl(intervals, scale, [&](uint32_t index)
{
m_index.ForEachInIntervalAndScale([&](uint32_t index)
{
if (checkUnique(index))
{
FeatureType ft;
GetFeature(index, ft);
fn(ft);
}
}, i.first, i.second, scale);
}
if (GetEditedStatus(index) != osm::Editor::FeatureStatus::Deleted)
fn(index);
});
}
inline void GetFeature(uint32_t index, FeatureType & ft) const
template <class TFn> void ForEachFeature(m2::RectD const & rect, TFn && fn) const
{
m_vector.GetByIndex(index, ft);
ft.SetID(FeatureID(GetId(), index));
uint32_t const scale = m_value.GetHeader().GetLastScale();
covering::IntervalsT intervals;
CoverRect(rect, scale, intervals);
ForEachIndexImpl(intervals, scale,
[&](uint32_t index)
{
FeatureType ft;
switch (GetEditedStatus(index))
{
case osm::Editor::FeatureStatus::Deleted: return;
case osm::Editor::FeatureStatus::Modified:
VERIFY(osm::Editor::Instance().GetEditedFeature(GetId(), index, ft), ());
fn(ft);
return;
case osm::Editor::FeatureStatus::Created:
CHECK(false, ("Created features index should be generated."));
case osm::Editor::FeatureStatus::Untouched: break;
}
GetFeature(index, ft);
fn(ft);
});
}
void GetFeature(uint32_t index, FeatureType & ft) const;
private:
osm::Editor::FeatureStatus GetEditedStatus(uint32_t index) const
{
return osm::Editor::Instance().GetFeatureStatus(GetId(), index);
}
template <class TFn> void ForEachIndexImpl(covering::IntervalsT const & intervals,
uint32_t scale, TFn && fn) const
{
CheckUniqueIndexes checkUnique(m_value.GetHeader().GetFormat() >= version::Format::v5);
for (auto const & i : intervals)
m_index.ForEachInIntervalAndScale([&] (uint32_t index) { fn(index); }, i.first, i.second, scale);
}
DISALLOW_COPY_AND_MOVE(MwmContext);