in src/java/com/twitter/search/earlybird/search/relevance/scoring/FeatureBasedScoringFunction.java [811:998]
protected abstract void generateExplanationForScoring(
LinearScoringData scoringData, boolean isHit, List<Explanation> details) throws IOException;
/**
* Generates the boosts part of the explanation for the document that is currently
* being evaluated.
*/
private void generateExplanationForBoosts(
LinearScoringData scoringData,
boolean isHit,
List<Explanation> details) {
List<Explanation> boostDetails = Lists.newArrayList();
boostDetails.add(Explanation.match((float) scoringData.scoreBeforeBoost, "Score before boost"));
// Lucene score boost
if (params.useLuceneScoreAsBoost) {
boostDetails.add(Explanation.match(
(float) scoringData.normalizedLuceneScore,
String.format("[x] Lucene score boost, luceneScore=%.3f",
scoringData.luceneScore)));
}
// card boost
if (scoringData.hasCardBoostApplied) {
boostDetails.add(Explanation.match((float) params.hasCardBoosts[scoringData.cardType],
"[x] card boost for type " + SearchCardType.cardTypeFromByteValue(scoringData.cardType)));
}
// Offensive
if (scoringData.isOffensive) {
boostDetails.add(Explanation.match((float) params.offensiveDamping, "[x] Offensive damping"));
} else {
boostDetails.add(Explanation.match(LinearScoringData.NO_BOOST_VALUE,
String.format("Not Offensive, damping=%.3f", params.offensiveDamping)));
}
// Spam
if (scoringData.spamUserDampApplied) {
boostDetails.add(Explanation.match((float) params.spamUserDamping, "[x] Spam"));
}
// NSFW
if (scoringData.nsfwUserDampApplied) {
boostDetails.add(Explanation.match((float) params.nsfwUserDamping, "[X] NSFW"));
}
// Bot
if (scoringData.botUserDampApplied) {
boostDetails.add(Explanation.match((float) params.botUserDamping, "[X] Bot"));
}
// Multiple hashtags or trends
if (scoringData.hasMultipleHashtagsOrTrends) {
boostDetails.add(Explanation.match((float) params.multipleHashtagsOrTrendsDamping,
"[x] Multiple hashtags or trends boost"));
} else {
boostDetails.add(Explanation.match(LinearScoringData.NO_BOOST_VALUE,
String.format("No multiple hashtags or trends, damping=%.3f",
params.multipleHashtagsOrTrendsDamping)));
}
if (scoringData.tweetHasTrendsBoostApplied) {
boostDetails.add(Explanation.match(
(float) params.tweetHasTrendBoost, "[x] Tweet has trend boost"));
}
if (scoringData.hasMedialUrlBoostApplied) {
boostDetails.add(Explanation.match(
(float) params.tweetHasMediaUrlBoost, "[x] Media url boost"));
}
if (scoringData.hasNewsUrlBoostApplied) {
boostDetails.add(Explanation.match(
(float) params.tweetHasNewsUrlBoost, "[x] News url boost"));
}
boostDetails.add(Explanation.match(0.0f, "[FIELDS HIT] " + scoringData.hitFields));
if (scoringData.hasNoTextHitDemotionApplied) {
boostDetails.add(Explanation.match(
(float) params.noTextHitDemotion, "[x] No text hit demotion"));
}
if (scoringData.hasUrlOnlyHitDemotionApplied) {
boostDetails.add(Explanation.match(
(float) params.urlOnlyHitDemotion, "[x] URL only hit demotion"));
}
if (scoringData.hasNameOnlyHitDemotionApplied) {
boostDetails.add(Explanation.match(
(float) params.nameOnlyHitDemotion, "[x] Name only hit demotion"));
}
if (scoringData.hasSeparateTextAndNameHitDemotionApplied) {
boostDetails.add(Explanation.match((float) params.separateTextAndNameHitDemotion,
"[x] Separate text/name demotion"));
}
if (scoringData.hasSeparateTextAndUrlHitDemotionApplied) {
boostDetails.add(Explanation.match((float) params.separateTextAndUrlHitDemotion,
"[x] Separate text/url demotion"));
}
if (scoringData.tweetFromVerifiedAccountBoostApplied) {
boostDetails.add(Explanation.match((float) params.tweetFromVerifiedAccountBoost,
"[x] Verified account boost"));
}
if (scoringData.tweetFromBlueVerifiedAccountBoostApplied) {
boostDetails.add(Explanation.match((float) params.tweetFromBlueVerifiedAccountBoost,
"[x] Blue-verified account boost"));
}
if (scoringData.selfTweetBoostApplied) {
boostDetails.add(Explanation.match((float) params.selfTweetBoost,
"[x] Self tweet boost"));
}
if (scoringData.skipReason == LinearScoringData.SkipReason.SOCIAL_FILTER) {
boostDetails.add(Explanation.noMatch("SKIPPED for social filter"));
} else {
if (scoringData.directFollowBoostApplied) {
boostDetails.add(Explanation.match((float) params.directFollowBoost,
"[x] Direct follow boost"));
}
if (scoringData.trustedCircleBoostApplied) {
boostDetails.add(Explanation.match((float) params.trustedCircleBoost,
"[x] Trusted circle boost"));
}
if (scoringData.outOfNetworkReplyPenaltyApplied) {
boostDetails.add(Explanation.match((float) params.outOfNetworkReplyPenalty,
"[-] Out of network reply penalty"));
}
}
// Language demotions
String langDetails = String.format(
"tweetLang=[%s] uiLang=[%s]",
ThriftLanguageUtil.getLocaleOf(
ThriftLanguage.findByValue(scoringData.tweetLangId)).getLanguage(),
ThriftLanguageUtil.getLocaleOf(ThriftLanguage.findByValue(params.uiLangId)).getLanguage());
if (scoringData.uiLangMult == 1.0) {
boostDetails.add(Explanation.match(
LinearScoringData.NO_BOOST_VALUE, "No UI Language demotion: " + langDetails));
} else {
boostDetails.add(Explanation.match(
(float) scoringData.uiLangMult, "[x] UI LangMult: " + langDetails));
}
StringBuilder userLangDetails = new StringBuilder();
userLangDetails.append("userLang=[");
for (int i = 0; i < params.userLangs.length; i++) {
if (params.userLangs[i] > 0.0) {
String lang = ThriftLanguageUtil.getLocaleOf(ThriftLanguage.findByValue(i)).getLanguage();
userLangDetails.append(String.format("%s:%.3f,", lang, params.userLangs[i]));
}
}
userLangDetails.append("]");
if (!params.useUserLanguageInfo) {
boostDetails.add(Explanation.noMatch(
"No User Language Demotion: " + userLangDetails.toString()));
} else {
boostDetails.add(Explanation.match(
(float) scoringData.userLangMult,
"[x] User LangMult: " + userLangDetails.toString()));
}
// Age decay
String ageDecayDetails = String.format(
"age=%d seconds, slope=%.3f, base=%.1f, half-life=%.0f",
scoringData.tweetAgeInSeconds, params.ageDecaySlope,
params.ageDecayBase, params.ageDecayHalflife);
if (params.useAgeDecay) {
boostDetails.add(Explanation.match(
(float) scoringData.ageDecayMult, "[x] AgeDecay: " + ageDecayDetails));
} else {
boostDetails.add(Explanation.match(1.0f, "Age decay disabled: " + ageDecayDetails));
}
// Score adjuster
boostDetails.add(Explanation.match(SCORE_ADJUSTER, "[x] score adjuster"));
Explanation boostCombo = isHit
? Explanation.match((float) scoringData.scoreAfterBoost,
"(MATCH) After Boosts and Demotions:", boostDetails)
: Explanation.noMatch("After Boosts and Demotions:", boostDetails);
details.add(boostCombo);
}