forked from organicmaps/organicmaps
[search] Cache features in viewport. For now, search only among them.
This commit is contained in:
parent
20faf97e15
commit
c8bbbfdf15
7 changed files with 125 additions and 33 deletions
|
@ -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>
|
||||
|
|
|
@ -189,6 +189,7 @@ public:
|
|||
bool isTiling);
|
||||
|
||||
void Search(string const & text, SearchCallbackT callback);
|
||||
search::Engine * GetSearchEngine();
|
||||
|
||||
void SetMaxWorldRect();
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue