Merge pull request #4502 from ygorshenin/exposing-hotels

[search] HotelsClassifier can be used on the UI side now.
This commit is contained in:
alexzatsepin 2016-10-14 17:37:50 +03:00 committed by GitHub
commit cc252729f0
12 changed files with 128 additions and 88 deletions

View file

@ -391,6 +391,8 @@ extern "C"
vparams.m_inputLocale = ReplaceDeprecatedLanguageCode(jni::ToNativeString(env, lang));
vparams.m_hotelsFilter = g_hotelsFilterBuilder.Build(env, hotelsFilter);
// TODO (@alexzatsepin): set up vparams.m_onCompleted here and use
// HotelsClassifier for hotel queries detection.
g_framework->NativeFramework()->SearchInViewport(vparams);
if (isMapAndTable)

View file

@ -99,7 +99,8 @@ using TObservers = NSHashTable<__kindof TObserver>;
}
{
__weak auto weakSelf = self;
m_viewportParams.m_onCompleted = [weakSelf] {
m_viewportParams.m_onCompleted = [weakSelf](search::Results const & results) {
// TODO (@igrechuhin): do something useful with |results|.
__strong auto self = weakSelf;
if (!self)
return;

View file

@ -1154,7 +1154,7 @@ bool Framework::SearchInViewport(search::ViewportSearchParams const & params)
static_cast<search::ViewportSearchCallback::Delegate &>(*this),
[params](search::Results const & results) {
if (results.IsEndMarker() && params.m_onCompleted)
GetPlatform().RunOnGuiThread([params]() { params.m_onCompleted(); });
GetPlatform().RunOnGuiThread([params, results]() { params.m_onCompleted(results); });
});
SetCurrentPositionIfPossible(p);
@ -2673,7 +2673,9 @@ bool Framework::ParseEditorDebugCommand(search::SearchParams const & params)
DebugPrint(types), types.GetBestType(), smd));
}
params.m_onResults(results);
params.m_onResults(search::Results::GetEndMarker(false));
results.SetEndMarker(false /* isCancelled */);
params.m_onResults(results);
return true;
}
else if (params.m_query == "?eclear")

View file

@ -31,8 +31,9 @@ public:
inline void Finish(bool cancelled)
{
m_results.SetEndMarker(cancelled);
if (m_onResults)
m_onResults(Results::GetEndMarker(cancelled));
m_onResults(m_results);
else
LOG(LERROR, ("OnResults is not set."));
}

View file

