[search] Brand new search :) For now, only name matching is used (i.e. no viewport intersection) and ranking is far from perfect.

This commit is contained in:
Yury Melnichek 2011-09-24 18:14:56 +02:00 committed by Alex Zolotarev
parent 6e9b2757f5
commit 3a0cb52832
21 changed files with 514 additions and 219 deletions

View file

@ -133,7 +133,8 @@ private:
ReadFeatureFunctor<F> 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);
}
}
}

View file

@ -48,22 +48,4 @@ struct EdgeValueReader
search::trie::ValueReader::ValueType,
search::trie::EdgeValueReader::ValueType> TrieIterator;
class SearchInfo
{
FeaturesVector m_features;
scoped_ptr<TrieIterator> 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

View file

@ -10,8 +10,6 @@
#include "../std/vector.hpp"
#include "../std/shared_ptr.hpp"
#include "../search/engine.hpp"
struct BenchmarkRectProvider;
class WindowHandle;
class PaintEvent;

View file

@ -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<TModel>::Clean()
template <typename TModel>
void Framework<TModel>::PrepareToShutdown()
{
if (m_pSearchEngine)
m_pSearchEngine->StopEverything();
}
template <typename TModel>
@ -634,11 +632,9 @@ void Framework<TModel>::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<Reader> 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);

View file

@ -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

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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<void (Result const &)> 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

View file

@ -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<void (Result const &)> const & f);
void StopEverything();
void OnQueryDelete(impl::Query *);
private:
IndexType const * m_pIndex;
SearchInfo * m_pSearchInfo;
scoped_ptr<CategoriesHolder> m_pCategories;
scoped_ptr<threads::IRunner> m_pRunner;
threads::Mutex m_mutex;
impl::Query * volatile m_pLastQuery;
int volatile m_queriesActive;
};
} // namespace search

176
search/feature_match.hpp Normal file
View file

@ -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 <class SrcIterT, class CompIterT>
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<search::TrieIterator> 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<search::TrieIterator>(pIter->GoToEdge(i)).swap(pIter);
symbolsMatched += count;
bMatched = true;
break;
}
}
if (!bMatched)
return NULL;
}
return pIter->Clone();
}
template <typename F>
void FullMatchInTrie(TrieIterator const & trieRoot,
strings::UniString const & s,
F & f)
{
size_t symbolsMatched = 0;
scoped_ptr<search::TrieIterator> 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 <typename F>
void PrefixMatchInTrie(TrieIterator const & trieRoot,
strings::UniString const & s,
F & f)
{
size_t symbolsMatched = 0;
scoped_ptr<search::TrieIterator> pIter(MoveTrieIteratorToString(trieRoot, s, symbolsMatched));
if (!pIter)
return;
priority_queue<pair<uint8_t, search::TrieIterator *> > 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<search::TrieIterator> 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<uint32_t, uint16_t> 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<uint16_t>(prevRankSum + rank));
}
void NextStep()
{
m_prevMap.swap(m_map);
m_map.clear();
m_bFirstStep = false;
}
};
} // namespace search::impl
template <typename F>
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<pair<uint32_t, uint16_t> > 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

View file

@ -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<void (Result const &)> const & f)
@ -289,19 +289,6 @@ void Query::Search(function<void (Result const &)> const & f)
f(Result(string(), string())); // Send last search result marker.
}
void Query::FlushResults(const function<void (const Result &)> &f)
{
vector<Result> results;
results.reserve(m_results.size());
while (!m_results.empty())
{
results.push_back(m_results.top().GenerateFinalResult());
m_results.pop();
}
for (vector<Result>::const_reverse_iterator it = results.rbegin(); it != results.rend(); ++it)
f(*it);
m_resultsRemaining = max(0, m_resultsRemaining - static_cast<int>(results.size()));
}
void Query::SearchAndDestroy(function<void (const Result &)> const & f)
{
@ -331,3 +318,4 @@ uint32_t Query::GetKeywordsToSkipForType(uint32_t const type) const
} // namespace search::impl
} // namespace search
*/

View file

@ -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<IntermediateResult> m_results;
int m_resultsRemaining;
Engine * m_pEngine;
bool volatile m_bTerminate;
};
} // namespace search::impl
} // namespace search
*/

View file

@ -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())

View file

@ -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.

View file

@ -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 \

35
search/search_engine.cpp Normal file
View file

@ -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<void (Result const &)> const & f)
{
LOG(LDEBUG, (queryText, viewport));
search::Query query(m_pIndex, m_pCategories.get());
query.Search(queryText, viewport, f);
f(Result::GetEndResult());
}
} // namespace search

39
search/search_engine.hpp Normal file
View file

@ -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<void (Result const &)> const & f);
private:
Index const * m_pIndex;
scoped_ptr<CategoriesHolder> m_pCategories;
};
} // namespace search

140
search/search_query.cpp Normal file
View file

@ -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<void (Result const &)> 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<impl::IntermediateResult>(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<void (Result const &)> const & f)
{
vector<impl::IntermediateResult> v(m_results.begin(), m_results.end());
sort_heap(v.begin(), v.end());
for (vector<impl::IntermediateResult>::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> 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<TrieIterator> 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

48
search/search_query.hpp Normal file
View file

@ -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<void (Result const &)> const & f,
unsigned int resultsNeeded = 10);
private:
friend class impl::FeatureLoader;
void AddResult(impl::IntermediateResult const & result);
void FlushResults(function<void (Result const &)> const & f);
void SearchFeatures();
Index const * m_pIndex;
CategoriesHolder const * m_pCategories;
string m_rawQuery;
strings::UniString m_uniQuery;
buffer_vector<strings::UniString, 32> m_tokens;
strings::UniString m_prefix;
m2::RectD m_viewport;
my::limited_priority_queue<impl::IntermediateResult> m_results;
};
} // namespace search

View file

@ -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<UniString> 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<UniString>(), Query("", m2::RectD(), 0, 0, 0, 0, 0).GetKeywords(), ());
TEST_EQUAL(MakeUniString(""), Query("", m2::RectD(), 0, 0, 0, 0, 0).GetPrefix(), ());
TEST_EQUAL(vector<UniString>(), 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<UniString>(), Query("", m2::RectD(), 0, 0, 0, 0).GetKeywords(), ());
TEST_EQUAL(MakeUniString(""), Query("", m2::RectD(), 0, 0, 0, 0).GetPrefix(), ());
TEST_EQUAL(vector<UniString>(), Query("Z", m2::RectD(), 0, 0, 0, 0).GetKeywords(), ());
TEST_EQUAL(MakeUniString("z"), Query("Z", m2::RectD(), 0, 0, 0, 0).GetPrefix(), ());
}
*/

View file

@ -11,7 +11,7 @@
#include "../std/utility.hpp"
#include "../std/vector.hpp"
/*
namespace
{
template <class SrcIterT, class CompIterT>
@ -120,3 +120,4 @@ void search::MatchAgainstTrie(search::impl::Query & query, search::TrieIterator
featureQueue.pop();
}
}
*/