[search] Cache features in viewport. For now, search only among them.

This commit is contained in:
Yury Melnichek 2011-09-27 00:06:09 +02:00 committed by Alex Zolotarev
parent 20faf97e15
commit c8bbbfdf15
7 changed files with 125 additions and 33 deletions

View file

@ -625,19 +625,29 @@ void Framework<TModel>::StopScale(ScaleEvent const & e)
m_renderPolicy->StopScale(pt1, pt2, m_timer.ElapsedSeconds());
}
template<typename TModel>
search::Engine * Framework<TModel>::GetSearchEngine()
{
// Classical "double check" synchronization pattern.
if (!m_pSearchEngine)
{
threads::MutexGuard lock(m_modelSyn);
if (!m_pSearchEngine)
{
scoped_ptr<Reader> pReader(GetPlatform().GetReader(SEARCH_CATEGORIES_FILE_NAME));
m_pSearchEngine.reset(
new search::Engine(&m_model.GetIndex(), new search::CategoriesHolder(*pReader)));
}
}
return m_pSearchEngine.get();
}
template<typename TModel>
void Framework<TModel>::Search(string const & text, SearchCallbackT callback)
{
threads::MutexGuard lock(m_modelSyn);
if (!m_pSearchEngine.get())
{
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);
search::Engine * pSearchEngine = GetSearchEngine();
pSearchEngine->SetViewport(m_navigator.Screen().GlobalRect());
pSearchEngine->Search(text, callback);
}
template <typename TModel>

View file

@ -189,6 +189,7 @@ public:
bool isTiling);
void Search(string const & text, SearchCallbackT callback);
search::Engine * GetSearchEngine();
void SetMaxWorldRect();

View file

