From 3a0cb528328f1a4703eb384a912d17f8cceb9a37 Mon Sep 17 00:00:00 2001 From: Yury Melnichek Date: Sat, 24 Sep 2011 18:14:56 +0200 Subject: [PATCH] [search] Brand new search :) For now, only name matching is used (i.e. no viewport intersection) and ranking is far from perfect. --- indexer/index.hpp | 3 +- indexer/search_trie.hpp | 18 --- map/benchmark_framework.hpp | 2 - map/framework.cpp | 12 +- map/framework.hpp | 2 +- search/categories_holder.cpp | 12 ++ search/categories_holder.hpp | 4 + search/engine.cpp | 98 ---------------- search/engine.hpp | 56 --------- search/feature_match.hpp | 176 +++++++++++++++++++++++++++++ search/query.cpp | 28 ++--- search/query.hpp | 9 +- search/result.cpp | 7 ++ search/result.hpp | 1 + search/search.pro | 21 +++- search/search_engine.cpp | 35 ++++++ search/search_engine.hpp | 39 +++++++ search/search_query.cpp | 140 +++++++++++++++++++++++ search/search_query.hpp | 48 ++++++++ search/search_tests/query_test.cpp | 19 ++-- search/search_trie_matching.cpp | 3 +- 21 files changed, 514 insertions(+), 219 deletions(-) delete mode 100644 search/engine.cpp delete mode 100644 search/engine.hpp create mode 100644 search/feature_match.hpp create mode 100644 search/search_engine.cpp create mode 100644 search/search_engine.hpp create mode 100644 search/search_query.cpp create mode 100644 search/search_query.hpp diff --git a/indexer/index.hpp b/indexer/index.hpp index 0fc0d5673e..51793b78b7 100644 --- a/indexer/index.hpp +++ b/indexer/index.hpp @@ -133,7 +133,8 @@ private: ReadFeatureFunctor f1(fv, f, offsets); for (size_t i = 0; i < intervals[ind].size(); ++i) { - index.ForEachInIntervalAndScale(f1, intervals[ind][i].first, intervals[ind][i].second, scale); + index.ForEachInIntervalAndScale(f1, intervals[ind][i].first, intervals[ind][i].second, + scale); } } } diff --git a/indexer/search_trie.hpp b/indexer/search_trie.hpp index 9538efb716..a3535a4205 100644 --- a/indexer/search_trie.hpp +++ b/indexer/search_trie.hpp @@ -48,22 +48,4 @@ struct EdgeValueReader search::trie::ValueReader::ValueType, search::trie::EdgeValueReader::ValueType> TrieIterator; - class SearchInfo - { - FeaturesVector m_features; - scoped_ptr m_iterator; - - public: - SearchInfo(FilesContainerR const & cont, feature::DataHeader const & header) - : m_features(cont, header), - m_iterator(::trie::reader::ReadTrie( - cont.GetReader(SEARCH_INDEX_FILE_TAG), - trie::ValueReader(), - trie::EdgeValueReader())) - { - } - - TrieIterator * GetTrie() { return m_iterator.get(); } - FeaturesVector * GetFeatures() { return &m_features; } - }; } // namespace search diff --git a/map/benchmark_framework.hpp b/map/benchmark_framework.hpp index ad652bb9c7..1ddc6c578c 100644 --- a/map/benchmark_framework.hpp +++ b/map/benchmark_framework.hpp @@ -10,8 +10,6 @@ #include "../std/vector.hpp" #include "../std/shared_ptr.hpp" -#include "../search/engine.hpp" - struct BenchmarkRectProvider; class WindowHandle; class PaintEvent; diff --git a/map/framework.cpp b/map/framework.cpp index 568de21cc0..b029156857 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -9,7 +9,7 @@ #include "../platform/settings.hpp" -#include "../search/engine.hpp" +#include "../search/search_engine.hpp" #include "../search/result.hpp" #include "../search/categories_holder.hpp" @@ -224,8 +224,6 @@ void Framework::Clean() template void Framework::PrepareToShutdown() { - if (m_pSearchEngine) - m_pSearchEngine->StopEverything(); } template @@ -634,11 +632,9 @@ void Framework::Search(string const & text, SearchCallbackT callback) if (!m_pSearchEngine.get()) { - search::CategoriesHolder holder; - string buffer; - ReaderT(GetPlatform().GetReader(SEARCH_CATEGORIES_FILE_NAME)).ReadAsString(buffer); - holder.LoadFromStream(buffer); - m_pSearchEngine.reset(new search::Engine(&m_model.GetIndex(), holder)); + scoped_ptr pReader(GetPlatform().GetReader(SEARCH_CATEGORIES_FILE_NAME)); + m_pSearchEngine.reset( + new search::Engine(&m_model.GetIndex(), new search::CategoriesHolder(*pReader))); } m_pSearchEngine->Search(text, m_navigator.Screen().GlobalRect(), callback); diff --git a/map/framework.hpp b/map/framework.hpp index ec58117589..3e0faf1aed 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -41,7 +41,7 @@ #include "../std/shared_ptr.hpp" #include "../std/target_os.hpp" -#include "../search/engine.hpp" +#include "../search/search_engine.hpp" //#define DRAW_TOUCH_POINTS diff --git a/search/categories_holder.cpp b/search/categories_holder.cpp index 909495bb4e..a6bc854993 100644 --- a/search/categories_holder.cpp +++ b/search/categories_holder.cpp @@ -106,6 +106,7 @@ size_t CategoriesHolder::LoadFromStream(string const & buffer) if (!cat.m_synonyms.empty() && !cat.m_types.empty()) m_categories.push_back(cat); + LOG(LINFO, ("Categories loaded: ", m_categories.size())); return m_categories.size(); } @@ -114,4 +115,15 @@ void CategoriesHolder::swap(CategoriesHolder & o) m_categories.swap(o.m_categories); } +CategoriesHolder::CategoriesHolder() +{ +} + +CategoriesHolder::CategoriesHolder(Reader const & reader) +{ + string buffer; + reader.ReadAsString(buffer); + LoadFromStream(buffer); +} + } diff --git a/search/categories_holder.hpp b/search/categories_holder.hpp index b331ef9c45..f96b691994 100644 --- a/search/categories_holder.hpp +++ b/search/categories_holder.hpp @@ -5,6 +5,7 @@ #include "../std/string.hpp" #include "../std/algorithm.hpp" +class Reader; namespace search { @@ -33,6 +34,9 @@ class CategoriesHolder public: typedef ContainerT::const_iterator const_iterator; + CategoriesHolder(); + explicit CategoriesHolder(Reader const & reader); + /// @return number of loaded categories or 0 if something goes wrong size_t LoadFromStream(string const & buffer); diff --git a/search/engine.cpp b/search/engine.cpp deleted file mode 100644 index 155fb002dc..0000000000 --- a/search/engine.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "categories_holder.hpp" -#include "engine.hpp" -#include "query.hpp" -#include "result.hpp" - -#include "../platform/concurrent_runner.hpp" - -#include "../base/logging.hpp" - -#include "../std/bind.hpp" -#include "../std/function.hpp" -#include "../std/string.hpp" -#include "../std/vector.hpp" - - -namespace search -{ - -Engine::Engine(IndexType const * pIndex, - CategoriesHolder & categories) - : m_pIndex(pIndex), m_pSearchInfo(NULL), - m_pCategories(new CategoriesHolder()), - m_pRunner(new threads::ConcurrentRunner), m_pLastQuery(NULL), - m_queriesActive(0) -{ - m_pCategories->swap(categories); -} - -Engine::~Engine() -{ - LOG(LDEBUG, (m_queriesActive)); - ASSERT_EQUAL(m_queriesActive, 0, ()); -} - -void Engine::Search(string const & queryText, - m2::RectD const & rect, - function const & f) -{ - LOG(LDEBUG, (queryText, rect)); - - impl::Query * pQuery = - new impl::Query(queryText, rect, m_pIndex, this, m_pCategories.get(), - m_pSearchInfo->GetTrie(), m_pSearchInfo->GetFeatures()); - - { - threads::MutexGuard mutexGuard(m_mutex); - UNUSED_VALUE(mutexGuard); - - ASSERT_GREATER_OR_EQUAL(m_queriesActive, 0, ()); - - if (m_pLastQuery) - { - LOG(LDEBUG, ("Stopping previous", m_pLastQuery->GetQueryText(), m_pLastQuery->GetViewport())); - m_pLastQuery->SetTerminateFlag(); - } - - m_pLastQuery = pQuery; - ++m_queriesActive; - LOG(LDEBUG, ("Queries active", m_queriesActive)); - } - - m_pRunner->Run(bind(&impl::Query::SearchAndDestroy, pQuery, f)); -} - -void Engine::OnQueryDelete(impl::Query * pQuery) -{ - threads::MutexGuard mutexGuard(m_mutex); - UNUSED_VALUE(mutexGuard); - - ASSERT_GREATER_OR_EQUAL(m_queriesActive, 1, ()); - - --m_queriesActive; - LOG(LDEBUG, ("Queries active", m_queriesActive)); - LOG(LDEBUG, ("Query destroyed", pQuery->GetQueryText(), pQuery->GetViewport())); - - if (m_pLastQuery == pQuery) - { - LOG(LDEBUG, ("Last query destroyed")); - m_pLastQuery = NULL; - } -} - -void Engine::StopEverything() -{ - threads::MutexGuard mutexGuard(m_mutex); - UNUSED_VALUE(mutexGuard); - - ASSERT_GREATER_OR_EQUAL(m_queriesActive, 0, ()); - LOG(LINFO, (m_queriesActive, m_pLastQuery)); - - if (m_pLastQuery) - { - LOG(LDEBUG, ("Stopping previous", m_pLastQuery->GetQueryText(), m_pLastQuery->GetViewport())); - m_pLastQuery->SetTerminateFlag(); - } -} - -} // namespace search diff --git a/search/engine.hpp b/search/engine.hpp deleted file mode 100644 index 9375409a45..0000000000 --- a/search/engine.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include "../indexer/index.hpp" -#include "../indexer/search_trie.hpp" - -#include "../geometry/rect2d.hpp" - -#include "../base/base.hpp" -#include "../base/mutex.hpp" -#include "../base/runner.hpp" - -#include "../std/function.hpp" -#include "../std/scoped_ptr.hpp" -#include "../std/string.hpp" - - -class Reader; -class ModelReaderPtr; -class FeatureType; - -namespace search -{ - -namespace impl { class Query; } -class CategoriesHolder; -class Result; - -class Engine -{ -public: - typedef Index IndexType; - - /// Doesn't take ownership of @pIndex and @pTrieIterator. Modifies @categories. - Engine(IndexType const * pIndex, - CategoriesHolder & categories); - ~Engine(); - - void Search(string const & query, - m2::RectD const & rect, - function const & f); - - void StopEverything(); - - void OnQueryDelete(impl::Query *); - -private: - IndexType const * m_pIndex; - SearchInfo * m_pSearchInfo; - scoped_ptr m_pCategories; - scoped_ptr m_pRunner; - threads::Mutex m_mutex; - impl::Query * volatile m_pLastQuery; - int volatile m_queriesActive; -}; - -} // namespace search diff --git a/search/feature_match.hpp b/search/feature_match.hpp new file mode 100644 index 0000000000..e322545074 --- /dev/null +++ b/search/feature_match.hpp @@ -0,0 +1,176 @@ +#pragma once +#include "../indexer/search_trie.hpp" +#include "../base/string_utils.hpp" +#include "../base/base.hpp" +#include "../std/algorithm.hpp" +#include "../std/bind.hpp" +#include "../std/queue.hpp" +#include "../std/scoped_ptr.hpp" +#include "../std/unordered_map.hpp" +#include "../std/utility.hpp" +#include "../std/vector.hpp" + +namespace search +{ +namespace impl +{ + +template +size_t CalcEqualLength(SrcIterT b, SrcIterT e, CompIterT bC, CompIterT eC) +{ + size_t count = 0; + while ((b != e) && (bC != eC) && (*b++ == *bC++)) + ++count; + return count; +} + +TrieIterator * MoveTrieIteratorToString(TrieIterator const & trieRoot, + strings::UniString const & queryS, + size_t & symbolsMatched) +{ + scoped_ptr pIter(trieRoot.Clone()); + symbolsMatched = 0; + size_t const szQuery = queryS.size(); + while (symbolsMatched < szQuery) + { + bool bMatched = false; + + for (size_t i = 0; i < pIter->m_edge.size(); ++i) + { + size_t const szEdge = pIter->m_edge[i].m_str.size(); + + size_t const count = CalcEqualLength(pIter->m_edge[i].m_str.begin(), + pIter->m_edge[i].m_str.end(), + queryS.begin() + symbolsMatched, + queryS.end()); + + if ((count > 0) && (count == szEdge || szQuery == count + symbolsMatched)) + { + scoped_ptr(pIter->GoToEdge(i)).swap(pIter); + symbolsMatched += count; + bMatched = true; + break; + } + } + + if (!bMatched) + return NULL; + } + return pIter->Clone(); +} + +template +void FullMatchInTrie(TrieIterator const & trieRoot, + strings::UniString const & s, + F & f) +{ + size_t symbolsMatched = 0; + scoped_ptr pIter(MoveTrieIteratorToString(trieRoot, s, symbolsMatched)); + if (!pIter || symbolsMatched != s.size()) + return; + for (size_t i = 0; i < pIter->m_value.size(); ++i) + f(pIter->m_value[i].m_featureId, pIter->m_value[i].m_rank); +} + +template +void PrefixMatchInTrie(TrieIterator const & trieRoot, + strings::UniString const & s, + F & f) +{ + size_t symbolsMatched = 0; + scoped_ptr pIter(MoveTrieIteratorToString(trieRoot, s, symbolsMatched)); + if (!pIter) + return; + + priority_queue > trieQueue; + trieQueue.push(make_pair(uint8_t(-1), pIter->Clone())); + + uint8_t maxRank = 0; + for (size_t i = 0; i < pIter->m_edge.size(); ++i) + maxRank = max(maxRank, pIter->m_edge[i].m_value); + + int featuresStillToMatch = 100000; + while (!trieQueue.empty() && (featuresStillToMatch > 0 || trieQueue.top().first == maxRank)) + { + scoped_ptr pIter(trieQueue.top().second); + trieQueue.pop(); + for (size_t i = 0; i < pIter->m_value.size(); ++i) + f(pIter->m_value[i].m_featureId, pIter->m_value[i].m_rank); + featuresStillToMatch -= pIter->m_value.size(); + for (size_t i = 0; i < pIter->m_edge.size(); ++i) + trieQueue.push(make_pair(pIter->m_edge[i].m_value, pIter->GoToEdge(i))); + } +} + +struct OffsetIntersecter +{ + typedef unordered_map MapType; + + MapType m_prevMap; + MapType m_map; + bool m_bFirstStep; + + void operator() (uint32_t offset, uint8_t rank) + { + uint16_t prevRankSum = 0; + if (!m_bFirstStep) + { + MapType::const_iterator it = m_prevMap.find(offset); + if (it == m_prevMap.end()) + return; + prevRankSum = it->second; + } + + uint16_t & mappedRank = m_map[offset]; + mappedRank = max(mappedRank, static_cast(prevRankSum + rank)); + } + + void NextStep() + { + m_prevMap.swap(m_map); + m_map.clear(); + m_bFirstStep = false; + } +}; + +} // namespace search::impl + +template +void MatchFeaturesInTrie(strings::UniString const * tokens, size_t tokenCount, + strings::UniString const & prefix, + TrieIterator const & trieRoot, + F & f, + size_t resultsNeeded) +{ + impl::OffsetIntersecter intersecter; + + // Match tokens. + for (size_t i = 0; i < tokenCount; ++i) + { + impl::FullMatchInTrie(trieRoot, tokens[i], intersecter); + intersecter.NextStep(); + } + + // Match prefix. + if (prefix.size() > 0) + { + impl::PrefixMatchInTrie(trieRoot, prefix, intersecter); + intersecter.NextStep(); + } + + typedef vector > ResType; + ResType res(intersecter.m_prevMap.begin(), intersecter.m_prevMap.end()); + + if (res.size() > resultsNeeded) + { + partial_sort(res.begin(), res.begin() + resultsNeeded, res.end(), + bind(&ResType::value_type::second, _1) > bind(&ResType::value_type::second, _2)); + res.resize(resultsNeeded); + } + + for (ResType::const_iterator it = res.begin(); it != res.end(); ++it) + f(it->first); +} + + +} // namespace search diff --git a/search/query.cpp b/search/query.cpp index 88caaed8ef..334b290f1e 100644 --- a/search/query.cpp +++ b/search/query.cpp @@ -15,7 +15,7 @@ #include "../std/algorithm.hpp" #include "../std/scoped_ptr.hpp" - +/* namespace search { namespace impl @@ -68,7 +68,7 @@ struct FeatureMatcher explicit FeatureMatcher(KeywordMatcher & keywordMatcher) : m_keywordMatcher(keywordMatcher), m_minScore(keywordMatcher.MAX_SCORE) {} - bool operator () (int /*lang*/, string const & name) + bool operator () (int , string const & name) { uint32_t const score = m_keywordMatcher.Score(name); if (score < m_minScore) @@ -131,16 +131,18 @@ struct FeatureProcessor } // unnamed namespace Query::Query(string const & query, m2::RectD const & viewport, IndexType const * pIndex, - Engine * pEngine, CategoriesHolder * pCategories, + CategoriesHolder * pCategories, TrieIterator * pTrieRoot, FeaturesVector * pFeatures) : m_queryText(query), m_queryUniText(NormalizeAndSimplifyString(query)), m_viewport(viewport), m_pCategories(pCategories), m_pTrieRoot(pTrieRoot), m_pFeatures(pFeatures), - m_pIndex(/*pIndex ? new IndexType(*pIndex) : */NULL), + m_pIndex( + // pIndex ? new IndexType(*pIndex) : + NULL), m_resultsRemaining(10), - m_pEngine(pEngine), m_bTerminate(false) + m_bTerminate(false) { search::Delimiters delims; SplitUniString(m_queryUniText, MakeBackInsertFunctor(m_keywords), delims); @@ -157,8 +159,6 @@ Query::Query(string const & query, m2::RectD const & viewport, IndexType const * Query::~Query() { - if (m_pEngine) - m_pEngine->OnQueryDelete(this); } void Query::Search(function const & f) @@ -289,19 +289,6 @@ void Query::Search(function const & f) f(Result(string(), string())); // Send last search result marker. } -void Query::FlushResults(const function &f) -{ - vector results; - results.reserve(m_results.size()); - while (!m_results.empty()) - { - results.push_back(m_results.top().GenerateFinalResult()); - m_results.pop(); - } - for (vector::const_reverse_iterator it = results.rbegin(); it != results.rend(); ++it) - f(*it); - m_resultsRemaining = max(0, m_resultsRemaining - static_cast(results.size())); -} void Query::SearchAndDestroy(function const & f) { @@ -331,3 +318,4 @@ uint32_t Query::GetKeywordsToSkipForType(uint32_t const type) const } // namespace search::impl } // namespace search +*/ diff --git a/search/query.hpp b/search/query.hpp index 356259665c..9ee8fc9c26 100644 --- a/search/query.hpp +++ b/search/query.hpp @@ -1,9 +1,12 @@ #pragma once -#include "engine.hpp" +/* + +#include "search_engine.hpp" #include "intermediate_result.hpp" #include "keyword_matcher.hpp" #include "result.hpp" +#include "../indexer/search_trie.hpp" #include "../geometry/rect2d.hpp" #include "../base/string_utils.hpp" #include "../std/function.hpp" @@ -27,7 +30,7 @@ public: typedef Engine::IndexType IndexType; Query(string const & query, m2::RectD const & viewport, IndexType const * pIndex, - Engine * pEngine, CategoriesHolder * pCategories, + CategoriesHolder * pCategories, TrieIterator * pTrieRoot, FeaturesVector * pFeatures); ~Query(); @@ -71,9 +74,9 @@ private: priority_queue m_results; int m_resultsRemaining; - Engine * m_pEngine; bool volatile m_bTerminate; }; } // namespace search::impl } // namespace search +*/ diff --git a/search/result.cpp b/search/result.cpp index fed481f355..f8740d9a41 100644 --- a/search/result.cpp +++ b/search/result.cpp @@ -18,6 +18,13 @@ Result::Result(string const & str, string const & suggestionStr) { } +Result Result::GetEndResult() +{ + Result result("", ""); + ASSERT(result.IsEndMarker(), ()); + return result; +} + Result::ResultType Result::GetResultType() const { if (!m_suggestionStr.empty()) diff --git a/search/result.hpp b/search/result.hpp index 7f43ca4b21..69870caf13 100644 --- a/search/result.hpp +++ b/search/result.hpp @@ -19,6 +19,7 @@ public: double distanceFromCenter, double directionFromCenter); Result(string const & str, string const & suggestionStr); + static Result GetEndResult(); bool IsEndMarker() const { return m_str.empty(); } // String that is displayed in the GUI. diff --git a/search/search.pro b/search/search.pro index ac49ae3e80..97bf4b70ba 100644 --- a/search/search.pro +++ b/search/search.pro @@ -11,23 +11,40 @@ include($$ROOT_DIR/common.pri) HEADERS += \ search_common.hpp \ - engine.hpp \ + search_engine.hpp \ intermediate_result.hpp \ keyword_matcher.hpp \ query.hpp \ + search_query.hpp \ result.hpp \ latlon_match.hpp \ categories_holder.hpp \ search_trie_matching.hpp \ approximate_string_match.hpp \ + feature_match.hpp \ SOURCES += \ - engine.cpp \ + search_engine.cpp \ intermediate_result.cpp \ keyword_matcher.cpp \ query.cpp \ + search_query.cpp \ result.cpp \ latlon_match.cpp \ categories_holder.cpp \ search_trie_matching.cpp \ approximate_string_match.cpp \ + + + + + + + + + + + + + + diff --git a/search/search_engine.cpp b/search/search_engine.cpp new file mode 100644 index 0000000000..fe8b5cb374 --- /dev/null +++ b/search/search_engine.cpp @@ -0,0 +1,35 @@ +#include "search_engine.hpp" +#include "categories_holder.hpp" +#include "result.hpp" +#include "search_query.hpp" + +#include "../base/logging.hpp" + +#include "../std/function.hpp" +#include "../std/string.hpp" +#include "../std/vector.hpp" + + +namespace search +{ + +Engine::Engine(IndexType const * pIndex, CategoriesHolder * pCategories) + : m_pIndex(pIndex), m_pCategories(pCategories) +{ +} + +Engine::~Engine() +{ +} + +void Engine::Search(string const & queryText, + m2::RectD const & viewport, + function const & f) +{ + LOG(LDEBUG, (queryText, viewport)); + search::Query query(m_pIndex, m_pCategories.get()); + query.Search(queryText, viewport, f); + f(Result::GetEndResult()); +} + +} // namespace search diff --git a/search/search_engine.hpp b/search/search_engine.hpp new file mode 100644 index 0000000000..c76b0b500b --- /dev/null +++ b/search/search_engine.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include "../indexer/index.hpp" + +#include "../geometry/rect2d.hpp" + +#include "../base/base.hpp" + +#include "../std/function.hpp" +#include "../std/scoped_ptr.hpp" +#include "../std/string.hpp" + +class Index; + +namespace search +{ + +class CategoriesHolder; +class Result; + +class Engine +{ +public: + typedef Index IndexType; + + // Doesn't take ownership of @pIndex. Takes ownership of pCategories + Engine(IndexType const * pIndex, CategoriesHolder * pCategories); + ~Engine(); + + void Search(string const & query, + m2::RectD const & rect, + function const & f); + +private: + Index const * m_pIndex; + scoped_ptr m_pCategories; +}; + +} // namespace search diff --git a/search/search_query.cpp b/search/search_query.cpp new file mode 100644 index 0000000000..4417b04278 --- /dev/null +++ b/search/search_query.cpp @@ -0,0 +1,140 @@ +#include "search_query.hpp" +#include "categories_holder.hpp" +#include "feature_match.hpp" +#include "latlon_match.hpp" +#include "result.hpp" +#include "../indexer/features_vector.hpp" +#include "../indexer/index.hpp" +#include "../indexer/search_delimiters.hpp" +#include "../indexer/search_string_utils.hpp" +#include "../base/logging.hpp" +#include "../base/string_utils.hpp" +#include "../base/stl_add.hpp" +#include "../std/algorithm.hpp" + +namespace search +{ + +Query::Query(Index const * pIndex, search::CategoriesHolder const * pCategories) + : m_pIndex(pIndex), m_pCategories(pCategories) +{ +} + +Query::~Query() +{} + +void Query::Search(string const & query, + m2::RectD const & viewport, + function const & f, + unsigned int resultsNeeded) +{ + // Initialize. + { + m_rawQuery = query; + m_viewport = viewport; + + m_uniQuery = strings::MakeUniString(m_rawQuery); + + search::Delimiters delims; + SplitUniString(m_uniQuery, MakeBackInsertFunctor(m_tokens), delims); + if (!m_tokens.empty() && !delims(strings::LastUniChar(m_rawQuery))) + { + m_prefix.swap(m_tokens.back()); + m_tokens.pop_back(); + } + if (m_tokens.size() > 31) + m_tokens.resize(31); + + m_results = my::limited_priority_queue(resultsNeeded); + } + + // Match (lat, lon). + { + double lat, lon, latPrec, lonPrec; + if (search::MatchLatLon(m_rawQuery, lat, lon, latPrec, lonPrec)) + { + double const precision = 5.0 * max(0.0001, min(latPrec, lonPrec)); // Min 55 meters + AddResult(impl::IntermediateResult(m_viewport, lat, lon, precision)); + } + } + + SearchFeatures(); + + FlushResults(f); +} + +void Query::AddResult(impl::IntermediateResult const & result) +{ + m_results.push(result); +} + +void Query::FlushResults(function const & f) +{ + vector v(m_results.begin(), m_results.end()); + sort_heap(v.begin(), v.end()); + for (vector::const_iterator it = v.begin(); it != v.end(); ++it) + f(it->GenerateFinalResult()); +} + +namespace impl +{ + +struct FeatureLoader +{ + uint32_t m_count; + FeaturesVector & m_featuresVector; + Query & m_query; + + FeatureLoader(FeaturesVector & featuresVector, Query & query) + : m_count(0), m_featuresVector(featuresVector), m_query(query) + { + } + + void operator() (uint32_t offset) + { + ++m_count; + FeatureType feature; + m_featuresVector.Get(offset, feature); + m_query.AddResult(impl::IntermediateResult(m_query.m_viewport, feature, + feature.GetPreferredDrawableName(), 0, 0)); + } +}; + +} // namespace search::impl + +void Query::SearchFeatures() +{ + if (!m_pIndex) + return; + + vector mwmInfo; + m_pIndex->GetMwmInfo(mwmInfo); + + m2::RectD extendedViewport = m_viewport; + extendedViewport.Scale(3); + + for (MwmSet::MwmId mwmId = 0; mwmId < mwmInfo.size(); ++mwmId) + { + // Search only mwms that intersect with viewport (world always does). + if (extendedViewport.IsIntersect(mwmInfo[mwmId].m_limitRect)) + { + Index::MwmLock mwmLock(*m_pIndex, mwmId); + if (MwmValue * pMwmValue = mwmLock.GetValue()) + { + scoped_ptr pTrieRoot(::trie::reader::ReadTrie( + pMwmValue->m_cont.GetReader(SEARCH_INDEX_FILE_TAG), + ::search::trie::ValueReader(), + ::search::trie::EdgeValueReader())); + if (pTrieRoot) + { + FeaturesVector featuresVector(pMwmValue->m_cont, pMwmValue->GetHeader()); + impl::FeatureLoader f(featuresVector, *this); + MatchFeaturesInTrie(m_tokens.data(), m_tokens.size(), m_prefix, *pTrieRoot, f, 10); + LOG(LINFO, ("Matched: ", f.m_count)); + } + } + } + } +} + +} // namespace search diff --git a/search/search_query.hpp b/search/search_query.hpp new file mode 100644 index 0000000000..6db12c5090 --- /dev/null +++ b/search/search_query.hpp @@ -0,0 +1,48 @@ +#pragma once +#include "intermediate_result.hpp" +#include "../geometry/rect2d.hpp" +#include "../base/buffer_vector.hpp" +#include "../base/limited_priority_queue.hpp" +#include "../std/function.hpp" +#include "../std/string.hpp" + +class Index; + +namespace search +{ + +class CategoriesHolder; +namespace impl { class IntermediateResult; class FeatureLoader; } + +class Query +{ +public: + Query(Index const * pIndex, CategoriesHolder const * pCategories); + ~Query(); + + void Search(string const & query, + m2::RectD const & viewport, + function const & f, + unsigned int resultsNeeded = 10); + +private: + + friend class impl::FeatureLoader; + + void AddResult(impl::IntermediateResult const & result); + void FlushResults(function const & f); + void SearchFeatures(); + + Index const * m_pIndex; + CategoriesHolder const * m_pCategories; + + string m_rawQuery; + strings::UniString m_uniQuery; + buffer_vector m_tokens; + strings::UniString m_prefix; + m2::RectD m_viewport; + + my::limited_priority_queue m_results; +}; + +} // namespace search diff --git a/search/search_tests/query_test.cpp b/search/search_tests/query_test.cpp index 2940bfbff9..49a0227318 100644 --- a/search/search_tests/query_test.cpp +++ b/search/search_tests/query_test.cpp @@ -3,7 +3,7 @@ #include "../../base/string_utils.hpp" #include "../../std/memcpy.hpp" #include "../../std/string.hpp" - +/* using search::impl::Query; using strings::MakeUniString; using strings::UniString; @@ -13,16 +13,17 @@ UNIT_TEST(QueryParseKeywords_Smoke) vector expected; expected.push_back(MakeUniString("minsk")); expected.push_back(MakeUniString("belarus")); - TEST_EQUAL(expected, Query("minsk belarus ", m2::RectD(), 0, 0, 0, 0, 0).GetKeywords(), ()); - TEST_EQUAL(MakeUniString(""), Query("minsk belarus ", m2::RectD(), 0, 0, 0, 0, 0).GetPrefix(), ()); - TEST_EQUAL(expected, Query("minsk belarus ma", m2::RectD(), 0, 0, 0, 0, 0).GetKeywords(), ()); - TEST_EQUAL(MakeUniString("ma"), Query("minsk belarus ma", m2::RectD(), 0, 0, 0, 0, 0).GetPrefix(), ()); + TEST_EQUAL(expected, Query("minsk belarus ", m2::RectD(), 0, 0, 0, 0).GetKeywords(), ()); + TEST_EQUAL(MakeUniString(""), Query("minsk belarus ", m2::RectD(), 0, 0, 0, 0).GetPrefix(), ()); + TEST_EQUAL(expected, Query("minsk belarus ma", m2::RectD(), 0, 0, 0, 0).GetKeywords(), ()); + TEST_EQUAL(MakeUniString("ma"), Query("minsk belarus ma", m2::RectD(), 0, 0, 0, 0).GetPrefix(), ()); } UNIT_TEST(QueryParseKeywords_Empty) { - TEST_EQUAL(vector(), Query("", m2::RectD(), 0, 0, 0, 0, 0).GetKeywords(), ()); - TEST_EQUAL(MakeUniString(""), Query("", m2::RectD(), 0, 0, 0, 0, 0).GetPrefix(), ()); - TEST_EQUAL(vector(), Query("Z", m2::RectD(), 0, 0, 0, 0, 0).GetKeywords(), ()); - TEST_EQUAL(MakeUniString("z"), Query("Z", m2::RectD(), 0, 0, 0, 0, 0).GetPrefix(), ()); + TEST_EQUAL(vector(), Query("", m2::RectD(), 0, 0, 0, 0).GetKeywords(), ()); + TEST_EQUAL(MakeUniString(""), Query("", m2::RectD(), 0, 0, 0, 0).GetPrefix(), ()); + TEST_EQUAL(vector(), Query("Z", m2::RectD(), 0, 0, 0, 0).GetKeywords(), ()); + TEST_EQUAL(MakeUniString("z"), Query("Z", m2::RectD(), 0, 0, 0, 0).GetPrefix(), ()); } +*/ diff --git a/search/search_trie_matching.cpp b/search/search_trie_matching.cpp index eea1d24e3b..0f438c6790 100644 --- a/search/search_trie_matching.cpp +++ b/search/search_trie_matching.cpp @@ -11,7 +11,7 @@ #include "../std/utility.hpp" #include "../std/vector.hpp" - +/* namespace { template @@ -120,3 +120,4 @@ void search::MatchAgainstTrie(search::impl::Query & query, search::TrieIterator featureQueue.pop(); } } +*/