/** Explain the score we computed for doc */
 @Override
 public Explanation explain(LeafReaderContext context, int doc) throws IOException {
   boolean match = false;
   float max = 0.0f, sum = 0.0f;
   List<Explanation> subs = new ArrayList<>();
   for (Weight wt : weights) {
     Explanation e = wt.explain(context, doc);
     if (e.isMatch()) {
       match = true;
       subs.add(e);
       sum += e.getValue();
       max = Math.max(max, e.getValue());
     }
   }
   if (match) {
     final float score = max + (sum - max) * tieBreakerMultiplier;
     final String desc =
         tieBreakerMultiplier == 0.0f
             ? "max of:"
             : "max plus " + tieBreakerMultiplier + " times others of:";
     return Explanation.match(score, desc, subs);
   } else {
     return Explanation.noMatch("No matching clause");
   }
 }
 public Explanation explain(int doc) throws IOException {
   Explanation subQueryExpl = weight.qWeight.explain(reader, doc);
   if (!subQueryExpl.isMatch()) {
     return subQueryExpl;
   }
   float sc = subQueryExpl.getValue() * vals.floatVal(doc);
   Explanation res =
       new ComplexExplanation(true, sc, BoostedQuery.this.toString() + ", product of:");
   res.addDetail(subQueryExpl);
   res.addDetail(vals.explain(doc));
   return res;
 }
    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;
    }
 /** Explain the score we computed for doc */
 @Override
 public Explanation explain(LeafReaderContext context, int doc) throws IOException {
   if (disjuncts.size() == 1) return weights.get(0).explain(context, doc);
   ComplexExplanation result = new ComplexExplanation();
   float max = 0.0f, sum = 0.0f;
   result.setDescription(
       tieBreakerMultiplier == 0.0f
           ? "max of:"
           : "max plus " + tieBreakerMultiplier + " times others of:");
   for (Weight wt : weights) {
     Explanation e = wt.explain(context, doc);
     if (e.isMatch()) {
       result.setMatch(Boolean.TRUE);
       result.addDetail(e);
       sum += e.getValue();
       max = Math.max(max, e.getValue());
     }
   }
   result.setValue(max + (sum - max) * tieBreakerMultiplier);
   return result;
 }
    @Override
    public Explanation explain(IndexReader reader, int doc) throws IOException {
      SolrIndexReader topReader = (SolrIndexReader) reader;
      SolrIndexReader[] subReaders = topReader.getLeafReaders();
      int[] offsets = topReader.getLeafOffsets();
      int readerPos = SolrIndexReader.readerIndex(doc, offsets);
      int readerBase = offsets[readerPos];

      Explanation subQueryExpl = qWeight.explain(reader, doc);
      if (!subQueryExpl.isMatch()) {
        return subQueryExpl;
      }

      DocValues vals = boostVal.getValues(context, subReaders[readerPos]);
      float sc = subQueryExpl.getValue() * vals.floatVal(doc - readerBase);
      Explanation res =
          new ComplexExplanation(true, sc, BoostedQuery.this.toString() + ", product of:");
      res.addDetail(subQueryExpl);
      res.addDetail(vals.explain(doc - readerBase));
      return res;
    }
    @Override
    public Explanation explain(AtomicReaderContext context, int doc) throws IOException {
      ComplexExplanation result = new ComplexExplanation();
      result.setDescription("weight(" + getQuery() + " in " + doc + "), product of:");

      Explanation idfExpl = new Explanation(idf, "idf(" + field + ":" + idfExp.explain() + ")");

      // 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
      ComplexExplanation fieldExpl = new ComplexExplanation();
      fieldExpl.setDescription("fieldWeight(" + getQuery() + " in " + doc + "), product of:");

      Scorer scorer = scorer(context, ScorerContext.def());
      if (scorer == null) {
        return new Explanation(0.0f, "no matching docs");
      }

      Explanation tfExplanation = new Explanation();
      int d = scorer.advance(doc);
      float phraseFreq;
      if (d == doc) {
        phraseFreq = scorer.freq();
      } else {
        phraseFreq = 0.0f;
      }

      tfExplanation.setValue(similarity.tf(phraseFreq));
      tfExplanation.setDescription("tf(phraseFreq=" + phraseFreq + ")");
      fieldExpl.addDetail(tfExplanation);
      fieldExpl.addDetail(idfExpl);

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

      fieldExpl.setMatch(Boolean.valueOf(tfExplanation.isMatch()));
      fieldExpl.setValue(tfExplanation.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;
    }