@ -7,6 +7,7 @@
#include "../std/queue.hpp"
#include "../std/scoped_ptr.hpp"
#include "../std/unordered_map.hpp"
#include "../std/unordered_set.hpp"
#include "../std/utility.hpp"
#include "../std/vector.hpp"
@ -106,14 +107,19 @@ struct OffsetIntersecter
{
typedef unordered_map<uint32_t, uint16_t> MapType;
unordered_set<uint32_t> const * m_pOffsetFilter;
MapType m_prevMap;
MapType m_map;
bool m_bFirstStep;
OffsetIntersecter() : m_bFirstStep(true) {}
explicit OffsetIntersecter(unordered_set<uint32_t> const * pOffsetFilter)
: m_pOffsetFilter(pOffsetFilter), m_bFirstStep(true) {}
void operator() (uint32_t offset, uint8_t rank)
{
if (m_pOffsetFilter && !m_pOffsetFilter->count(offset))
return;
uint16_t prevRankSum = 0;
if (!m_bFirstStep)
{
@ -141,10 +147,11 @@ template <typename F>
void MatchFeaturesInTrie(strings::UniString const * tokens, size_t tokenCount,
strings::UniString const & prefix,
TrieIterator const & trieRoot,
unordered_set<uint32_t> const * pOffsetsFilter,
F & f,
size_t resultsNeeded)
{
impl::OffsetIntersecter intersecter;
impl::OffsetIntersecter intersecter(pOffsetsFilter);
// Match tokens.
for (size_t i = 0; i < tokenCount; ++i)

View file

@ -16,19 +16,22 @@ namespace search
Engine::Engine(IndexType const * pIndex, CategoriesHolder * pCategories)
: m_pIndex(pIndex), m_pCategories(pCategories)
{
m_pQuery.reset(new Query(pIndex, pCategories));
}
Engine::~Engine()
{
}
void Engine::Search(string const & queryText,
m2::RectD const & viewport,
function<void (Result const &)> const & f)
void Engine::SetViewport(m2::RectD const & viewport)
{
LOG(LDEBUG, (queryText, viewport));
search::Query query(m_pIndex, m_pCategories.get());
query.Search(queryText, viewport, f);
m_pQuery->SetViewport(viewport);
}
void Engine::Search(string const & queryText, function<void (Result const &)> const & f)
{
LOG(LDEBUG, (queryText));
m_pQuery->Search(queryText, f);
f(Result::GetEndResult());
}

View file

@ -16,6 +16,7 @@ namespace search
{
class CategoriesHolder;
class Query;
class Result;
class Engine
@ -27,13 +28,13 @@ public:
Engine(IndexType const * pIndex, CategoriesHolder * pCategories);
~Engine();
void Search(string const & query,
m2::RectD const & rect,
function<void (Result const &)> const & f);
void SetViewport(m2::RectD const & viewport);
void Search(string const & query, function<void (Result const &)> const & f);
private:
Index const * m_pIndex;
scoped_ptr<CategoriesHolder> m_pCategories;
scoped_ptr<search::Query> m_pQuery;
};
} // namespace search

View file

@ -3,8 +3,10 @@
#include "feature_match.hpp"
#include "latlon_match.hpp"
#include "result.hpp"
#include "../indexer/feature_covering.hpp"
#include "../indexer/features_vector.hpp"
#include "../indexer/index.hpp"
#include "../indexer/scales.hpp"
#include "../indexer/search_delimiters.hpp"
#include "../indexer/search_string_utils.hpp"
#include "../base/logging.hpp"
@ -16,23 +18,88 @@ namespace search
{
Query::Query(Index const * pIndex, search::CategoriesHolder const * pCategories)
: m_pIndex(pIndex), m_pCategories(pCategories)
: m_pIndex(pIndex), m_pCategories(pCategories), m_viewport(m2::RectD::GetEmptyRect()),
m_viewportExtended(m2::RectD::GetEmptyRect())
{
}
Query::~Query()
{}
{
}
void Query::SetViewport(m2::RectD const & viewport)
{
// TODO: Clear m_viewportExtended when mwm index is added or removed!
if (m_viewport != viewport)
{
m_viewport = viewport;
m_viewportExtended = m_viewport;
m_viewportExtended.Scale(3);
UpdateViewportOffsets();
}
}
void Query::UpdateViewportOffsets()
{
vector<MwmInfo> mwmInfo;
m_pIndex->GetMwmInfo(mwmInfo);
m_offsetsInViewport.resize(mwmInfo.size());
int const scale = min(max(scales::GetScaleLevel(m_viewport) + 7, 10), scales::GetUpperScale());
covering::IntervalsT intervals[2];
bool intervalCovered[2] = {false, false};
for (MwmSet::MwmId mwmId = 0; mwmId < mwmInfo.size(); ++mwmId)
{
// Search only mwms that intersect with viewport (world always does).
if (m_viewportExtended.IsIntersect(mwmInfo[mwmId].m_limitRect))
{
Index::MwmLock mwmLock(*m_pIndex, mwmId);
if (MwmValue * pMwmValue = mwmLock.GetValue())
{
feature::DataHeader const & header = pMwmValue->GetHeader();
// TODO: Refactor me!
// prepare needed covering
int const cellDepth = covering::GetCodingDepth(header.GetScaleRange());
int const ind = (cellDepth == RectId::DEPTH_LEVELS ? 0 : 1);
if (!intervalCovered[ind])
{
covering::CoverViewportAndAppendLowerLevels(m_viewport, cellDepth, intervals[ind]);
intervalCovered[ind] = true;
}
ScaleIndex<ModelReaderPtr> index(pMwmValue->m_cont.GetReader(INDEX_FILE_TAG),
pMwmValue->m_factory);
for (size_t i = 0; i < intervals[ind].size(); ++i)
{
index.ForEachInIntervalAndScale(MakeInsertFunctor(m_offsetsInViewport[mwmId]),
intervals[ind][i].first, intervals[ind][i].second,
scale);
}
}
}
}
size_t offsetsCached = 0;
for (MwmSet::MwmId mwmId = 0; mwmId < mwmInfo.size(); ++mwmId)
offsetsCached += m_offsetsInViewport[mwmId].size();
LOG(LINFO, ("For search in viewport cached ",
"mwms:", mwmInfo.size(),
"offsets:", offsetsCached));
}
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 = NormalizeAndSimplifyString(m_rawQuery);
search::Delimiters delims;
@ -109,13 +176,10 @@ void Query::SearchFeatures()
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))
if (m_viewportExtended.IsIntersect(mwmInfo[mwmId].m_limitRect))
{
Index::MwmLock mwmLock(*m_pIndex, mwmId);
if (MwmValue * pMwmValue = mwmLock.GetValue())
@ -128,8 +192,8 @@ void Query::SearchFeatures()
{
FeaturesVector featuresVector(pMwmValue->m_cont, pMwmValue->GetHeader());
impl::FeatureLoader f(featuresVector, *this);
MatchFeaturesInTrie(m_tokens.data(), m_tokens.size(), m_prefix, *pTrieRoot, f,
m_results.max_size() * 10);
MatchFeaturesInTrie(m_tokens.data(), m_tokens.size(), m_prefix, *pTrieRoot,
&m_offsetsInViewport[mwmId], f, m_results.max_size() * 10);
LOG(LINFO, ("Matched: ", f.m_count));
}
}

View file

@ -5,6 +5,8 @@
#include "../base/limited_priority_queue.hpp"
#include "../std/function.hpp"
#include "../std/string.hpp"
#include "../std/unordered_set.hpp"
#include "../std/vector.hpp"
class Index;
@ -20,8 +22,8 @@ public:
Query(Index const * pIndex, CategoriesHolder const * pCategories);
~Query();
void SetViewport(m2::RectD const & viewport);
void Search(string const & query,
m2::RectD const & viewport,
function<void (Result const &)> const & f,
unsigned int resultsNeeded = 10);
@ -31,6 +33,7 @@ private:
void AddResult(impl::IntermediateResult const & result);
void FlushResults(function<void (Result const &)> const & f);
void UpdateViewportOffsets();
void SearchFeatures();
Index const * m_pIndex;
@ -41,6 +44,9 @@ private:
buffer_vector<strings::UniString, 32> m_tokens;
strings::UniString m_prefix;
m2::RectD m_viewport;
m2::RectD m_viewportExtended;
vector<unordered_set<uint32_t> > m_offsetsInViewport;
my::limited_priority_queue<impl::IntermediateResult> m_results;
};