protected abstract void generateExplanationForScoring()

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);
  }