public Explanation explain(IndexReader reader, int doc) throws IOException {
      ComplexExplanation result = new ComplexExplanation();
      result.setDescription("weight(" + getQuery() + " in " + doc + "), product of:");

      Explanation idfExpl = new Explanation(idf, "idf(docFreq=" + reader.docFreq(term) + ")");

      // explain query weight
      Explanation queryExpl = new Explanation();
      queryExpl.setDescription("queryWeight(" + getQuery() + "), product of:");

      Explanation boostExpl = new Explanation(getBoost(), "boost");
      if (getBoost() != 1.0f) queryExpl.addDetail(boostExpl);
      queryExpl.addDetail(idfExpl);

      Explanation queryNormExpl = new Explanation(queryNorm, "queryNorm");
      queryExpl.addDetail(queryNormExpl);

      queryExpl.setValue(boostExpl.getValue() * idfExpl.getValue() * queryNormExpl.getValue());

      result.addDetail(queryExpl);

      // explain field weight
      String field = term.field();
      ComplexExplanation fieldExpl = new ComplexExplanation();
      fieldExpl.setDescription("fieldWeight(" + term + " in " + doc + "), product of:");

      Explanation tfExpl = scorer(reader).explain(doc);
      fieldExpl.addDetail(tfExpl);
      fieldExpl.addDetail(idfExpl);

      Explanation fieldNormExpl = new Explanation();
      byte[] fieldNorms = reader.norms(field);
      float fieldNorm = fieldNorms != null ? Similarity.decodeNorm(fieldNorms[doc]) : 0.0f;
      fieldNormExpl.setValue(fieldNorm);
      fieldNormExpl.setDescription("fieldNorm(field=" + field + ", doc=" + doc + ")");
      fieldExpl.addDetail(fieldNormExpl);

      fieldExpl.setMatch(Boolean.valueOf(tfExpl.isMatch()));
      fieldExpl.setValue(tfExpl.getValue() * idfExpl.getValue() * fieldNormExpl.getValue());

      result.addDetail(fieldExpl);
      result.setMatch(fieldExpl.getMatch());

      // combine them
      result.setValue(queryExpl.getValue() * fieldExpl.getValue());

      if (queryExpl.getValue() == 1.0f) return fieldExpl;

      return result;
    }
 @Override
 public final Explanation explain(BasicStats stats, float tfn) {
   Explanation result = new Explanation();
   result.setDescription(getClass().getSimpleName() + ", computed from: ");
   result.setValue(score(stats, tfn));
   result.addDetail(new Explanation(tfn, "tfn"));
   return result;
 }
 /**
  * Returns an explanation for the normalized term frequency.
  *
  * <p>The default normalization methods use the field length of the document and the average field
  * length to compute the normalized term frequency. This method provides a generic explanation for
  * such methods. Subclasses that use other statistics must override this method.
  */
 public Explanation explain(BasicStats stats, float tf, float len) {
   Explanation result = new Explanation();
   result.setDescription(getClass().getSimpleName() + ", computed from: ");
   result.setValue(tfn(stats, tf, len));
   result.addDetail(new Explanation(tf, "tf"));
   result.addDetail(new Explanation(stats.getAvgFieldLength(), "avgFieldLength"));
   result.addDetail(new Explanation(len, "len"));
   return result;
 }
  /**
   * This method is no longer an official member of {@link Scorer}, but it is needed by SpanWeight
   * to build an explanation.
   */
  protected Explanation explain(final int doc) throws IOException {
    Explanation tfExplanation = new Explanation();

    int expDoc = advance(doc);

    float phraseFreq = (expDoc == doc) ? freq : 0.0f;
    tfExplanation.setValue(similarity.tf(phraseFreq));
    tfExplanation.setDescription("tf(phraseFreq=" + phraseFreq + ")");

    return tfExplanation;
  }
  /*
   * (non-Javadoc)
   *
   * @see org.apache.lucene.search.Scorer#explain(int)
   */
  public Explanation explain(int doc) throws IOException {
    // TODO: Work out what a proper explanation would be here?
    Explanation tfExplanation = new Explanation();

    while (next() && doc() < doc) {}

    float phraseFreq = (doc() == doc) ? freq : 0.0f;
    tfExplanation.setValue(getSimilarity().tf(phraseFreq));
    tfExplanation.setDescription("tf(phraseFreq=" + phraseFreq + ")");

    return tfExplanation;
  }
 @Override
 protected Explanation explain(int doc) throws IOException {
   Explanation result = new Explanation();
   // Add detail about tf/idf...
   Explanation nonPayloadExpl = super.explain(doc);
   result.addDetail(nonPayloadExpl);
   // Add detail about payload
   Explanation payloadExpl = function.explain(doc, payloadsSeen, payloadScore);
   result.addDetail(payloadExpl);
   result.setValue(nonPayloadExpl.getValue() * payloadExpl.getValue());
   result.setDescription("PayloadNearQuery, product of:");
   return result;
 }
      @Override
      protected Explanation explain(final int doc) throws IOException {
        ComplexExplanation result = new ComplexExplanation();
        Explanation nonPayloadExpl = super.explain(doc);
        result.addDetail(nonPayloadExpl);
        // QUESTION: Is there a way to avoid this skipTo call? We need to know
        // whether to load the payload or not
        Explanation payloadBoost = new Explanation();
        result.addDetail(payloadBoost);

        float payloadScore = getPayloadScore();
        payloadBoost.setValue(payloadScore);
        // GSI: I suppose we could toString the payload, but I don't think that
        // would be a good idea
        payloadBoost.setDescription("scorePayload(...)");
        result.setValue(nonPayloadExpl.getValue() * payloadScore);
        result.setDescription("btq, product of:");
        result.setMatch(
            nonPayloadExpl.getValue() == 0 ? Boolean.FALSE : Boolean.TRUE); // LUCENE-1303
        return result;
      }
  @Override
  protected Explanation createExplain(Explanation innerExplain, IndexReader reader, int doc)
      throws IOException {
    if (reader instanceof BoboIndexReader) {
      Explanation finalExpl = new Explanation();
      finalExpl.addDetail(innerExplain);

      _func.initializeReader((BoboIndexReader) reader, _jsonParam);

      float innerValue = innerExplain.getValue();
      float value = 0;
      if (_func.useInnerScore()) value = _func.newScore(innerValue, doc);
      else value = _func.newScore(doc);

      finalExpl.setValue(value);
      finalExpl.setDescription("Custom score: " + _func.getExplainString(innerValue, doc));
      return finalExpl;
    } else {
      throw new IllegalStateException("reader not instance of " + BoboIndexReader.class);
    }
  }