@ -240,7 +240,9 @@ void Engine::DoSearch(SearchParams const & params, m2::RectD const & viewport,
// Early exit when query processing is cancelled.
if (processor.IsCancelled())
{
params.m_onResults(Results::GetEndMarker(true /* isCancelled */));
Results results;
results.SetEndMarker(true /* isCancelled */);
params.m_onResults(results);
return;
}

View file

@ -1,23 +1,27 @@
#include "search/hotels_classifier.hpp"
#include "search/result.hpp"
#include "std/cstdint.hpp"
namespace search
{
void HotelsClassifier::AddBatch(Results const & results)
// static
bool HotelsClassifier::IsHotelResults(Results const & results)
{
if (results.IsEndMarker())
return;
HotelsClassifier classifier;
classifier.Add(results.begin(), results.end());
return classifier.IsHotelResults();
}
for (auto const & result : results)
void HotelsClassifier::Add(Results::Iter begin, Results::Iter end)
{
for (; begin != end; ++begin)
{
m_numHotels += (*begin).m_metadata.m_isHotel;
++m_numResults;
if (result.m_metadata.m_isHotel)
++m_numHotels;
}
}
bool HotelsClassifier::IsHotelQuery() const
bool HotelsClassifier::IsHotelResults() const
{
// Threshold used to activate hotels mode. Probably is too strict,
// but we don't have statistics now.

View file

@ -1,11 +1,9 @@
#pragma once
#include "std/cstdint.hpp"
#include "search/result.hpp"
namespace search
{
class Results;
// A binary classifier that can be used in conjunction with search
// engine to decide whether the majority of results are hotels or not.
//
@ -13,9 +11,10 @@ class Results;
class HotelsClassifier
{
public:
void AddBatch(Results const & results);
static bool IsHotelResults(Results const & results);
bool IsHotelQuery() const;
void Add(Results::Iter begin, Results::Iter end);
bool IsHotelResults() const;
private:
uint64_t m_numHotels = 0;

View file

@ -5,6 +5,7 @@
namespace search
{
// Result ------------------------------------------------------------------------------------------
Result::Result(FeatureID const & id, m2::PointD const & pt, string const & str,
string const & address, string const & type, uint32_t featureType,
Metadata const & meta)
@ -139,10 +140,16 @@ string Result::ToStringForStats() const
return s;
}
bool Results::AddResult(Result && res)
// Results -----------------------------------------------------------------------------------------
Results::Results()
{
Clear();
}
bool Results::AddResult(Result && result)
{
// Find first feature result.
auto it = find_if(m_vec.begin(), m_vec.end(), [](Result const & r)
auto it = find_if(m_results.begin(), m_results.end(), [](Result const & r)
{
switch (r.GetResultType())
{
@ -153,43 +160,46 @@ bool Results::AddResult(Result && res)
}
});
if (res.IsSuggest())
if (result.IsSuggest())
{
if (distance(m_vec.begin(), it) >= MAX_SUGGESTS_COUNT)
if (distance(m_results.begin(), it) >= MAX_SUGGESTS_COUNT)
return false;
for (auto i = m_vec.begin(); i != it; ++i)
if (res.IsEqualSuggest(*i))
for (auto i = m_results.begin(); i != it; ++i)
if (result.IsEqualSuggest(*i))
return false;
for (auto i = it; i != m_vec.end(); ++i)
{
auto & r = *i;
auto const oldPos = r.GetPositionInResults();
r.SetPositionInResults(oldPos + 1);
}
res.SetPositionInResults(distance(m_vec.begin(), it));
m_vec.insert(it, move(res));
InsertResult(it, move(result));
}
else
{
for (; it != m_vec.end(); ++it)
if (res.IsEqualFeature(*it))
for (; it != m_results.end(); ++it)
{
if (result.IsEqualFeature(*it))
return false;
res.SetPositionInResults(m_vec.size());
m_vec.push_back(move(res));
}
InsertResult(m_results.end(), move(result));
}
return true;
}
void Results::AddResultNoChecks(Result && result)
{
InsertResult(m_results.end(), move(result));
}
void Results::Clear()
{
m_results.clear();
m_status = Status::None;
}
size_t Results::GetSuggestsCount() const
{
size_t res = 0;
for (size_t i = 0; i < GetCount(); i++)
{
if (m_vec[i].IsSuggest())
if (m_results[i].IsSuggest())
++res;
else
{
@ -200,10 +210,22 @@ size_t Results::GetSuggestsCount() const
return res;
}
////////////////////////////////////////////////////////////////////////////////////
// AddressInfo implementation
////////////////////////////////////////////////////////////////////////////////////
void Results::InsertResult(vector<Result>::iterator where, Result && result)
{
ASSERT_LESS(m_results.size(), numeric_limits<int32_t>::max(), ());
for (auto it = where; it != m_results.end(); ++it)
{
auto & r = *it;
auto const position = r.GetPositionInResults();
r.SetPositionInResults(position + 1);
}
result.SetPositionInResults(distance(m_results.begin(), where));
m_results.insert(where, move(result));
}
// AddressInfo -------------------------------------------------------------------------------------
bool AddressInfo::IsEmptyName() const
{
return m_name.empty() && m_house.empty();
@ -324,5 +346,4 @@ string DebugPrint(Result const & result)
return "Result { Name: " + result.GetString() + "; Type: " + result.GetFeatureType() +
"; Info: " + DebugPrint(result.GetRankingInfo()) + " }";
}
} // namespace search

View file

@ -133,67 +133,63 @@ public:
class Results
{
vector<Result> m_vec;
enum StatusT
{
NONE, // default status
ENDED_CANCELLED, // search ended with canceling
ENDED // search ended itself
};
StatusT m_status;
explicit Results(bool isCancelled)
{
m_status = (isCancelled ? ENDED_CANCELLED : ENDED);
}
public:
Results() : m_status(NONE) {}
using Iter = vector<Result>::const_iterator;
static Results GetEndMarker(bool isCancelled) { return Results(isCancelled); }
Results();
bool IsEndMarker() const { return (m_status != NONE); }
bool IsEndedNormal() const { return (m_status == ENDED); }
bool IsEndedCancelled() const { return m_status == ENDED_CANCELLED; }
inline bool IsEndMarker() const { return m_status != Status::None; }
inline bool IsEndedNormal() const { return m_status == Status::EndedNormal; }
inline bool IsEndedCancelled() const { return m_status == Status::EndedCancelled; }
bool AddResult(Result && res);
/// Fast function that don't do any duplicates checks.
/// Used in viewport search only.
void AddResultNoChecks(Result && res)
void SetEndMarker(bool cancelled)
{
ASSERT_LESS(m_vec.size(), numeric_limits<int32_t>::max(), ());
res.SetPositionInResults(static_cast<int32_t>(m_vec.size()));
m_vec.push_back(move(res));
m_status = cancelled ? Status::EndedCancelled : Status::EndedNormal;
}
inline void Clear() { m_vec.clear(); }
bool AddResult(Result && result);
typedef vector<Result>::const_iterator IterT;
// Fast version of AddResult() that doesn't do any duplicates checks.
void AddResultNoChecks(Result && result);
inline IterT begin() const { return m_vec.begin(); }
inline IterT end() const { return m_vec.end(); }
void Clear();
inline size_t GetCount() const { return m_vec.size(); }
inline Iter begin() const { return m_results.begin(); }
inline Iter end() const { return m_results.end(); }
inline size_t GetCount() const { return m_results.size(); }
size_t GetSuggestsCount() const;
inline Result & GetResult(size_t i)
{
ASSERT_LESS(i, m_vec.size(), ());
return m_vec[i];
ASSERT_LESS(i, m_results.size(), ());
return m_results[i];
}
inline Result const & GetResult(size_t i) const
{
ASSERT_LESS(i, m_vec.size(), ());
return m_vec[i];
ASSERT_LESS(i, m_results.size(), ());
return m_results[i];
}
inline void Swap(Results & rhs)
inline void Swap(Results & rhs) { m_results.swap(rhs.m_results); }
private:
enum class Status
{
m_vec.swap(rhs.m_vec);
}
None,
EndedCancelled,
EndedNormal
};
// Inserts |result| in |m_results| at position denoted by |where|.
//
// *NOTE* all iterators, references and pointers to |m_results| are
// invalid after the call.
void InsertResult(vector<Result>::iterator where, Result && result);
vector<Result> m_results;
Status m_status;
};
struct AddressInfo

View file

@ -2,18 +2,26 @@
#include "search/result.hpp"
#include "base/assert.hpp"
namespace search
{
ViewportSearchCallback::ViewportSearchCallback(Delegate & delegate, TOnResults onResults)
: m_delegate(delegate), m_onResults(move(onResults)), m_hotelsModeSet(false), m_firstCall(true)
: m_delegate(delegate)
, m_onResults(move(onResults))
, m_hotelsModeSet(false)
, m_firstCall(true)
, m_lastResultsSize(0)
{
}
void ViewportSearchCallback::operator()(Results const & results)
{
m_hotelsClassif.AddBatch(results);
ASSERT_LESS_OR_EQUAL(m_lastResultsSize, results.GetCount(), ());
m_hotelsClassif.Add(results.begin() + m_lastResultsSize, results.end());
m_lastResultsSize = results.GetCount();
if (!m_hotelsModeSet && m_hotelsClassif.IsHotelQuery())
if (!m_hotelsModeSet && m_hotelsClassif.IsHotelResults())
{
m_delegate.SetHotelDisplacementMode();
m_hotelsModeSet = true;

View file

@ -37,8 +37,10 @@ private:
Delegate & m_delegate;
TOnResults m_onResults;
HotelsClassifier m_hotelsClassif;
bool m_hotelsModeSet;
bool m_firstCall;
HotelsClassifier m_hotelsClassif;
size_t m_lastResultsSize;
};
} // namespace search

View file

@ -8,10 +8,12 @@
namespace search
{
class Results;
struct ViewportSearchParams
{
using TOnStarted = function<void()>;
using TOnCompleted = function<void()>;
using TOnCompleted = function<void(Results const & results)>;
string m_query;
string m_inputLocale;