forked from organicmaps/organicmaps
[search] Fixed keyword matching: compare matched name's length only after language comparison.
This commit is contained in:
parent
89d4fd00df
commit
00aafcdeae
4 changed files with 66 additions and 16 deletions
|
@ -30,7 +30,7 @@ bool KeywordLangMatcher::ScoreT::operator <(KeywordLangMatcher::ScoreT const & s
|
|||
if (m_langScore != score.m_langScore)
|
||||
return m_langScore < score.m_langScore;
|
||||
|
||||
return false;
|
||||
return m_parentScore.LessInTokensLength(score.m_parentScore);
|
||||
}
|
||||
|
||||
void KeywordLangMatcher::SetLanguages(vector<vector<int8_t> > const & languagePriorities)
|
||||
|
|
|
@ -116,10 +116,17 @@ bool KeywordMatcher::ScoreT::operator < (KeywordMatcher::ScoreT const & s) const
|
|||
if (m_sumTokenMatchDistance != s.m_sumTokenMatchDistance)
|
||||
return m_sumTokenMatchDistance > s.m_sumTokenMatchDistance;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KeywordMatcher::ScoreT::LessInTokensLength(ScoreT const & s) const
|
||||
{
|
||||
if (m_bFullQueryMatched)
|
||||
{
|
||||
ASSERT(s.m_bFullQueryMatched, ());
|
||||
return m_nameTokensLength > s.m_nameTokensLength;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
string DebugPrint(KeywordMatcher::ScoreT const & score)
|
||||
|
|
|
@ -19,13 +19,14 @@ public:
|
|||
public:
|
||||
ScoreT();
|
||||
bool operator < (ScoreT const & s) const;
|
||||
bool LessInTokensLength(ScoreT const & s) const;
|
||||
|
||||
bool IsQueryMatched() const { return m_bFullQueryMatched; }
|
||||
|
||||
private:
|
||||
friend class KeywordMatcher;
|
||||
friend string DebugPrint(ScoreT const & score);
|
||||
|
||||
bool IsQueryMatched() const { return m_bFullQueryMatched; }
|
||||
|
||||
uint32_t m_sumTokenMatchDistance;
|
||||
uint32_t m_nameTokensMatched;
|
||||
uint32_t m_nameTokensLength;
|
||||
|
@ -48,8 +49,6 @@ public:
|
|||
ScoreT Score(StringT const * tokens, size_t count) const;
|
||||
//@}
|
||||
|
||||
static bool IsQueryMatched(ScoreT const & score) { return score.IsQueryMatched(); }
|
||||
|
||||
private:
|
||||
vector<StringT> m_keywords;
|
||||
StringT m_prefix;
|
||||
|
|
|
@ -17,7 +17,6 @@ namespace
|
|||
{
|
||||
|
||||
using search::KeywordMatcher;
|
||||
typedef search::KeywordMatcher::ScoreT ScoreT;
|
||||
using search::MAX_TOKENS;
|
||||
|
||||
enum ExpectedMatchResult
|
||||
|
@ -42,8 +41,7 @@ struct KeywordMatcherTestCase
|
|||
char const * m_name;
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
void TestKeywordMatcher(char const * const query, KeywordMatcherTestCase const (&testCases)[N])
|
||||
void InitMatcher(char const * query, KeywordMatcher & matcher)
|
||||
{
|
||||
vector<strings::UniString> keywords;
|
||||
strings::UniString prefix;
|
||||
|
@ -53,20 +51,54 @@ void TestKeywordMatcher(char const * const query, KeywordMatcherTestCase const (
|
|||
keywords.pop_back();
|
||||
}
|
||||
|
||||
KeywordMatcher matcher;
|
||||
matcher.SetKeywords(&keywords[0], keywords.size(), prefix);
|
||||
ScoreT prevScore = ScoreT();
|
||||
}
|
||||
|
||||
class TestScore
|
||||
{
|
||||
typedef KeywordMatcher::ScoreT ScoreT;
|
||||
ScoreT m_score;
|
||||
|
||||
public:
|
||||
TestScore() {}
|
||||
TestScore(ScoreT const & score) : m_score(score) {}
|
||||
|
||||
bool operator<(TestScore const & s) const
|
||||
{
|
||||
if (m_score < s.m_score)
|
||||
return true;
|
||||
return m_score.LessInTokensLength(s.m_score);
|
||||
}
|
||||
|
||||
bool IsQueryMatched() const { return m_score.IsQueryMatched(); }
|
||||
|
||||
friend string DebugPrint(TestScore const & score);
|
||||
};
|
||||
|
||||
string DebugPrint(TestScore const & s)
|
||||
{
|
||||
return DebugPrint(s.m_score);
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
void TestKeywordMatcher(char const * const query, KeywordMatcherTestCase const (&testCases)[N])
|
||||
{
|
||||
KeywordMatcher matcher;
|
||||
InitMatcher(query, matcher);
|
||||
|
||||
TestScore prevScore;
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
{
|
||||
char const * const name = testCases[i].m_name;
|
||||
char const * const prevName = (i == 0 ? "N/A" : testCases[i-1].m_name);
|
||||
ScoreT const testScore = matcher.Score(name);
|
||||
TestScore const testScore = matcher.Score(name);
|
||||
|
||||
// Test that a newly created matcher returns the same result
|
||||
{
|
||||
KeywordMatcher freshMatcher;
|
||||
freshMatcher.SetKeywords(&keywords[0], keywords.size(), prefix);
|
||||
ScoreT const freshScore = freshMatcher.Score(name);
|
||||
InitMatcher(query, freshMatcher);
|
||||
|
||||
TestScore const freshScore = freshMatcher.Score(name);
|
||||
// TEST_EQUAL(testScore, freshScore, (query, name));
|
||||
TEST(!(testScore < freshScore), (query, name));
|
||||
TEST(!(freshScore < testScore), (query, name));
|
||||
|
@ -75,7 +107,7 @@ void TestKeywordMatcher(char const * const query, KeywordMatcherTestCase const (
|
|||
if (testCases[i].m_eMatch != ANY_RES)
|
||||
{
|
||||
TEST_EQUAL(testCases[i].m_eMatch == MATCHES,
|
||||
KeywordMatcher::IsQueryMatched(testScore),
|
||||
testScore.IsQueryMatched(),
|
||||
(query, name, testScore));
|
||||
}
|
||||
|
||||
|
@ -103,6 +135,7 @@ void TestKeywordMatcher(char const * const query, KeywordMatcherTestCase const (
|
|||
|
||||
} // unnamed namespace
|
||||
|
||||
|
||||
UNIT_TEST(KeywordMatcher_Prefix)
|
||||
{
|
||||
char const query[] = "new";
|
||||
|
@ -297,3 +330,14 @@ UNIT_TEST(KeywordMatcher_ManyTokensInReverseOrder)
|
|||
};
|
||||
TestKeywordMatcher(query.c_str(), testCases);
|
||||
}
|
||||
|
||||
UNIT_TEST(KeywordMatcher_DifferentLangs)
|
||||
{
|
||||
KeywordMatcher matcher;
|
||||
|
||||
InitMatcher("не", matcher);
|
||||
|
||||
char const * arr[] = { "Невский переулок", "Неўскі завулак" };
|
||||
TEST(!(matcher.Score(arr[0]) < matcher.Score(arr[1])), ());
|
||||
TEST(!(matcher.Score(arr[1]) < matcher.Score(arr[0])), ());
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue