diff options
author | Yuri Gorshenin <y@maps.me> | 2015-07-24 15:54:19 +0300 |
---|---|---|
committer | Alex Zolotarev <alex@maps.me> | 2015-09-23 02:58:04 +0300 |
commit | be7aecb7efa171aa67ac20397794a217f9421dc3 (patch) | |
tree | 2e821b4bd637a9af302912697377d00253fb9ffa /search | |
parent | d7af959ce6c52d949bbdd2161a507b02f5b6684a (diff) |
[search] Implemented retrieval.
Diffstat (limited to 'search')
-rw-r--r-- | search/feature_offset_match.hpp | 8 | ||||
-rw-r--r-- | search/integration_tests/integration_tests.pro | 1 | ||||
-rw-r--r-- | search/integration_tests/retrieval_test.cpp | 230 | ||||
-rw-r--r-- | search/integration_tests/test_search_request.hpp | 7 | ||||
-rw-r--r-- | search/retrieval.cpp | 230 | ||||
-rw-r--r-- | search/retrieval.hpp | 89 | ||||
-rw-r--r-- | search/search.pro | 2 | ||||
-rw-r--r-- | search/search_query.cpp | 4 | ||||
-rw-r--r-- | search/search_query_params.cpp | 4 | ||||
-rw-r--r-- | search/search_query_params.hpp | 3 |
10 files changed, 569 insertions, 9 deletions
diff --git a/search/feature_offset_match.hpp b/search/feature_offset_match.hpp index 3474d69a23..370c1356ac 100644 --- a/search/feature_offset_match.hpp +++ b/search/feature_offset_match.hpp @@ -1,5 +1,6 @@ #pragma once #include "search/search_common.hpp" +#include "search/search_query.hpp" #include "search/search_query_params.hpp" #include "indexer/search_trie.hpp" @@ -44,6 +45,7 @@ TrieIterator * MoveTrieIteratorToString(TrieIterator const & trieRoot, unique_ptr<search::TrieIterator> pIter(trieRoot.Clone()); size_t const szQuery = queryS.size(); + while (symbolsMatched < szQuery) { bool bMatched = false; @@ -406,8 +408,8 @@ void MatchFeaturesInTrie(SearchQueryParams const & params, TrieIterator const & impl::OffsetIntersecter<TFilter> intersecter(filter); for (size_t i = 0; i < params.m_tokens.size(); ++i) { - ForEachLangPrefix(params, trieRoot, [&](TrieRootPrefix & langRoot, int8_t /* lang */) - { + ForEachLangPrefix(params, trieRoot, [&](TrieRootPrefix & langRoot, int8_t lang) + { MatchTokenInTrie(params.m_tokens[i], langRoot, intersecter); }); categoriesHolder.GetValues(i, intersecter); @@ -417,7 +419,7 @@ void MatchFeaturesInTrie(SearchQueryParams const & params, TrieIterator const & if (!params.m_prefixTokens.empty()) { ForEachLangPrefix(params, trieRoot, [&](TrieRootPrefix & langRoot, int8_t /* lang */) - { + { MatchTokenPrefixInTrie(params.m_prefixTokens, langRoot, intersecter); }); categoriesHolder.GetValues(params.m_tokens.size(), intersecter); diff --git a/search/integration_tests/integration_tests.pro b/search/integration_tests/integration_tests.pro index e3daa7c8b4..c41d9c4a2b 100644 --- a/search/integration_tests/integration_tests.pro +++ b/search/integration_tests/integration_tests.pro @@ -21,6 +21,7 @@ macx-*: LIBS *= "-framework Foundation" "-framework IOKit" SOURCES += \ ../../testing/testingmain.cpp \ + retrieval_test.cpp \ smoke_test.cpp \ test_mwm_builder.cpp \ test_search_engine.cpp \ diff --git a/search/integration_tests/retrieval_test.cpp b/search/integration_tests/retrieval_test.cpp new file mode 100644 index 0000000000..3cfad01ce5 --- /dev/null +++ b/search/integration_tests/retrieval_test.cpp @@ -0,0 +1,230 @@ +#include "testing/testing.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 "search/integration_tests/test_mwm_builder.hpp" +#include "search/retrieval.hpp" +#include "search/search_query_params.hpp" + +#include "platform/local_country_file.hpp" +#include "platform/platform.hpp" + +#include "base/scope_guard.hpp" +#include "base/string_utils.hpp" + +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")); +} + +class TestCallback : public search::Retrieval::Callback +{ +public: + TestCallback(MwmSet::MwmId const & id) : m_id(id), m_triggered(false) {} + + // search::Retrieval::Callback overrides: + void OnMwmProcessed(MwmSet::MwmId const & id, vector<uint32_t> const & offsets) override + { + TEST(!m_triggered, ("Callback must be triggered only once.")); + TEST_EQUAL(m_id, id, ()); + m_triggered = true; + m_offsets = offsets; + } + + bool WasTriggered() const { return m_triggered; } + + vector<uint32_t> & Offsets() { return m_offsets; } + vector<uint32_t> const & Offsets() const { return m_offsets; } + +private: + MwmSet::MwmId const m_id; + vector<uint32_t> m_offsets; + bool m_triggered; +}; + +class MultiMwmCallback : public search::Retrieval::Callback +{ +public: + MultiMwmCallback(vector<MwmSet::MwmId> const & ids) : m_ids(ids), m_numFeatures(0) {} + + // search::Retrieval::Callback overrides: + void OnMwmProcessed(MwmSet::MwmId const & id, vector<uint32_t> const & offsets) override + { + auto const it = find(m_ids.cbegin(), m_ids.cend(), id); + TEST(it != m_ids.cend(), ("Unknown mwm:", id)); + + auto const rt = m_retrieved.find(id); + TEST(rt == m_retrieved.cend(), ("For", id, "callback must be triggered only once.")); + + m_retrieved.insert(id); + m_numFeatures += offsets.size(); + } + + uint64_t GetNumMwms() const { return m_retrieved.size(); } + + uint64_t GetNumFeatures() const { return m_numFeatures; } + +private: + vector<MwmSet::MwmId> m_ids; + set<MwmSet::MwmId> 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); + MY_SCOPE_GUARD(deleteFile, [&]() + { + file.DeleteFromDisk(MapOptions::Map); + }); + + // Create a test mwm with 100 whiskey bars. + { + TestMwmBuilder builder(file); + for (int x = 0; x < 10; ++x) + { + for (int y = 0; y < 10; ++y) + builder.AddPOI(m2::PointD(x, y), "Whiskey bar", "en"); + } + } + TEST_EQUAL(MapOptions::Map, file.GetFiles(), ()); + + Index index; + auto p = index.RegisterMap(file); + auto & handle = p.first; + TEST(handle.IsAlive(), ()); + TEST_EQUAL(p.second, MwmSet::RegResult::Success, ()); + + search::SearchQueryParams params; + InitParams("whiskey bar", params); + + search::Retrieval retrieval; + + // Retrieve all (100) whiskey bars from the mwm. + { + TestCallback callback(handle.GetId()); + + retrieval.Init(index, 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(handle.GetId()); + retrieval.Go(dummyCallback); + TEST(!dummyCallback.WasTriggered(), ()); + } + + // Retrieve all whiskey bars from the left-bottom 5 x 5 square. + { + TestCallback callback(handle.GetId()); + search::Retrieval::Limits limits; + limits.SetMaxViewportScale(5.0); + + retrieval.Init(index, m2::RectD(m2::PointD(0, 0), m2::PointD(1, 1)), params, limits); + retrieval.Go(callback); + TEST(callback.WasTriggered(), ()); + TEST_EQUAL(36 /* number of whiskey bars in a 5 x 5 square (border is counted) */, + callback.Offsets().size(), ()); + } + + // Retrieve at least than 8 whiskey bars from the center. + { + TestCallback callback(handle.GetId()); + search::Retrieval::Limits limits; + limits.SetMinNumFeatures(8); + + retrieval.Init(index, 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); + MY_SCOPE_GUARD(deleteFiles, [&]() + { + msk.DeleteFromDisk(MapOptions::Map); + mtv.DeleteFromDisk(MapOptions::Map); + zrh.DeleteFromDisk(MapOptions::Map); + }); + + { + TestMwmBuilder builder(msk); + builder.AddPOI(m2::PointD(0, 0), "Cafe MTV", "en"); + } + { + TestMwmBuilder builder(mtv); + builder.AddPOI(m2::PointD(10, 0), "MTV", "en"); + } + { + TestMwmBuilder builder(zrh); + builder.AddPOI(m2::PointD(0, 10), "Bar MTV", "en"); + } + + Index index; + auto mskP = index.RegisterMap(msk); + auto & mskHandle = mskP.first; + + auto mtvP = index.RegisterMap(mtv); + auto & mtvHandle = mtvP.first; + + auto zrhP = index.RegisterMap(zrh); + auto & zrhHandle = zrhP.first; + + TEST(mskHandle.IsAlive(), ()); + TEST(mtvHandle.IsAlive(), ()); + TEST(zrhHandle.IsAlive(), ()); + + search::SearchQueryParams params; + InitParams("mtv", params); + + search::Retrieval retrieval; + + { + TestCallback callback(mskHandle.GetId()); + search::Retrieval::Limits limits; + limits.SetMinNumFeatures(1); + + retrieval.Init(index, m2::RectD(m2::PointD(-1.0, -1.0), m2::PointD(1.0, 1.0)), params, limits); + retrieval.Go(callback); + TEST(callback.WasTriggered(), ()); + TEST_EQUAL(callback.Offsets().size(), 1, ()); + } + + { + MultiMwmCallback callback({mskHandle.GetId(), mtvHandle.GetId(), zrhHandle.GetId()}); + search::Retrieval::Limits limits; + + retrieval.Init(index, m2::RectD(m2::PointD(-1.0, -1.0), m2::PointD(1.0, 1.0)), params, limits); + retrieval.Go(callback); + TEST_EQUAL(3, callback.GetNumMwms(), ()); + TEST_EQUAL(3, callback.GetNumFeatures(), ()); + } +} diff --git a/search/integration_tests/test_search_request.hpp b/search/integration_tests/test_search_request.hpp index fc36b578de..f11bc39a8c 100644 --- a/search/integration_tests/test_search_request.hpp +++ b/search/integration_tests/test_search_request.hpp @@ -11,10 +11,9 @@ class TestSearchEngine; -// This class wraps a search query to a search engine. Note that a -// full token match will be performed, e.g. the last token will be -// handled as a complete token (like other tokens), not a token's -// prefix. +// This class wraps a search query to a search engine. Note that the +// last token will be handled as a complete token iff it will be +// followed by a space in a query. class TestSearchRequest { public: diff --git a/search/retrieval.cpp b/search/retrieval.cpp new file mode 100644 index 0000000000..db47039fc1 --- /dev/null +++ b/search/retrieval.cpp @@ -0,0 +1,230 @@ +#include "search/retrieval.hpp" + +#include "search/feature_offset_match.hpp" + +#include "indexer/index.hpp" +#include "indexer/search_trie.hpp" + +#include "coding/reader_wrapper.hpp" + +#include "base/stl_add.hpp" + +#include "std/cmath.hpp" + +namespace search +{ +namespace +{ +struct EmptyFilter +{ + inline bool operator()(uint32_t /* featureId */) const { return true; } +}; + +void RetrieveAddressFeatures(MwmSet::MwmHandle const & handle, SearchQueryParams const & params, + vector<uint32_t> & offsets) +{ + auto * value = handle.GetValue<MwmValue>(); + ASSERT(value, ()); + serial::CodingParams codingParams(GetCPForTrie(value->GetHeader().GetDefCodingParams())); + ModelReaderPtr searchReader = value->m_cont.GetReader(SEARCH_INDEX_FILE_TAG); + unique_ptr<TrieIterator> const trieRoot( + ::trie::reader::ReadTrie(SubReaderWrapper<Reader>(searchReader.GetPtr()), + trie::ValueReader(codingParams), trie::EdgeValueReader())); + + offsets.clear(); + auto collector = [&](trie::ValueReader::ValueType const & value) + { + offsets.push_back(value.m_featureId); + }; + MatchFeaturesInTrie(params, *trieRoot, EmptyFilter(), collector); +} + +void RetrieveGeometryFeatures(MwmSet::MwmHandle const & handle, m2::RectD const & viewport, + SearchQueryParams const & params, vector<uint32_t> & offsets) +{ + auto * value = handle.GetValue<MwmValue>(); + ASSERT(value, ()); + feature::DataHeader const & header = value->GetHeader(); + ASSERT(viewport.IsIntersect(header.GetBounds()), ()); + + auto const scaleRange = header.GetScaleRange(); + int const scale = min(max(params.m_scale, scaleRange.first), scaleRange.second); + + covering::CoveringGetter covering(viewport, covering::ViewportWithLowLevels); + covering::IntervalsT const & intervals = covering.Get(scale); + ScaleIndex<ModelReaderPtr> index(value->m_cont.GetReader(INDEX_FILE_TAG), value->m_factory); + + offsets.clear(); + auto collector = MakeBackInsertFunctor(offsets); + for (auto const & interval : intervals) + { + index.ForEachInIntervalAndScale(collector, interval.first, interval.second, scale); + } +} +} // namespace + +Retrieval::Limits::Limits() + : m_minNumFeatures(0), + m_maxViewportScale(0.0), + m_minNumFeaturesSet(false), + m_maxViewportScaleSet(false) +{ +} + +void Retrieval::Limits::SetMinNumFeatures(uint64_t minNumFeatures) +{ + m_minNumFeatures = minNumFeatures; + m_minNumFeaturesSet = true; +} + +uint64_t Retrieval::Limits::GetMinNumFeatures() const +{ + ASSERT(IsMinNumFeaturesSet(), ()); + return m_minNumFeatures; +} + +void Retrieval::Limits::SetMaxViewportScale(double maxViewportScale) +{ + m_maxViewportScale = maxViewportScale; + m_maxViewportScaleSet = true; +} + +double Retrieval::Limits::GetMaxViewportScale() const +{ + ASSERT(IsMaxViewportScaleSet(), ()); + return m_maxViewportScale; +} + +Retrieval::FeatureBucket::FeatureBucket(MwmSet::MwmHandle && handle) + : m_handle(move(handle)), + m_intersectsWithViewport(false), + m_coveredByViewport(false), + m_finished(false) +{ + auto * value = m_handle.GetValue<MwmValue>(); + ASSERT(value, ()); + feature::DataHeader const & header = value->GetHeader(); + m_bounds = header.GetBounds(); +} + +Retrieval::Retrieval() : m_index(nullptr) {} + +void Retrieval::Init(Index & index, m2::RectD const & viewport, SearchQueryParams const & params, + Limits const & limits) +{ + m_index = &index; + m_viewport = viewport; + m_params = params; + m_limits = limits; + + vector<shared_ptr<MwmInfo>> infos; + index.GetMwmsInfo(infos); + + m_buckets.clear(); + for (auto const & info : infos) + { + MwmSet::MwmHandle handle = + index.GetMwmHandleByCountryFile(info->GetLocalFile().GetCountryFile()); + if (!handle.IsAlive()) + continue; + auto * value = handle.GetValue<MwmValue>(); + if (value && value->m_cont.IsExist(SEARCH_INDEX_FILE_TAG) && + value->m_cont.IsExist(INDEX_FILE_TAG)) + { + m_buckets.emplace_back(move(handle)); + } + } +} + +void Retrieval::Go(Callback & callback) +{ + static double const kViewportScaleMul = sqrt(2.0); + + for (double viewportScale = 1.0;; viewportScale *= kViewportScaleMul) + { + double scale = viewportScale; + if (m_limits.IsMaxViewportScaleSet() && scale >= m_limits.GetMaxViewportScale()) + scale = m_limits.GetMaxViewportScale(); + + m2::RectD viewport = m_viewport; + viewport.Scale(scale); + RetrieveForViewport(viewport, callback); + + if (ViewportCoversAllMwms()) + break; + if (m_limits.IsMaxViewportScaleSet() && scale >= m_limits.GetMaxViewportScale()) + break; + if (m_limits.IsMinNumFeaturesSet() && CountRetrievedFeatures() >= m_limits.GetMinNumFeatures()) + break; + } + + for (auto & bucket : m_buckets) + { + if (bucket.m_finished) + continue; + // The bucket is not covered by viewport, thus all matching + // features were not reported. + bucket.m_finished = true; + if (!bucket.m_intersection.empty()) + callback.OnMwmProcessed(bucket.m_handle.GetId(), bucket.m_intersection); + } +} + +void Retrieval::RetrieveForViewport(m2::RectD const & viewport, Callback & callback) +{ + for (auto & bucket : m_buckets) + { + if (bucket.m_coveredByViewport || bucket.m_finished || !viewport.IsIntersect(bucket.m_bounds)) + continue; + + if (!bucket.m_intersectsWithViewport) + { + // This is the first time viewport intersects with mwm. Retrieve + // all matching features from search index. + RetrieveAddressFeatures(bucket.m_handle, m_params, bucket.m_addressFeatures); + sort(bucket.m_addressFeatures.begin(), bucket.m_addressFeatures.end()); + bucket.m_intersectsWithViewport = true; + } + + // Mwm is still not covered by expanding viewport. + if (!bucket.m_coveredByViewport) + { + RetrieveGeometryFeatures(bucket.m_handle, viewport, m_params, bucket.m_geometryFeatures); + sort(bucket.m_geometryFeatures.begin(), bucket.m_geometryFeatures.end()); + + bucket.m_intersection.clear(); + set_intersection(bucket.m_addressFeatures.begin(), bucket.m_addressFeatures.end(), + bucket.m_geometryFeatures.begin(), bucket.m_geometryFeatures.end(), + back_inserter(bucket.m_intersection)); + } + + if (!bucket.m_coveredByViewport && viewport.IsRectInside(bucket.m_bounds)) + { + // Next time we will skip the bucket, so it's better to report all it's features now. + bucket.m_coveredByViewport = true; + bucket.m_finished = true; + if (!bucket.m_intersection.empty()) + callback.OnMwmProcessed(bucket.m_handle.GetId(), bucket.m_intersection); + } + } +} + +bool Retrieval::ViewportCoversAllMwms() const +{ + for (auto const & bucket : m_buckets) + { + if (!bucket.m_coveredByViewport) + return false; + } + return true; +} + +uint64_t Retrieval::CountRetrievedFeatures() const +{ + static_assert(sizeof(size_t) <= sizeof(uint64_t), "uint64_t must be not less than size_t"); + uint64_t count = 0; + for (auto const & bucket : m_buckets) + count += bucket.m_intersection.size(); + return count; +} +} // namespace search diff --git a/search/retrieval.hpp b/search/retrieval.hpp new file mode 100644 index 0000000000..97f94d39a9 --- /dev/null +++ b/search/retrieval.hpp @@ -0,0 +1,89 @@ +#pragma once + +#include "search/search_query_params.hpp" + +#include "indexer/mwm_set.hpp" + +#include "geometry/rect2d.hpp" + +#include "std/function.hpp" +#include "std/vector.hpp" + +class Index; + +namespace search +{ +class Retrieval +{ +public: + class Callback + { + public: + virtual ~Callback() = default; + + virtual void OnMwmProcessed(MwmSet::MwmId const & id, vector<uint32_t> const & offsets) = 0; + }; + + // Following class represents a set of retrieval's limits. + struct Limits + { + public: + Limits(); + + // Sets lower bound on number of features to be retrieved. + void SetMinNumFeatures(uint64_t minNumFeatures); + uint64_t GetMinNumFeatures() const; + + // Sets upper bound on a maximum viewport's scale. + void SetMaxViewportScale(double maxViewportScale); + double GetMaxViewportScale() const; + + inline bool IsMinNumFeaturesSet() const { return m_minNumFeaturesSet; } + inline bool IsMaxViewportScaleSet() const { return m_maxViewportScaleSet; } + + private: + uint64_t m_minNumFeatures; + double m_maxViewportScale; + + bool m_minNumFeaturesSet : 1; + bool m_maxViewportScaleSet : 1; + }; + + Retrieval(); + + void Init(Index & index, m2::RectD const & viewport, SearchQueryParams const & params, + Limits const & limits); + + void Go(Callback & callback); + +private: + struct FeatureBucket + { + FeatureBucket(MwmSet::MwmHandle && handle); + + MwmSet::MwmHandle m_handle; + vector<uint32_t> m_addressFeatures; + vector<uint32_t> m_geometryFeatures; + vector<uint32_t> m_intersection; + m2::RectD m_bounds; + bool m_intersectsWithViewport : 1; + bool m_coveredByViewport : 1; + bool m_finished : 1; + }; + + // *NOTE* arguments of successive calls of this method should be + // *non-decreasing. + void RetrieveForViewport(m2::RectD const & viewport, Callback & callback); + + bool ViewportCoversAllMwms() const; + + uint64_t CountRetrievedFeatures() const; + + Index * m_index; + m2::RectD m_viewport; + SearchQueryParams m_params; + Limits m_limits; + + vector<FeatureBucket> m_buckets; +}; +} // namespace search diff --git a/search/search.pro b/search/search.pro index 697013c988..a0f318a3cc 100644 --- a/search/search.pro +++ b/search/search.pro @@ -22,6 +22,7 @@ HEADERS += \ locality_finder.hpp \ params.hpp \ result.hpp \ + retrieval.hpp \ search_common.hpp \ search_engine.hpp \ search_query.hpp \ @@ -40,6 +41,7 @@ SOURCES += \ locality_finder.cpp \ params.cpp \ result.cpp \ + retrieval.cpp \ search_engine.cpp \ search_query.cpp \ search_query_params.cpp \ diff --git a/search/search_query.cpp b/search/search_query.cpp index cbc9732b2f..85eeee4e29 100644 --- a/search/search_query.cpp +++ b/search/search_query.cpp @@ -1746,7 +1746,7 @@ void Query::SearchLocality(MwmValue * pMwm, impl::Locality & res1, impl::Region trie::ValueReader(cp), trie::EdgeValueReader())); ForEachLangPrefix(params, *trieRoot, [&](TrieRootPrefix & langRoot, int8_t lang) - { + { impl::DoFindLocality doFind(*this, pMwm, lang); MatchTokensInTrie(params.m_tokens, langRoot, doFind); @@ -1859,7 +1859,7 @@ void Query::SearchInMWM(Index::MwmHandle const & mwmHandle, SearchQueryParams co FeaturesFilter filter( (viewportId == DEFAULT_V || isWorld) ? 0 : &m_offsetsInViewport[viewportId][mwmId], *this); MatchFeaturesInTrie(params, *trieRoot, filter, [&](TrieValueT const & value) - { + { AddResultFromTrie(value, mwmId, viewportId); }); } diff --git a/search/search_query_params.cpp b/search/search_query_params.cpp index de36c8bbc1..916c0393b3 100644 --- a/search/search_query_params.cpp +++ b/search/search_query_params.cpp @@ -1,6 +1,7 @@ #include "search/search_query_params.hpp" #include "indexer/feature_impl.hpp" +#include "indexer/scales.hpp" #include "base/assert.hpp" @@ -56,11 +57,14 @@ private: }; } // namespace +SearchQueryParams::SearchQueryParams() : m_scale(scales::GetUpperScale()) {} + void SearchQueryParams::Clear() { m_tokens.clear(); m_prefixTokens.clear(); m_langs.clear(); + m_scale = scales::GetUpperScale(); } void SearchQueryParams::EraseTokens(vector<size_t> & eraseInds) diff --git a/search/search_query_params.hpp b/search/search_query_params.hpp index 6bae19b42b..6646e6096c 100644 --- a/search/search_query_params.hpp +++ b/search/search_query_params.hpp @@ -17,6 +17,9 @@ struct SearchQueryParams vector<TSynonymsVector> m_tokens; TSynonymsVector m_prefixTokens; TLangsSet m_langs; + int m_scale; + + SearchQueryParams(); void Clear(); |