diff --git a/search/retrieval.cpp b/search/retrieval.cpp index 20b476ac2f..2e94385d99 100644 --- a/search/retrieval.cpp +++ b/search/retrieval.cpp @@ -22,12 +22,7 @@ #include "coding/compressed_bit_vector.hpp" #include "coding/reader_wrapper.hpp" -#include "base/assert.hpp" -#include "base/stl_helpers.hpp" - #include "std/algorithm.hpp" -#include "std/cmath.hpp" -#include "std/limits.hpp" using osm::Editor; @@ -35,16 +30,6 @@ namespace search { namespace { -// A value used to represent maximum viewport scale. -double const kInfinity = numeric_limits::infinity(); - -// Maximum viewport scale level when we stop to expand viewport and -// simply return all rest features from mwms. -double const kMaxViewportScaleLevel = scales::GetUpperCountryScale(); - -// Upper bound on a number of features when fast path is used. -// Otherwise, slow path is used. -uint64_t constexpr kFastPathThreshold = 100; unique_ptr SortFeaturesAndBuildCBV(vector && features) { @@ -158,273 +143,11 @@ unique_ptr RetrieveGeometryFeaturesImpl( return SortFeaturesAndBuildCBV(move(features)); } -// This class represents a fast retrieval strategy. When number of -// matching features in an mwm is small, it is worth computing their -// centers explicitly, by loading geometry from mwm. -class FastPathStrategy : public Retrieval::Strategy -{ -public: - FastPathStrategy(Index const & index, MwmSet::MwmHandle & handle, m2::RectD const & viewport, - unique_ptr && addressFeatures) - : Strategy(handle, viewport), m_lastReported(0) - { - ASSERT(addressFeatures.get(), - ("Strategy must be initialized with valid address features set.")); - - m2::PointD const center = m_viewport.Center(); - - Index::FeaturesLoaderGuard loader(index, m_handle.GetId()); - coding::CompressedBitVectorEnumerator::ForEach( - *addressFeatures, [&](uint64_t featureId) - { - ASSERT_LESS_OR_EQUAL(featureId, numeric_limits::max(), ()); - FeatureType feature; - loader.GetFeatureByIndex(featureId, feature); - m_features.emplace_back(featureId, - feature::GetCenter(feature, FeatureType::WORST_GEOMETRY)); - }); - - // Order features by distance from the center of |viewport|. - sort(m_features.begin(), m_features.end(), - [¢er](pair const & lhs, pair const & rhs) - { - return lhs.second.SquareLength(center) < rhs.second.SquareLength(center); - }); - } - - // Retrieval::Strategy overrides: - bool RetrieveImpl(double scale, my::Cancellable const & /* cancellable */, - TCallback const & callback) override - { - m2::RectD viewport = m_viewport; - viewport.Scale(scale); - - vector features; - - ASSERT_LESS_OR_EQUAL(m_lastReported, m_features.size(), ()); - while (m_lastReported < m_features.size() && - viewport.IsPointInside(m_features[m_lastReported].second)) - { - features.push_back(m_features[m_lastReported].first); - ++m_lastReported; - } - - auto cbv = SortFeaturesAndBuildCBV(move(features)); - callback(*cbv); - - return true; - } - -private: - vector> m_features; - size_t m_lastReported; -}; - -// This class represents a slow retrieval strategy. It starts with -// initial viewport and iteratively scales it until whole mwm is -// covered by a scaled viewport. On each scale it retrieves features -// for a scaled viewport from a geometry index and then intersects -// them with features retrieved from search index. -class SlowPathStrategy : public Retrieval::Strategy -{ -public: - SlowPathStrategy(MwmSet::MwmHandle & handle, m2::RectD const & viewport, - SearchQueryParams const & params, - unique_ptr && addressFeatures) - : Strategy(handle, viewport) - , m_params(params) - , m_nonReported(move(addressFeatures)) - , m_coverageScale(0) - { - ASSERT(m_nonReported.get(), ("Strategy must be initialized with valid address features set.")); - - // No need to initialize slow path strategy when there are no - // features at all. - if (m_nonReported->PopCount() == 0) - return; - - auto * value = m_handle.GetValue(); - ASSERT(value, ()); - feature::DataHeader const & header = value->GetHeader(); - auto const scaleRange = header.GetScaleRange(); - m_coverageScale = min(max(m_params.m_scale, scaleRange.first), scaleRange.second); - m_bounds = header.GetBounds(); - } - - // Retrieval::Strategy overrides: - bool RetrieveImpl(double scale, my::Cancellable const & cancellable, - TCallback const & callback) override - { - m2::RectD currViewport = m_viewport; - currViewport.Scale(scale); - - // Early exit when scaled viewport does not intersect mwm bounds. - if (!currViewport.Intersect(m_bounds)) - return true; - - // Early exit when all features from this mwm were already - // reported. - if (!m_nonReported || m_nonReported->PopCount() == 0) - return true; - - unique_ptr geometryFeatures; - - // Early exit when whole mwm is inside scaled viewport. - if (currViewport.IsRectInside(m_bounds)) - { - geometryFeatures.swap(m_nonReported); - callback(*geometryFeatures); - return true; - } - - try - { - if (m_prevScale < 0) - { - covering::IntervalsT coverage; - 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); - } - else - { - m2::RectD prevViewport = m_viewport; - prevViewport.Scale(m_prevScale); - - m2::RectD a(currViewport.LeftTop(), prevViewport.RightTop()); - m2::RectD c(currViewport.RightBottom(), prevViewport.LeftBottom()); - m2::RectD b(a.RightTop(), c.RightTop()); - m2::RectD d(a.LeftBottom(), c.LeftBottom()); - - covering::IntervalsT 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); - coverage.erase(remove_if(coverage.begin(), coverage.end(), - [this](covering::IntervalT const & interval) - { - return m_visited.Elems().count(interval) != 0; - }), - coverage.end()); - - covering::IntervalsT reducedCoverage; - for (auto const & interval : coverage) - m_visited.SubtractFrom(interval, reducedCoverage); - - /// @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); - } - } - catch (CancelException &) - { - return false; - } - - auto toReport = coding::CompressedBitVector::Intersect(*m_nonReported, *geometryFeatures); - m_nonReported = coding::CompressedBitVector::Subtract(*m_nonReported, *toReport); - callback(*toReport); - return true; - } - -private: - SearchQueryParams const & m_params; - - unique_ptr m_nonReported; - - // This set is used to accumulate all read intervals from mwm and - // prevent further reads from the same offsets. - my::IntervalSet m_visited; - - m2::RectD m_bounds; - int m_coverageScale; -}; } // namespace -// Retrieval::Limits ------------------------------------------------------------------------------- -Retrieval::Limits::Limits() - : m_maxNumFeatures(0) - , m_maxViewportScale(0.0) - , m_maxNumFeaturesSet(false) - , m_maxViewportScaleSet(false) - , m_searchInWorld(false) +namespace v2 { -} - -void Retrieval::Limits::SetMaxNumFeatures(uint64_t maxNumFeatures) -{ - m_maxNumFeatures = maxNumFeatures; - m_maxNumFeaturesSet = true; -} - -uint64_t Retrieval::Limits::GetMaxNumFeatures() const -{ - ASSERT(IsMaxNumFeaturesSet(), ()); - return m_maxNumFeatures; -} - -void Retrieval::Limits::SetMaxViewportScale(double maxViewportScale) -{ - m_maxViewportScale = maxViewportScale; - m_maxViewportScaleSet = true; -} - -double Retrieval::Limits::GetMaxViewportScale() const -{ - ASSERT(IsMaxViewportScaleSet(), ()); - return m_maxViewportScale; -} - -// Retrieval::Strategy ----------------------------------------------------------------------------- -Retrieval::Strategy::Strategy(MwmSet::MwmHandle & handle, m2::RectD const & viewport) - : m_handle(handle), m_viewport(viewport), m_prevScale(-numeric_limits::epsilon()) -{ -} - -bool Retrieval::Strategy::Retrieve(double scale, my::Cancellable const & cancellable, - TCallback const & callback) -{ - ASSERT_GREATER(scale, m_prevScale, ("Invariant violation.")); - bool result = RetrieveImpl(scale, cancellable, callback); - m_prevScale = scale; - return result; -} - -// Retrieval::Bucket ------------------------------------------------------------------------------- -Retrieval::Bucket::Bucket(MwmSet::MwmHandle && handle) - : m_handle(move(handle)) - , m_featuresReported(0) - , m_numAddressFeatures(0) - , m_intersectsWithViewport(false) - , m_finished(false) -{ - auto * value = m_handle.GetValue(); - ASSERT(value, ()); - feature::DataHeader const & header = value->GetHeader(); - m_bounds = header.GetBounds(); -} - -// Retrieval --------------------------------------------------------------------------------------- -Retrieval::Retrieval() : m_index(nullptr), m_featuresReported(0) {} - -// static -unique_ptr Retrieval::RetrieveAddressFeatures( +unique_ptr RetrieveAddressFeatures( MwmSet::MwmId const & id, MwmValue & value, my::Cancellable const & cancellable, SearchQueryParams const & params) { @@ -445,9 +168,8 @@ unique_ptr Retrieval::RetrieveAddressFeatures( return unique_ptr(); } -// static -unique_ptr Retrieval::RetrieveGeometryFeatures( - v2::MwmContext const & context, my::Cancellable const & cancellable, +unique_ptr RetrieveGeometryFeatures( + MwmContext const & context, my::Cancellable const & cancellable, m2::RectD const & rect, int scale) { covering::IntervalsT coverage; @@ -455,196 +177,5 @@ unique_ptr Retrieval::RetrieveGeometryFeatures( return RetrieveGeometryFeaturesImpl(context, cancellable, coverage, scale); } -void Retrieval::Init(Index & index, vector> const & infos, - m2::RectD const & viewport, SearchQueryParams const & params, - Limits const & limits) -{ - Release(); - - m_index = &index; - m_viewport = viewport; - m_params = params; - m_limits = limits; - m_featuresReported = 0; - - for (auto const & info : infos) - { - MwmSet::MwmHandle handle = index.GetMwmHandleById(MwmSet::MwmId(info)); - if (!handle.IsAlive()) - continue; - auto * value = handle.GetValue(); - if (!value || !value->m_cont.IsExist(SEARCH_INDEX_FILE_TAG) || - !value->m_cont.IsExist(INDEX_FILE_TAG)) - { - continue; - } - bool const isWorld = value->GetHeader().GetType() == feature::DataHeader::world; - if (isWorld && !m_limits.GetSearchInWorld()) - continue; - m_buckets.emplace_back(move(handle)); - } -} - -void Retrieval::Go(Callback & callback) -{ - static double const kViewportScaleMul = sqrt(2.0); - - double currScale = 1.0; - while (true) - { - if (IsCancelled()) - break; - - double reducedScale = currScale; - if (m_limits.IsMaxViewportScaleSet() && reducedScale >= m_limits.GetMaxViewportScale()) - reducedScale = m_limits.GetMaxViewportScale(); - - for (auto & bucket : m_buckets) - { - if (!RetrieveForScale(bucket, reducedScale, callback)) - break; - } - - if (Finished()) - break; - - if (m_limits.IsMaxViewportScaleSet() && reducedScale >= m_limits.GetMaxViewportScale()) - break; - if (m_limits.IsMaxNumFeaturesSet() && m_featuresReported >= m_limits.GetMaxNumFeatures()) - break; - - currScale *= kViewportScaleMul; - } -} - -void Retrieval::Release() { m_buckets.clear(); } - -bool Retrieval::RetrieveForScale(Bucket & bucket, double scale, Callback & callback) -{ - if (IsCancelled()) - return false; - - m2::RectD viewport = m_viewport; - viewport.Scale(scale); - if (scales::GetScaleLevelD(viewport) <= kMaxViewportScaleLevel) - { - viewport.MakeInfinite(); - scale = kInfinity; - } - - if (bucket.m_finished || !viewport.IsIntersect(bucket.m_bounds)) - return true; - - if (!bucket.m_intersectsWithViewport) - { - // This is the first time viewport intersects with - // mwm. Initialize bucket's retrieval strategy. - if (!InitBucketStrategy(bucket, scale)) - return false; - bucket.m_intersectsWithViewport = true; - } - - ASSERT(bucket.m_intersectsWithViewport, ()); - ASSERT_LESS_OR_EQUAL(bucket.m_featuresReported, bucket.m_numAddressFeatures, ()); - if (bucket.m_featuresReported == bucket.m_numAddressFeatures) - { - // All features were reported for the bucket, mark it as - // finished and move to the next bucket. - FinishBucket(bucket, callback); - return true; - } - - auto wrapper = [&](coding::CompressedBitVector const & features) - { - ReportFeatures(bucket, features, scale, callback); - }; - - if (!bucket.m_strategy->Retrieve(scale, *this /* cancellable */, wrapper)) - return false; - - if (viewport.IsRectInside(bucket.m_bounds)) - { - // Viewport completely covers the bucket, so mark it as finished - // and switch to the next bucket. Note that "viewport covers the - // bucket" is not the same as "all features from the bucket were - // reported", because of scale parameter. Search index reports - // all matching features, but geometry index can skip features - // from more detailed scales. - FinishBucket(bucket, callback); - } - - return true; -} - -bool Retrieval::InitBucketStrategy(Bucket & bucket, double scale) -{ - ASSERT(!bucket.m_strategy, ()); - ASSERT_EQUAL(0, bucket.m_numAddressFeatures, ()); - - unique_ptr addressFeatures; - - try - { - addressFeatures = - RetrieveAddressFeatures(bucket.m_handle.GetId(), *bucket.m_handle.GetValue(), - *this /* cancellable */, m_params); - } - catch (CancelException &) - { - return false; - } - - ASSERT(addressFeatures.get(), ("Can't retrieve address features.")); - bucket.m_numAddressFeatures = addressFeatures->PopCount(); - - if (bucket.m_numAddressFeatures < kFastPathThreshold) - { - bucket.m_strategy.reset( - new FastPathStrategy(*m_index, bucket.m_handle, m_viewport, move(addressFeatures))); - } - else - { - bucket.m_strategy.reset( - new SlowPathStrategy(bucket.m_handle, m_viewport, m_params, move(addressFeatures))); - } - - return true; -} - -void Retrieval::FinishBucket(Bucket & bucket, Callback & callback) -{ - if (bucket.m_finished) - return; - - auto const mwmId = bucket.m_handle.GetId(); - - bucket.m_finished = true; - bucket.m_handle = MwmSet::MwmHandle(); - - callback.OnMwmProcessed(mwmId); -} - -bool Retrieval::Finished() const -{ - for (auto const & bucket : m_buckets) - { - if (!bucket.m_finished) - return false; - } - return true; -} - -void Retrieval::ReportFeatures(Bucket & bucket, coding::CompressedBitVector const & features, - double scale, Callback & callback) -{ - if (m_limits.IsMaxNumFeaturesSet() && m_featuresReported >= m_limits.GetMaxNumFeatures()) - return; - - if (features.PopCount() == 0) - return; - - callback.OnFeaturesRetrieved(bucket.m_handle.GetId(), scale, features); - bucket.m_featuresReported += features.PopCount(); - m_featuresReported += features.PopCount(); -} -} // namespace search +} // namespace v2 +} // namespace search diff --git a/search/retrieval.hpp b/search/retrieval.hpp index 34219b87ed..016bf7f30a 100644 --- a/search/retrieval.hpp +++ b/search/retrieval.hpp @@ -4,16 +4,11 @@ #include "indexer/mwm_set.hpp" -#include "geometry/rect2d.hpp" - #include "base/cancellable.hpp" -#include "base/macros.hpp" -#include "std/function.hpp" #include "std/unique_ptr.hpp" -#include "std/vector.hpp" -class Index; + class MwmValue; namespace coding @@ -23,163 +18,19 @@ class CompressedBitVector; namespace search { -namespace v2 { struct MwmContext; } - -class Retrieval : public my::Cancellable +namespace v2 { -public: - class Callback - { - public: - virtual ~Callback() = default; +struct MwmContext; - // Called each time a bunch of features for an mwm is retrieved. - // This method may be called several times for the same mwm, - // reporting disjoint sets of features. - virtual void OnFeaturesRetrieved(MwmSet::MwmId const & id, double scale, - coding::CompressedBitVector const & features) = 0; - - // Called when all matching features for an mwm were retrieved and - // reported. Cliens may assume that this method is called no more - // than once for |id| and after that call there won't be any calls - // of OnFeaturesRetrieved() for |id|. - virtual void OnMwmProcessed(MwmSet::MwmId const & id) {} - }; - - // This class wraps a set of retrieval's limits like number of - // features to be retrieved, maximum viewport scale, etc. - struct Limits - { - public: - Limits(); - - // Sets upper bound (inclusive) on a number of features to be - // retrieved. - void SetMaxNumFeatures(uint64_t minNumFeatures); - uint64_t GetMaxNumFeatures() const; - inline bool IsMaxNumFeaturesSet() const { return m_maxNumFeaturesSet; } - - // Sets upper bound on a maximum viewport's scale. - void SetMaxViewportScale(double maxViewportScale); - double GetMaxViewportScale() const; - inline bool IsMaxViewportScaleSet() const { return m_maxViewportScaleSet; } - - // Sets whether retrieval should/should not skip World.mwm. - inline void SetSearchInWorld(bool searchInWorld) { m_searchInWorld = searchInWorld; } - inline bool GetSearchInWorld() const { return m_searchInWorld; } - - private: - uint64_t m_maxNumFeatures; - double m_maxViewportScale; - - bool m_maxNumFeaturesSet : 1; - bool m_maxViewportScaleSet : 1; - bool m_searchInWorld : 1; - }; - - // This class represents a retrieval's strategy. - class Strategy - { - public: - using TCallback = function; - - Strategy(MwmSet::MwmHandle & handle, m2::RectD const & viewport); - - virtual ~Strategy() = default; - - // Retrieves features for m_viewport scaled by |scale|. Returns - // false when cancelled. - // - // *NOTE* This method should be called on a strictly increasing - // *sequence of scales. - WARN_UNUSED_RESULT bool Retrieve(double scale, my::Cancellable const & cancellable, - TCallback const & callback); - - protected: - WARN_UNUSED_RESULT virtual bool RetrieveImpl(double scale, my::Cancellable const & cancellable, - TCallback const & callback) = 0; - - MwmSet::MwmHandle & m_handle; - m2::RectD const m_viewport; - double m_prevScale; - }; - - Retrieval(); - - // Retrieves from the search index corresponding to |value| all - // features matching to |params|. - WARN_UNUSED_RESULT static unique_ptr RetrieveAddressFeatures( +// Retrieves from the search index corresponding to |value| all +// features matching to |params|. +unique_ptr RetrieveAddressFeatures( MwmSet::MwmId const & id, MwmValue & value, my::Cancellable const & cancellable, SearchQueryParams const & params); - // Retrieves from the geometry index corresponding to |value| all features belonging to |rect|. - WARN_UNUSED_RESULT static unique_ptr RetrieveGeometryFeatures( - v2::MwmContext const & context, my::Cancellable const & cancellable, +// Retrieves from the geometry index corresponding to |value| all features belonging to |rect|. +unique_ptr RetrieveGeometryFeatures( + MwmContext const & context, my::Cancellable const & cancellable, m2::RectD const & rect, int scale); - - // Initializes retrieval process, sets up internal state, takes all - // necessary system resources. - void Init(Index & index, vector> const & infos, m2::RectD const & viewport, - SearchQueryParams const & params, Limits const & limits); - - // Start retrieval process. - // - // *NOTE* Retrieval may report features not belonging to viewport - // (even scaled by maximum allowed scale). The reason is the current - // geomerty index algorithm - when it asked for features in a - // rectangle, it reports all features from cells that cover (not - // covered by) a rectangle. - void Go(Callback & callback); - - // Releases all taken system resources. - void Release(); - -private: - // This class is a wrapper around single mwm during retrieval - // process. - struct Bucket - { - Bucket(MwmSet::MwmHandle && handle); - - MwmSet::MwmHandle m_handle; - m2::RectD m_bounds; - - // The order matters here - strategy may contain references to the - // fields above, thus it must be destructed before them. - unique_ptr m_strategy; - - size_t m_featuresReported; - uint32_t m_numAddressFeatures; - bool m_intersectsWithViewport : 1; - bool m_finished : 1; - }; - - // Retrieves features for the viewport scaled by |scale| and invokes - // callback on retrieved features. Returns false when cancelled. - // - // *NOTE* |scale| of successive calls of this method should be - // non-decreasing. - WARN_UNUSED_RESULT bool RetrieveForScale(Bucket & bucket, double scale, Callback & callback); - - // Inits bucket retrieval strategy. Returns false when cancelled. - WARN_UNUSED_RESULT bool InitBucketStrategy(Bucket & bucket, double scale); - - // Marks bucket as finished and invokes callback. - void FinishBucket(Bucket & bucket, Callback & callback); - - // Returns true when all buckets are marked as finished. - bool Finished() const; - - // Reports features, updates bucket's stats. - void ReportFeatures(Bucket & bucket, coding::CompressedBitVector const & features, double scale, - Callback & callback); - - Index * m_index; - m2::RectD m_viewport; - SearchQueryParams m_params; - Limits m_limits; - uint64_t m_featuresReported; - - vector m_buckets; -}; -} // namespace search +} // namespace v2 +} // namespace search diff --git a/search/search_integration_tests/retrieval_test.cpp b/search/search_integration_tests/retrieval_test.cpp deleted file mode 100644 index 45423771cd..0000000000 --- a/search/search_integration_tests/retrieval_test.cpp +++ /dev/null @@ -1,419 +0,0 @@ -#include "testing/testing.hpp" - -#include "search/retrieval.hpp" -#include "search/search_query_params.hpp" -#include "search/search_tests_support/test_feature.hpp" -#include "search/search_tests_support/test_mwm_builder.hpp" -#include "search/search_tests_support/test_results_matching.hpp" -#include "search/search_tests_support/test_search_engine.hpp" -#include "search/search_tests_support/test_search_request.hpp" - -#include "indexer/classificator_loader.hpp" -#include "indexer/index.hpp" -#include "indexer/mwm_set.hpp" -#include "indexer/scales.hpp" -#include "indexer/search_delimiters.hpp" -#include "indexer/search_string_utils.hpp" - -#include "storage/country_decl.hpp" -#include "storage/country_info_getter.hpp" - -#include "platform/local_country_file.hpp" -#include "platform/local_country_file_utils.hpp" -#include "platform/platform.hpp" - -#include "coding/compressed_bit_vector.hpp" - -#include "base/scope_guard.hpp" -#include "base/string_utils.hpp" - -#include "std/algorithm.hpp" -#include "std/initializer_list.hpp" -#include "std/limits.hpp" -#include "std/shared_ptr.hpp" - -using namespace search::tests_support; - -using TRules = vector>; - -namespace -{ -void InitParams(string const & query, search::SearchQueryParams & params) -{ - params.Clear(); - auto insertTokens = [¶ms](strings::UniString const & token) - { - params.m_tokens.push_back({token}); - }; - search::Delimiters delims; - SplitUniString(search::NormalizeAndSimplifyString(query), insertTokens, delims); - - params.m_langs.insert(StringUtf8Multilang::GetLangIndex("en")); -} - -bool AllMwmsReleased(Index & index) -{ - vector> infos; - index.GetMwmsInfo(infos); - for (auto const & info : infos) - { - if (info->GetNumRefs() != 0) - return false; - } - return true; -} - -void Cleanup(platform::LocalCountryFile const & map) -{ - platform::CountryIndexes::DeleteFromDisk(map); - map.DeleteFromDisk(MapOptions::Map); -} - -void Cleanup(initializer_list const & maps) -{ - for (auto const & map : maps) - Cleanup(map); -} - -class TestCallback : public search::Retrieval::Callback -{ -public: - TestCallback(MwmSet::MwmId const & id) : m_id(id), m_triggered(false) {} - - // search::Retrieval::Callback overrides: - void OnFeaturesRetrieved(MwmSet::MwmId const & id, double scale, - coding::CompressedBitVector const & features) override - { - TEST_EQUAL(m_id, id, ()); - m_triggered = true; - coding::CompressedBitVectorEnumerator::ForEach( - features, [&](uint64_t featureId) - { - CHECK_LESS(featureId, numeric_limits::max(), ()); - m_offsets.push_back(static_cast(featureId)); - }); - } - - void OnMwmProcessed(MwmSet::MwmId const & /* id */) override {} - - bool WasTriggered() const { return m_triggered; } - - vector & Offsets() { return m_offsets; } - vector const & Offsets() const { return m_offsets; } - -private: - MwmSet::MwmId const m_id; - vector m_offsets; - bool m_triggered; -}; - -class MultiMwmCallback : public search::Retrieval::Callback -{ -public: - MultiMwmCallback(vector const & ids) : m_ids(ids), m_numFeatures(0) {} - - // search::Retrieval::Callback overrides: - void OnFeaturesRetrieved(MwmSet::MwmId const & id, double /* scale */, - coding::CompressedBitVector const & features) override - { - auto const it = find(m_ids.cbegin(), m_ids.cend(), id); - TEST(it != m_ids.cend(), ("Unknown mwm:", id)); - - m_retrieved.insert(id); - m_numFeatures += features.PopCount(); - } - - void OnMwmProcessed(MwmSet::MwmId const & /* id */) override {} - - uint64_t GetNumMwms() const { return m_retrieved.size(); } - - uint64_t GetNumFeatures() const { return m_numFeatures; } - -private: - vector m_ids; - set m_retrieved; - uint64_t m_numFeatures; -}; -} // namespace - -UNIT_TEST(Retrieval_Smoke) -{ - classificator::Load(); - Platform & platform = GetPlatform(); - - platform::LocalCountryFile file(platform.WritableDir(), platform::CountryFile("WhiskeyTown"), 0); - Cleanup(file); - MY_SCOPE_GUARD(deleteFile, [&]() - { - Cleanup(file); - }); - - // Create a test mwm with 100 whiskey bars. - { - TestMwmBuilder builder(file, feature::DataHeader::country); - for (int x = 0; x < 10; ++x) - { - for (int y = 0; y < 10; ++y) - builder.Add(TestPOI(m2::PointD(x, y), "Whiskey bar", "en")); - } - } - TEST_EQUAL(MapOptions::MapWithCarRouting, file.GetFiles(), ()); - - Index index; - auto p = index.RegisterMap(file); - auto & id = p.first; - TEST(id.IsAlive(), ()); - TEST_EQUAL(p.second, MwmSet::RegResult::Success, ()); - - search::SearchQueryParams params; - InitParams("whiskey bar", params); - - search::Retrieval retrieval; - - vector> infos; - index.GetMwmsInfo(infos); - - // Retrieve all (100) whiskey bars from the mwm. - { - TestCallback callback(id); - - retrieval.Init(index, infos, m2::RectD(m2::PointD(0, 0), m2::PointD(1, 1)), params, - search::Retrieval::Limits()); - retrieval.Go(callback); - TEST(callback.WasTriggered(), ()); - TEST_EQUAL(100, callback.Offsets().size(), ()); - - TestCallback dummyCallback(id); - retrieval.Go(dummyCallback); - TEST(!dummyCallback.WasTriggered(), ()); - } - - // Retrieve all whiskey bars from the left-bottom 5 x 5 square. - // Note that due to current coverage algorithm the number of - // retrieved results can be greater than 36. - { - TestCallback callback(id); - search::Retrieval::Limits limits; - limits.SetMaxViewportScale(9.0); - - retrieval.Init(index, infos, m2::RectD(m2::PointD(0, 0), m2::PointD(1, 1)), params, limits); - retrieval.Go(callback); - TEST(callback.WasTriggered(), ()); - TEST_GREATER_OR_EQUAL(callback.Offsets().size(), - 36 /* number of whiskey bars in a 5 x 5 square (border is counted) */, - ()); - } - - // Retrieve exactly 8 whiskey bars from the center. Note that due - // to current coverage algorithm the number of retrieved results can - // be greater than 8. - { - TestCallback callback(id); - search::Retrieval::Limits limits; - limits.SetMaxNumFeatures(8); - - retrieval.Init(index, infos, m2::RectD(m2::PointD(4.9, 4.9), m2::PointD(5.1, 5.1)), params, - limits); - retrieval.Go(callback); - TEST(callback.WasTriggered(), ()); - TEST_GREATER_OR_EQUAL(callback.Offsets().size(), 8, ()); - } -} - -UNIT_TEST(Retrieval_3Mwms) -{ - classificator::Load(); - Platform & platform = GetPlatform(); - - platform::LocalCountryFile msk(platform.WritableDir(), platform::CountryFile("msk"), 0); - platform::LocalCountryFile mtv(platform.WritableDir(), platform::CountryFile("mtv"), 0); - platform::LocalCountryFile zrh(platform.WritableDir(), platform::CountryFile("zrh"), 0); - Cleanup({msk, mtv, zrh}); - MY_SCOPE_GUARD(cleanup, [&]() - { - Cleanup({msk, mtv, zrh}); - }); - - { - TestMwmBuilder builder(msk, feature::DataHeader::country); - builder.Add(TestPOI(m2::PointD(0, 0), "Cafe MTV", "en")); - } - { - TestMwmBuilder builder(mtv, feature::DataHeader::country); - builder.Add(TestPOI(m2::PointD(10, 0), "MTV", "en")); - } - { - TestMwmBuilder builder(zrh, feature::DataHeader::country); - builder.Add(TestPOI(m2::PointD(0, 10), "Bar MTV", "en")); - } - - Index index; - auto mskP = index.RegisterMap(msk); - auto & mskId = mskP.first; - - auto mtvP = index.RegisterMap(mtv); - auto & mtvId = mtvP.first; - - auto zrhP = index.RegisterMap(zrh); - auto & zrhId = zrhP.first; - - TEST(mskId.IsAlive(), ()); - TEST(mtvId.IsAlive(), ()); - TEST(zrhId.IsAlive(), ()); - - search::SearchQueryParams params; - InitParams("mtv", params); - - vector> infos; - index.GetMwmsInfo(infos); - - search::Retrieval retrieval; - - { - TestCallback callback(mskId); - search::Retrieval::Limits limits; - limits.SetMaxNumFeatures(1); - - retrieval.Init(index, infos, m2::RectD(m2::PointD(-1.0, -1.0), m2::PointD(1.0, 1.0)), params, - limits); - retrieval.Go(callback); - retrieval.Release(); - - TEST(callback.WasTriggered(), ()); - TEST_EQUAL(callback.Offsets().size(), 1, ()); - TEST(AllMwmsReleased(index), ()); - } - - { - MultiMwmCallback callback({mskId, mtvId, zrhId}); - search::Retrieval::Limits limits; - limits.SetMaxNumFeatures(10 /* more than total number of features in all these mwms */); - - retrieval.Init(index, infos, m2::RectD(m2::PointD(-1.0, -1.0), m2::PointD(1.0, 1.0)), params, - limits); - retrieval.Go(callback); - retrieval.Release(); - - TEST_EQUAL(3 /* total number of mwms */, callback.GetNumMwms(), ()); - TEST_EQUAL(3 /* total number of features in all these mwms */, callback.GetNumFeatures(), ()); - TEST(AllMwmsReleased(index), ()); - } - - { - MultiMwmCallback callback({mskId, mtvId, zrhId}); - search::Retrieval::Limits limits; - - retrieval.Init(index, infos, m2::RectD(m2::PointD(-1.0, -1.0), m2::PointD(1.0, 1.0)), params, - limits); - retrieval.Go(callback); - retrieval.Release(); - - TEST_EQUAL(3, callback.GetNumMwms(), ()); - TEST_EQUAL(3, callback.GetNumFeatures(), ()); - TEST(AllMwmsReleased(index), ()); - } -} - -// This test creates a couple of maps: -// * model map of Moscow, with "Cafe MTV" at the center -// * model map of MTV, with "Cafe Moscow" at the center -// * TestWorld map, with Moscow and MTV -// TestWorld map is needed because locality search works only on world maps. -// -// Then, it tests search engine on following requests: -// -// 1. "Moscow", viewport covers only Moscow - should return two -// results (Moscow city and Cafe Moscow at MTV). -// 2. "MTV", viewport covers only MTV"- should return two results (MTV -// city and Cafe MTV at Moscow). -// 3. "Moscow MTV", viewport covers only MTV - should return MTV cafe -// at Moscow. -// 4. "MTV Moscow", viewport covers only Moscow - should return Moscow -// cafe at MTV. -UNIT_TEST(Retrieval_CafeMTV) -{ - classificator::Load(); - Platform & platform = GetPlatform(); - - platform::LocalCountryFile msk(platform.WritableDir(), platform::CountryFile("msk"), 0); - platform::LocalCountryFile mtv(platform.WritableDir(), platform::CountryFile("mtv"), 0); - platform::LocalCountryFile testWorld(platform.WritableDir(), platform::CountryFile("testWorld"), - 0); - Cleanup({msk, mtv, testWorld}); - MY_SCOPE_GUARD(cleanup, [&]() - { - Cleanup({msk, mtv, testWorld}); - }); - - TestCity mskCity(m2::PointD(1, 0), "Moscow", "en", 100 /* rank */); - TestPOI mtvCafe(m2::PointD(1, 0), "Cafe MTV", "en"); - - TestCity mtvCity(m2::PointD(-1, 0), "MTV", "en", 100 /* rank */); - TestPOI mskCafe(m2::PointD(-1, 0), "Cafe Moscow", "en"); - - { - TestMwmBuilder builder(msk, feature::DataHeader::country); - builder.Add(mskCity); - builder.Add(mtvCafe); - } - { - TestMwmBuilder builder(mtv, feature::DataHeader::country); - builder.Add(mtvCity); - builder.Add(mskCafe); - } - { - TestMwmBuilder builder(testWorld, feature::DataHeader::world); - builder.Add(mskCity); - builder.Add(mtvCity); - } - - m2::RectD const mskViewport(m2::PointD(0.99, -0.1), m2::PointD(1.01, 0.1)); - m2::RectD const mtvViewport(m2::PointD(-1.1, -0.1), m2::PointD(-0.99, 0.1)); - - // There are test requests involving locality search, thus it's - // better to mock information about countries. - vector countries; - countries.emplace_back(msk.GetCountryName(), mskViewport); - countries.emplace_back(mtv.GetCountryName(), mtvViewport); - - TestSearchEngine engine(make_unique(countries), - search::Engine::Params()); - TEST_EQUAL(MwmSet::RegResult::Success, engine.RegisterMap(msk).second, ()); - TEST_EQUAL(MwmSet::RegResult::Success, engine.RegisterMap(mtv).second, ()); - TEST_EQUAL(MwmSet::RegResult::Success, engine.RegisterMap(testWorld).second, ()); - - auto const mskId = engine.GetMwmIdByCountryFile(msk.GetCountryFile()); - auto const mtvId = engine.GetMwmIdByCountryFile(mtv.GetCountryFile()); - auto const testWorldId = engine.GetMwmIdByCountryFile(testWorld.GetCountryFile()); - - { - TestSearchRequest request(engine, "Moscow ", "en", search::Mode::Everywhere, mskViewport); - request.Wait(); - - auto mskCityAlts = {ExactMatch(testWorldId, mskCity), ExactMatch(mskId, mskCity)}; - TRules rules = {AlternativesMatch(mskCityAlts), ExactMatch(mtvId, mskCafe)}; - TEST(MatchResults(engine, rules, request.Results()), ()); - } - - { - TestSearchRequest request(engine, "MTV ", "en", search::Mode::Everywhere, mtvViewport); - request.Wait(); - - auto mtvCityAlts = {ExactMatch(testWorldId, mtvCity), ExactMatch(mtvId, mtvCity)}; - TRules rules = {AlternativesMatch(mtvCityAlts), ExactMatch(mskId, mtvCafe)}; - TEST(MatchResults(engine, rules, request.Results()), ()); - } - - { - TestSearchRequest request(engine, "Moscow MTV ", "en", search::Mode::Everywhere, mtvViewport); - request.Wait(); - - auto alternatives = {ExactMatch(mskId, mtvCafe), ExactMatch(mtvId, mskCafe)}; - TRules rules = {AlternativesMatch(alternatives)}; - - // TODO (@gorshenin): current search algorithm can't retrieve both - // Cafe Moscow @ MTV and Cafe MTV @ Moscow, it'll just return one - // of them. Fix this test when locality search will be fixed. - TEST(MatchResults(engine, rules, request.Results()), ()); - } -} diff --git a/search/search_integration_tests/search_integration_tests.pro b/search/search_integration_tests/search_integration_tests.pro index 65053322a3..5b0aece50d 100644 --- a/search/search_integration_tests/search_integration_tests.pro +++ b/search/search_integration_tests/search_integration_tests.pro @@ -21,6 +21,5 @@ macx-*: LIBS *= "-framework IOKit" SOURCES += \ ../../testing/testingmain.cpp \ - retrieval_test.cpp \ search_query_v2_test.cpp \ smoke_test.cpp \ diff --git a/search/search_query.cpp b/search/search_query.cpp index 30410031e5..1f274d89d0 100644 --- a/search/search_query.cpp +++ b/search/search_query.cpp @@ -162,30 +162,6 @@ void RemoveDuplicatingLinear(vector & indV) } } // namespace -Query::RetrievalCallback::RetrievalCallback(Index & index, Query & query, ViewportID viewportId) - : m_index(index), m_query(query), m_viewportId(viewportId) -{ -} - -void Query::RetrievalCallback::OnFeaturesRetrieved(MwmSet::MwmId const & id, double scale, - coding::CompressedBitVector const & features) -{ - auto const & table = m_rankTableCache.Get(m_index, id); - - coding::CompressedBitVectorEnumerator::ForEach( - features, [&](uint64_t featureId) - { - ASSERT_LESS_OR_EQUAL(featureId, numeric_limits::max(), ()); - m_query.AddPreResult1(id, static_cast(featureId), table.Get(featureId), scale, - m_viewportId); - }); -} - -void Query::RetrievalCallback::OnMwmProcessed(MwmSet::MwmId const & id) -{ - m_rankTableCache.Remove(id); -} - // static size_t const Query::kPreResultsCount; @@ -230,18 +206,6 @@ Query::Query(Index & index, CategoriesHolder const & categories, vector SetPreferredLocale("en"); } -void Query::Reset() -{ - Cancellable::Reset(); - m_retrieval.Reset(); -} - -void Query::Cancel() -{ - Cancellable::Cancel(); - m_retrieval.Cancel(); -} - void Query::SetLanguage(int id, int8_t lang) { m_keywordsScorer.SetLanguage(GetLangIndex(id), lang); @@ -1707,25 +1671,8 @@ void Query::SearchFeaturesInViewport(SearchQueryParams const & params, TMWMVecto void Query::SearchInMwms(TMWMVector const & mwmsInfo, SearchQueryParams const & params, ViewportID viewportId) { - Retrieval::Limits limits; - limits.SetMaxNumFeatures(kPreResultsCount); - limits.SetSearchInWorld(m_worldSearch); - - m2::RectD const * viewport = nullptr; - if (viewportId == LOCALITY_V) - { - limits.SetMaxViewportScale(1.0); - viewport = &m_viewport[LOCALITY_V]; - } - else - { - viewport = &m_viewport[CURRENT_V]; - } - - m_retrieval.Init(m_index, mwmsInfo, *viewport, params, limits); - RetrievalCallback callback(m_index, *this, viewportId); - m_retrieval.Go(callback); - m_retrieval.Release(); + /// @note Old Retrieval logic is obsolete and moved to trash. + /// @todo Move to trash this Query code :) } void Query::SuggestStrings(Results & res) diff --git a/search/search_query.hpp b/search/search_query.hpp index c9ab994940..948cfd0fd2 100644 --- a/search/search_query.hpp +++ b/search/search_query.hpp @@ -2,7 +2,6 @@ #include "search/intermediate_result.hpp" #include "search/keyword_lang_matcher.hpp" #include "search/mode.hpp" -#include "search/retrieval.hpp" #include "search/search_trie.hpp" #include "search/suggest.hpp" #include "search/v2/rank_table_cache.hpp" @@ -74,10 +73,6 @@ public: Query(Index & index, CategoriesHolder const & categories, vector const & suggests, storage::CountryInfoGetter const & infoGetter); - // my::Cancellable overrides: - void Reset() override; - void Cancel() override; - inline void SupportOldFormat(bool b) { m_supportOldFormat = b; } void Init(bool viewportSearch); @@ -135,25 +130,6 @@ protected: friend string DebugPrint(ViewportID viewportId); - class RetrievalCallback : public Retrieval::Callback - { - public: - RetrievalCallback(Index & index, Query & query, ViewportID id); - - // Retrieval::Callback overrides: - void OnFeaturesRetrieved(MwmSet::MwmId const & id, double scale, - coding::CompressedBitVector const & features) override; - - void OnMwmProcessed(MwmSet::MwmId const & id) override; - - private: - - Index & m_index; - Query & m_query; - ViewportID m_viewportId; - search::v2::RankTableCache m_rankTableCache; - }; - friend class impl::FeatureLoader; friend class impl::BestNameFinder; friend class impl::PreResult2Maker; @@ -245,7 +221,6 @@ protected: Mode m_mode; bool m_worldSearch; bool m_suggestsEnabled; - Retrieval m_retrieval; /// @name Get ranking params. //@{ diff --git a/search/v2/geocoder.cpp b/search/v2/geocoder.cpp index f744859b6c..4d18f1dfe1 100644 --- a/search/v2/geocoder.cpp +++ b/search/v2/geocoder.cpp @@ -570,8 +570,8 @@ void Geocoder::GoImpl(vector> & infos, bool inViewport) unique_ptr viewportCBV; if (inViewport) { - viewportCBV = Retrieval::RetrieveGeometryFeatures(*m_context, cancellable, - m_params.m_viewport, m_params.m_scale); + viewportCBV = v2::RetrieveGeometryFeatures(*m_context, cancellable, + m_params.m_viewport, m_params.m_scale); } PrepareAddressFeatures(); @@ -645,7 +645,7 @@ void Geocoder::PrepareAddressFeatures() for (size_t i = 0; i < m_numTokens; ++i) { PrepareRetrievalParams(i, i + 1); - m_addressFeatures[i] = Retrieval::RetrieveAddressFeatures( + m_addressFeatures[i] = RetrieveAddressFeatures( m_context->GetId(), m_context->m_value, static_cast(*this), m_retrievalParams); ASSERT(m_addressFeatures[i], ()); @@ -1303,7 +1303,7 @@ unique_ptr Geocoder::LoadCategories( for_each(categories.begin(), categories.end(), [&](strings::UniString const & category) { m_retrievalParams.m_tokens[0][0] = category; - auto cbv = Retrieval::RetrieveAddressFeatures( + auto cbv = RetrieveAddressFeatures( context.GetId(), context.m_value, static_cast(*this), m_retrievalParams); if (!coding::CompressedBitVector::IsEmpty(cbv)) @@ -1357,7 +1357,7 @@ coding::CompressedBitVector const * Geocoder::RetrieveGeometryFeatures(MwmContex return v.m_cbv.get(); } - auto cbv = Retrieval::RetrieveGeometryFeatures(context, *this, rect, m_params.m_scale); + auto cbv = v2::RetrieveGeometryFeatures(context, *this, rect, m_params.m_scale); auto const * result = cbv.get(); features.push_back({m2::Inflate(rect, kComparePoints, kComparePoints), move(cbv), id});