1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
|
//
// C++ Implementation: complexscorecalculationstrategy
//
// Description:
//
//
// Author: Benjamin Mesing <bensmail@gmx.net>, (C) 2005
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include "complexscorecalculationstrategy.h"
#include <vector>
#include <cassert>
// NApt
#include <ipackagedb.h>
// NPlugin
#include <packagenotfoundexception.h>
namespace NApt {
const float ComplexScoreCalculationStrategy::Scores::DIRECT_CS_MATCH = 20;
const float ComplexScoreCalculationStrategy::Scores::DIRECT_MATCH = 18;
const float ComplexScoreCalculationStrategy::Scores::WHOLE_CS_WORD = 15;
const float ComplexScoreCalculationStrategy::Scores::WHOLE_WORD = 14;
const float ComplexScoreCalculationStrategy::Scores::BORDER_MATCH = 8;
const float ComplexScoreCalculationStrategy::Scores::INNER_MATCH = 3;
float ComplexScoreCalculationStrategy::ScoreInformation::_maximumDescriptionScore = 0;
ComplexScoreCalculationStrategy::ComplexScoreCalculationStrategy(IPackageDB* pPackageDb)
{
_pPackageDb = pPackageDb;
}
ComplexScoreCalculationStrategy::~ComplexScoreCalculationStrategy()
{
}
/////////////////////////////////////////////////////
// IScoreCalculationStrategy Interface
/////////////////////////////////////////////////////
void ComplexScoreCalculationStrategy::calculateScore(const set<string>& packages)
{
qDebug("Calculating Score");
assert(_includePatterns.size() != 0);
vector<ScoreInformation> scoreInformation;
scoreInformation.reserve(packages.size());
// reset the maximum description count
ScoreInformation::clearMaximumDescriptionScore();
// collect the relevant information for each package
for (set<string>::const_iterator it = packages.begin(); it != packages.end(); ++it)
{
try
{
ScoreInformation si = getScoreInformation(*it, _cs);
scoreInformation.push_back(si);
}
// if the package was not found, add it with a score of 1
catch (NPlugin::PackageNotFoundException& e)
{
qDebug("PackageNotFoundException");
setScore(*it, 0.5f);
}
}
// calculate the scores for each package
{
const float includeNum = _includePatterns.size();
float maxDescriptionScore = ScoreInformation::getMaximumDescriptionScore();
// if maxDescriptionScore is 0 every description score is null, so we can choose any number
// except 0 here...
if (maxDescriptionScore == 0)
maxDescriptionScore = 1;
for (vector<ScoreInformation>::const_iterator it = scoreInformation.begin();
it != scoreInformation.end(); ++it )
{
const ScoreInformation& si = *it;
// normalize the scores by the maximum scores possible
float nameScores = si.getNameScore() / (includeNum * Scores::DIRECT_CS_MATCH);
float descriptionScores = si.getDescriptionScore() / maxDescriptionScore;
float score = (3 * nameScores + descriptionScores) / 4.0f;
setScore(si.package(), score);
}
}
}
/////////////////////////////////////////////////////
// Helper Methods
/////////////////////////////////////////////////////
ComplexScoreCalculationStrategy::ScoreInformation
ComplexScoreCalculationStrategy::getScoreInformation(const string& package, bool) const
{
ScoreInformation info(package);
auto& packageStruct = _pPackageDb->getPackageRecord(package);
for (QStringList::const_iterator it = _includePatterns.begin(); it != _includePatterns.end(); ++it)
{
info.addNameScore(getNameScore(packageStruct, *it));
info.addDescriptionScore(getDescriptionScore(packageStruct, *it));
}
return info;
}
float ComplexScoreCalculationStrategy::getNameScore(const IPackage& package, const QString& pattern) const
{
// if the pattern does not match at all
if (package.name().indexOf(pattern, 0, Qt::CaseInsensitive) == -1)
return 0;
// if the package name equals (case insensitve) the pattern
// (this is because it was found in the pattern and they have the same size)
if (package.name().length() == pattern.length())
{
// if it equals case sensitive
if (package.name() == pattern)
return Scores::DIRECT_CS_MATCH;
else
return Scores::DIRECT_MATCH;
}
// the pattern was found, but does not equal the package name
// take the highest rated match we found
Matches m = findMatches(package.name(), pattern);
if (m.wholeWordCsMatches > 0)
return Scores::WHOLE_CS_WORD;
if (m.wholeWordMatches > 0)
return Scores::WHOLE_WORD;
if (m.borderMatches)
return Scores::BORDER_MATCH;
if (m.innerMatches)
return Scores::INNER_MATCH;
assert(false);
return 0;
}
float ComplexScoreCalculationStrategy::getDescriptionScore(const IPackage& package, const QString& pattern) const
{
Matches m = findMatches(package.shortDescription(), pattern);
return (m.wholeWordCsMatches * Scores::WHOLE_CS_WORD + m.wholeWordMatches * Scores::WHOLE_WORD
+ m.innerMatches * Scores::INNER_MATCH + m.borderMatches * Scores::BORDER_MATCH) / pattern.length();
}
ComplexScoreCalculationStrategy::Matches
ComplexScoreCalculationStrategy::findMatches(const QString& string, const QString& pattern) const
{
Matches matches;
int i = 0;
while ( (i = string.indexOf(pattern, i, Qt::CaseInsensitive)) != -1 )
{
// holds if the pattern was matched at the front boundary of a word
bool front = false;
if (i==0)
front = true;
else
{
QChar c = string.at(i-1);
// if the character before is not a letter we have a boundary
front = !c.isLetter();
}
// holds if the pattern was matched at the back boundary of a word
bool back = false;
if ( i + pattern.length() == string.length() )
back = true;
else
{
QChar c = string.at(i + pattern.length());
back = !c.isLetter();
}
if (front && back)
{
QString substring = string.mid(i, pattern.length());
if (substring == pattern)
++matches.wholeWordCsMatches;
else
++matches.wholeWordMatches;
}
else if (front || back)
++matches.borderMatches;
else
++matches.innerMatches;
i += pattern.length();
}
return matches;
}
}
|