[search] Fixed keyword matching: compare matched name's length only after language comparison.

This commit is contained in:
vng 2014-01-23 22:29:54 +03:00 committed by Alex Zolotarev
parent 89d4fd00df
commit 00aafcdeae
4 changed files with 66 additions and 16 deletions

View file

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

View file

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

View file

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

View file

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