private static Status.TermIndexStatus checkFields(Fields fields,Bits liveDocs,int maxDoc,FieldInfos fieldInfos,boolean doPrint,boolean isVectors,PrintStream infoStream,boolean verbose) throws IOException {
  long startNS;
  if (doPrint) {
    startNS=System.nanoTime();
  }
 else {
    startNS=0;
  }
  final Status.TermIndexStatus status=new Status.TermIndexStatus();
  int computedFieldCount=0;
  PostingsEnum postings=null;
  String lastField=null;
  for (  String field : fields) {
    if (lastField != null && field.compareTo(lastField) <= 0) {
      throw new RuntimeException("fields out of order: lastField=" + lastField + " field="+ field);
    }
    lastField=field;
    FieldInfo fieldInfo=fieldInfos.fieldInfo(field);
    if (fieldInfo == null) {
      throw new RuntimeException("fieldsEnum inconsistent with fieldInfos, no fieldInfos for: " + field);
    }
    if (fieldInfo.getIndexOptions() == IndexOptions.NONE) {
      throw new RuntimeException("fieldsEnum inconsistent with fieldInfos, isIndexed == false for: " + field);
    }
    computedFieldCount++;
    final Terms terms=fields.terms(field);
    if (terms == null) {
      continue;
    }
    final boolean hasFreqs=terms.hasFreqs();
    final boolean hasPositions=terms.hasPositions();
    final boolean hasPayloads=terms.hasPayloads();
    final boolean hasOffsets=terms.hasOffsets();
    BytesRef maxTerm;
    BytesRef minTerm;
    if (isVectors) {
      maxTerm=null;
      minTerm=null;
    }
 else {
      BytesRef bb=terms.getMin();
      if (bb != null) {
        assert bb.isValid();
        minTerm=BytesRef.deepCopyOf(bb);
      }
 else {
        minTerm=null;
      }
      bb=terms.getMax();
      if (bb != null) {
        assert bb.isValid();
        maxTerm=BytesRef.deepCopyOf(bb);
        if (minTerm == null) {
          throw new RuntimeException("field \"" + field + "\" has null minTerm but non-null maxTerm");
        }
      }
 else {
        maxTerm=null;
        if (minTerm != null) {
          throw new RuntimeException("field \"" + field + "\" has non-null minTerm but null maxTerm");
        }
      }
    }
    final boolean expectedHasFreqs=(isVectors || fieldInfo.getIndexOptions().compareTo(IndexOptions.DOCS_AND_FREQS) >= 0);
    if (hasFreqs != expectedHasFreqs) {
      throw new RuntimeException("field \"" + field + "\" should have hasFreqs="+ expectedHasFreqs+ " but got "+ hasFreqs);
    }
    if (hasFreqs == false) {
      if (terms.getSumTotalTermFreq() != -1) {
        throw new RuntimeException("field \"" + field + "\" hasFreqs is false, but Terms.getSumTotalTermFreq()="+ terms.getSumTotalTermFreq()+ " (should be -1)");
      }
    }
    if (!isVectors) {
      final boolean expectedHasPositions=fieldInfo.getIndexOptions().compareTo(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS) >= 0;
      if (hasPositions != expectedHasPositions) {
        throw new RuntimeException("field \"" + field + "\" should have hasPositions="+ expectedHasPositions+ " but got "+ hasPositions);
      }
      final boolean expectedHasPayloads=fieldInfo.hasPayloads();
      if (hasPayloads != expectedHasPayloads) {
        throw new RuntimeException("field \"" + field + "\" should have hasPayloads="+ expectedHasPayloads+ " but got "+ hasPayloads);
      }
      final boolean expectedHasOffsets=fieldInfo.getIndexOptions().compareTo(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS) >= 0;
      if (hasOffsets != expectedHasOffsets) {
        throw new RuntimeException("field \"" + field + "\" should have hasOffsets="+ expectedHasOffsets+ " but got "+ hasOffsets);
      }
    }
    final TermsEnum termsEnum=terms.iterator();
    boolean hasOrd=true;
    final long termCountStart=status.delTermCount + status.termCount;
    BytesRefBuilder lastTerm=null;
    long sumTotalTermFreq=0;
    long sumDocFreq=0;
    FixedBitSet visitedDocs=new FixedBitSet(maxDoc);
    while (true) {
      final BytesRef term=termsEnum.next();
      if (term == null) {
        break;
      }
      assert term.isValid();
      if (lastTerm == null) {
        lastTerm=new BytesRefBuilder();
        lastTerm.copyBytes(term);
      }
 else {
        if (lastTerm.get().compareTo(term) >= 0) {
          throw new RuntimeException("terms out of order: lastTerm=" + lastTerm.get() + " term="+ term);
        }
        lastTerm.copyBytes(term);
      }
      if (isVectors == false) {
        if (minTerm == null) {
          assert maxTerm == null;
          throw new RuntimeException("field=\"" + field + "\": invalid term: term="+ term+ ", minTerm="+ minTerm);
        }
        if (term.compareTo(minTerm) < 0) {
          throw new RuntimeException("field=\"" + field + "\": invalid term: term="+ term+ ", minTerm="+ minTerm);
        }
        if (term.compareTo(maxTerm) > 0) {
          throw new RuntimeException("field=\"" + field + "\": invalid term: term="+ term+ ", maxTerm="+ maxTerm);
        }
      }
      final int docFreq=termsEnum.docFreq();
      if (docFreq <= 0) {
        throw new RuntimeException("docfreq: " + docFreq + " is out of bounds");
      }
      sumDocFreq+=docFreq;
      postings=termsEnum.postings(postings,PostingsEnum.ALL);
      if (hasFreqs == false) {
        if (termsEnum.totalTermFreq() != -1) {
          throw new RuntimeException("field \"" + field + "\" hasFreqs is false, but TermsEnum.totalTermFreq()="+ termsEnum.totalTermFreq()+ " (should be -1)");
        }
      }
      if (hasOrd) {
        long ord=-1;
        try {
          ord=termsEnum.ord();
        }
 catch (        UnsupportedOperationException uoe) {
          hasOrd=false;
        }
        if (hasOrd) {
          final long ordExpected=status.delTermCount + status.termCount - termCountStart;
          if (ord != ordExpected) {
            throw new RuntimeException("ord mismatch: TermsEnum has ord=" + ord + " vs actual="+ ordExpected);
          }
        }
      }
      int lastDoc=-1;
      int docCount=0;
      boolean hasNonDeletedDocs=false;
      long totalTermFreq=0;
      while (true) {
        final int doc=postings.nextDoc();
        if (doc == DocIdSetIterator.NO_MORE_DOCS) {
          break;
        }
        visitedDocs.set(doc);
        int freq=-1;
        if (hasFreqs) {
          freq=postings.freq();
          if (freq <= 0) {
            throw new RuntimeException("term " + term + ": doc "+ doc+ ": freq "+ freq+ " is out of bounds");
          }
          totalTermFreq+=freq;
        }
 else {
          if (postings.freq() != 1) {
            throw new RuntimeException("term " + term + ": doc "+ doc+ ": freq "+ freq+ " != 1 when Terms.hasFreqs() is false");
          }
        }
        if (liveDocs == null || liveDocs.get(doc)) {
          hasNonDeletedDocs=true;
          status.totFreq++;
          if (freq >= 0) {
            status.totPos+=freq;
          }
        }
        docCount++;
        if (doc <= lastDoc) {
          throw new RuntimeException("term " + term + ": doc "+ doc+ " <= lastDoc "+ lastDoc);
        }
        if (doc >= maxDoc) {
          throw new RuntimeException("term " + term + ": doc "+ doc+ " >= maxDoc "+ maxDoc);
        }
        lastDoc=doc;
        int lastPos=-1;
        int lastOffset=0;
        if (hasPositions) {
          for (int j=0; j < freq; j++) {
            final int pos=postings.nextPosition();
            if (pos < 0) {
              throw new RuntimeException("term " + term + ": doc "+ doc+ ": pos "+ pos+ " is out of bounds");
            }
            if (pos > IndexWriter.MAX_POSITION) {
              throw new RuntimeException("term " + term + ": doc "+ doc+ ": pos "+ pos+ " > IndexWriter.MAX_POSITION="+ IndexWriter.MAX_POSITION);
            }
            if (pos < lastPos) {
              throw new RuntimeException("term " + term + ": doc "+ doc+ ": pos "+ pos+ " < lastPos "+ lastPos);
            }
            lastPos=pos;
            BytesRef payload=postings.getPayload();
            if (payload != null) {
              assert payload.isValid();
            }
            if (payload != null && payload.length < 1) {
              throw new RuntimeException("term " + term + ": doc "+ doc+ ": pos "+ pos+ " payload length is out of bounds "+ payload.length);
            }
            if (hasOffsets) {
              int startOffset=postings.startOffset();
              int endOffset=postings.endOffset();
              if (!isVectors) {
                if (startOffset < 0) {
                  throw new RuntimeException("term " + term + ": doc "+ doc+ ": pos "+ pos+ ": startOffset "+ startOffset+ " is out of bounds");
                }
                if (startOffset < lastOffset) {
                  throw new RuntimeException("term " + term + ": doc "+ doc+ ": pos "+ pos+ ": startOffset "+ startOffset+ " < lastStartOffset "+ lastOffset);
                }
                if (endOffset < 0) {
                  throw new RuntimeException("term " + term + ": doc "+ doc+ ": pos "+ pos+ ": endOffset "+ endOffset+ " is out of bounds");
                }
                if (endOffset < startOffset) {
                  throw new RuntimeException("term " + term + ": doc "+ doc+ ": pos "+ pos+ ": endOffset "+ endOffset+ " < startOffset "+ startOffset);
                }
              }
              lastOffset=startOffset;
            }
          }
        }
      }
      if (hasNonDeletedDocs) {
        status.termCount++;
      }
 else {
        status.delTermCount++;
      }
      final long totalTermFreq2=termsEnum.totalTermFreq();
      final boolean hasTotalTermFreq=hasFreqs && totalTermFreq2 != -1;
      if (docCount != docFreq) {
        throw new RuntimeException("term " + term + " docFreq="+ docFreq+ " != tot docs w/o deletions "+ docCount);
      }
      if (hasTotalTermFreq) {
        if (totalTermFreq2 <= 0) {
          throw new RuntimeException("totalTermFreq: " + totalTermFreq2 + " is out of bounds");
        }
        sumTotalTermFreq+=totalTermFreq;
        if (totalTermFreq != totalTermFreq2) {
          throw new RuntimeException("term " + term + " totalTermFreq="+ totalTermFreq2+ " != recomputed totalTermFreq="+ totalTermFreq);
        }
      }
      if (hasPositions) {
        for (int idx=0; idx < 7; idx++) {
          final int skipDocID=(int)(((idx + 1) * (long)maxDoc) / 8);
          postings=termsEnum.postings(postings,PostingsEnum.ALL);
          final int docID=postings.advance(skipDocID);
          if (docID == DocIdSetIterator.NO_MORE_DOCS) {
            break;
          }
 else {
            if (docID < skipDocID) {
              throw new RuntimeException("term " + term + ": advance(docID="+ skipDocID+ ") returned docID="+ docID);
            }
            final int freq=postings.freq();
            if (freq <= 0) {
              throw new RuntimeException("termFreq " + freq + " is out of bounds");
            }
            int lastPosition=-1;
            int lastOffset=0;
            for (int posUpto=0; posUpto < freq; posUpto++) {
              final int pos=postings.nextPosition();
              if (pos < 0) {
                throw new RuntimeException("position " + pos + " is out of bounds");
              }
              if (pos < lastPosition) {
                throw new RuntimeException("position " + pos + " is < lastPosition "+ lastPosition);
              }
              lastPosition=pos;
              if (hasOffsets) {
                int startOffset=postings.startOffset();
                int endOffset=postings.endOffset();
                if (!isVectors) {
                  if (startOffset < 0) {
                    throw new RuntimeException("term " + term + ": doc "+ docID+ ": pos "+ pos+ ": startOffset "+ startOffset+ " is out of bounds");
                  }
                  if (startOffset < lastOffset) {
                    throw new RuntimeException("term " + term + ": doc "+ docID+ ": pos "+ pos+ ": startOffset "+ startOffset+ " < lastStartOffset "+ lastOffset);
                  }
                  if (endOffset < 0) {
                    throw new RuntimeException("term " + term + ": doc "+ docID+ ": pos "+ pos+ ": endOffset "+ endOffset+ " is out of bounds");
                  }
                  if (endOffset < startOffset) {
                    throw new RuntimeException("term " + term + ": doc "+ docID+ ": pos "+ pos+ ": endOffset "+ endOffset+ " < startOffset "+ startOffset);
                  }
                }
                lastOffset=startOffset;
              }
            }
            final int nextDocID=postings.nextDoc();
            if (nextDocID == DocIdSetIterator.NO_MORE_DOCS) {
              break;
            }
            if (nextDocID <= docID) {
              throw new RuntimeException("term " + term + ": advance(docID="+ skipDocID+ "), then .next() returned docID="+ nextDocID+ " vs prev docID="+ docID);
            }
          }
          if (isVectors) {
            break;
          }
        }
      }
 else {
        for (int idx=0; idx < 7; idx++) {
          final int skipDocID=(int)(((idx + 1) * (long)maxDoc) / 8);
          postings=termsEnum.postings(postings,PostingsEnum.NONE);
          final int docID=postings.advance(skipDocID);
          if (docID == DocIdSetIterator.NO_MORE_DOCS) {
            break;
          }
 else {
            if (docID < skipDocID) {
              throw new RuntimeException("term " + term + ": advance(docID="+ skipDocID+ ") returned docID="+ docID);
            }
            final int nextDocID=postings.nextDoc();
            if (nextDocID == DocIdSetIterator.NO_MORE_DOCS) {
              break;
            }
            if (nextDocID <= docID) {
              throw new RuntimeException("term " + term + ": advance(docID="+ skipDocID+ "), then .next() returned docID="+ nextDocID+ " vs prev docID="+ docID);
            }
          }
          if (isVectors) {
            break;
          }
        }
      }
    }
    if (minTerm != null && status.termCount + status.delTermCount == 0) {
      throw new RuntimeException("field=\"" + field + "\": minTerm is non-null yet we saw no terms: "+ minTerm);
    }
    final Terms fieldTerms=fields.terms(field);
    if (fieldTerms == null) {
    }
 else {
      long fieldTermCount=(status.delTermCount + status.termCount) - termCountStart;
      if (false && hasFreqs == false) {
        checkTermRanges(field,maxDoc,fieldTerms,fieldTermCount);
      }
      final Object stats=fieldTerms.getStats();
      assert stats != null;
      if (status.blockTreeStats == null) {
        status.blockTreeStats=new HashMap<>();
      }
      status.blockTreeStats.put(field,stats);
      if (sumTotalTermFreq != 0) {
        final long v=fields.terms(field).getSumTotalTermFreq();
        if (v != -1 && sumTotalTermFreq != v) {
          throw new RuntimeException("sumTotalTermFreq for field " + field + "="+ v+ " != recomputed sumTotalTermFreq="+ sumTotalTermFreq);
        }
      }
      if (sumDocFreq != 0) {
        final long v=fields.terms(field).getSumDocFreq();
        if (v != -1 && sumDocFreq != v) {
          throw new RuntimeException("sumDocFreq for field " + field + "="+ v+ " != recomputed sumDocFreq="+ sumDocFreq);
        }
      }
      final int v=fieldTerms.getDocCount();
      if (v != -1 && visitedDocs.cardinality() != v) {
        throw new RuntimeException("docCount for field " + field + "="+ v+ " != recomputed docCount="+ visitedDocs.cardinality());
      }
      if (lastTerm != null) {
        if (termsEnum.seekCeil(lastTerm.get()) != TermsEnum.SeekStatus.FOUND) {
          throw new RuntimeException("seek to last term " + lastTerm.get() + " failed");
        }
        if (termsEnum.term().equals(lastTerm.get()) == false) {
          throw new RuntimeException("seek to last term " + lastTerm.get() + " returned FOUND but seeked to the wrong term "+ termsEnum.term());
        }
        int expectedDocFreq=termsEnum.docFreq();
        PostingsEnum d=termsEnum.postings(null,PostingsEnum.NONE);
        int docFreq=0;
        while (d.nextDoc() != DocIdSetIterator.NO_MORE_DOCS) {
          docFreq++;
        }
        if (docFreq != expectedDocFreq) {
          throw new RuntimeException("docFreq for last term " + lastTerm.get() + "="+ expectedDocFreq+ " != recomputed docFreq="+ docFreq);
        }
      }
      long termCount=-1;
      if (fieldTermCount > 0) {
        termCount=fields.terms(field).size();
        if (termCount != -1 && termCount != fieldTermCount) {
          throw new RuntimeException("termCount mismatch " + termCount + " vs "+ fieldTermCount);
        }
      }
      if (hasOrd && status.termCount - termCountStart > 0) {
        int seekCount=(int)Math.min(10000L,termCount);
        if (seekCount > 0) {
          BytesRef[] seekTerms=new BytesRef[seekCount];
          for (int i=seekCount - 1; i >= 0; i--) {
            long ord=i * (termCount / seekCount);
            termsEnum.seekExact(ord);
            long actualOrd=termsEnum.ord();
            if (actualOrd != ord) {
              throw new RuntimeException("seek to ord " + ord + " returned ord "+ actualOrd);
            }
            seekTerms[i]=BytesRef.deepCopyOf(termsEnum.term());
          }
          for (int i=seekCount - 1; i >= 0; i--) {
            if (termsEnum.seekCeil(seekTerms[i]) != TermsEnum.SeekStatus.FOUND) {
              throw new RuntimeException("seek to existing term " + seekTerms[i] + " failed");
            }
            if (termsEnum.term().equals(seekTerms[i]) == false) {
              throw new RuntimeException("seek to existing term " + seekTerms[i] + " returned FOUND but seeked to the wrong term "+ termsEnum.term());
            }
            postings=termsEnum.postings(postings,PostingsEnum.NONE);
            if (postings == null) {
              throw new RuntimeException("null DocsEnum from to existing term " + seekTerms[i]);
            }
          }
        }
      }
    }
  }
  int fieldCount=fields.size();
  if (fieldCount != -1) {
    if (fieldCount < 0) {
      throw new RuntimeException("invalid fieldCount: " + fieldCount);
    }
    if (fieldCount != computedFieldCount) {
      throw new RuntimeException("fieldCount mismatch " + fieldCount + " vs recomputed field count "+ computedFieldCount);
    }
  }
  if (doPrint) {
    msg(infoStream,String.format(Locale.ROOT,"OK [%d terms; %d terms/docs pairs; %d tokens] [took %.3f sec]",status.termCount,status.totFreq,status.totPos,nsToSec(System.nanoTime() - startNS)));
  }
  if (verbose && status.blockTreeStats != null && infoStream != null && status.termCount > 0) {
    for (    Map.Entry<String,Object> ent : status.blockTreeStats.entrySet()) {
      infoStream.println("      field \"" + ent.getKey() + "\":");
      infoStream.println("      " + ent.getValue().toString().replace("\n","\n      "));
    }
  }
  return status;
}

private static Status . TermIndexStatus checkFields ( Fields fields , Bits liveDocs , int maxDoc , FieldInfos fieldInfos , boolean doPrint , boolean isVectors , PrintStream infoStream , boolean verbose ) throws IOException { long startNS ; if ( doPrint ) { startNS = System . nanoTime ( ) ; } else { startNS = 0 ; } final Status . TermIndexStatus status = new Status . TermIndexStatus ( ) ; int computedFieldCount = 0 ; PostingsEnum postings = null ; String lastField = null ; for ( String field : fields ) { if ( lastField != null && field . compareTo ( lastField ) <= 0 ) { throw new RuntimeException ( "fields out of order: lastField=" + lastField + " field=" + field ) ; } lastField = field ; FieldInfo fieldInfo = fieldInfos . fieldInfo ( field ) ; if ( fieldInfo == null ) { throw new RuntimeException ( "fieldsEnum inconsistent with fieldInfos, no fieldInfos for: " + field ) ; } if ( fieldInfo . getIndexOptions ( ) == IndexOptions . NONE ) { throw new RuntimeException ( "fieldsEnum inconsistent with fieldInfos, isIndexed == false for: " + field ) ; } computedFieldCount ++ ; final Terms terms = fields . terms ( field ) ; if ( terms == null ) { continue ; } final boolean hasFreqs = terms . hasFreqs ( ) ; final boolean hasPositions = terms . hasPositions ( ) ; final boolean hasPayloads = terms . hasPayloads ( ) ; final boolean hasOffsets = terms . hasOffsets ( ) ; BytesRef maxTerm ; BytesRef minTerm ; if ( isVectors ) { maxTerm = null ; minTerm = null ; } else { BytesRef bb = terms . getMin ( ) ; if ( bb != null ) { assert bb . isValid ( ) ; minTerm = BytesRef . deepCopyOf ( bb ) ; } else { minTerm = null ; } bb = terms . getMax ( ) ; if ( bb != null ) { assert bb . isValid ( ) ; maxTerm = BytesRef . deepCopyOf ( bb ) ; if ( minTerm == null ) { throw new RuntimeException ( "field \"" + field + "\" has null minTerm but non-null maxTerm" ) ; } } else { maxTerm = null ; if ( minTerm != null ) { throw new RuntimeException ( "field \"" + field + "\" has non-null minTerm but null maxTerm" ) ; } } } final boolean expectedHasFreqs = ( isVectors || fieldInfo . getIndexOptions ( ) . compareTo ( IndexOptions . DOCS_AND_FREQS ) >= 0 ) ; if ( hasFreqs != expectedHasFreqs ) { throw new RuntimeException ( "field \"" + field + "\" should have hasFreqs=" + expectedHasFreqs + " but got " + hasFreqs ) ; } if ( hasFreqs == false ) { if ( terms . getSumTotalTermFreq ( ) != - 1 ) { throw new RuntimeException ( "field \"" + field + "\" hasFreqs is false, but Terms.getSumTotalTermFreq()=" + terms . getSumTotalTermFreq ( ) + " (should be -1)" ) ; } } if ( ! isVectors ) { final boolean expectedHasPositions = fieldInfo . getIndexOptions ( ) . compareTo ( IndexOptions . DOCS_AND_FREQS_AND_POSITIONS ) >= 0 ; if ( hasPositions != expectedHasPositions ) { throw new RuntimeException ( "field \"" + field + "\" should have hasPositions=" + expectedHasPositions + " but got " + hasPositions ) ; } final boolean expectedHasPayloads = fieldInfo . hasPayloads ( ) ; if ( hasPayloads != expectedHasPayloads ) { throw new RuntimeException ( "field \"" + field + "\" should have hasPayloads=" + expectedHasPayloads + " but got " + hasPayloads ) ; } final boolean expectedHasOffsets = fieldInfo . getIndexOptions ( ) . compareTo ( IndexOptions . DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS ) >= 0 ; if ( hasOffsets != expectedHasOffsets ) { throw new RuntimeException ( "field \"" + field + "\" should have hasOffsets=" + expectedHasOffsets + " but got " + hasOffsets ) ; } } final TermsEnum termsEnum = terms . iterator ( ) ; boolean hasOrd = true ; final long termCountStart = status . delTermCount + status . termCount ; BytesRefBuilder lastTerm = null ; long sumTotalTermFreq = 0 ; long sumDocFreq = 0 ; FixedBitSet visitedDocs = new FixedBitSet ( maxDoc ) ; while ( true ) { final BytesRef term = termsEnum . next ( ) ; if ( term == null ) { break ; } assert term . isValid ( ) ; if ( lastTerm == null ) { lastTerm = new BytesRefBuilder ( ) ; lastTerm . copyBytes ( term ) ; } else { if ( lastTerm . get ( ) . compareTo ( term ) >= 0 ) { throw new RuntimeException ( "terms out of order: lastTerm=" + lastTerm . get ( ) + " term=" + term ) ; } lastTerm . copyBytes ( term ) ; } if ( isVectors == false ) { if ( minTerm == null ) { assert maxTerm == null ; throw new RuntimeException ( "field=\"" + field + "\": invalid term: term=" + term + ", minTerm=" + minTerm ) ; } if ( term . compareTo ( minTerm ) < 0 ) { throw new RuntimeException ( "field=\"" + field + "\": invalid term: term=" + term + ", minTerm=" + minTerm ) ; } if ( term . compareTo ( maxTerm ) > 0 ) { throw new RuntimeException ( "field=\"" + field + "\": invalid term: term=" + term + ", maxTerm=" + maxTerm ) ; } } final int docFreq = termsEnum . docFreq ( ) ; if ( docFreq <= 0 ) { throw new RuntimeException ( "docfreq: " + docFreq + " is out of bounds" ) ; } sumDocFreq += docFreq ; postings = termsEnum . postings ( postings , PostingsEnum . ALL ) ; if ( hasFreqs == false ) { if ( termsEnum . totalTermFreq ( ) != - 1 ) { throw new RuntimeException ( "field \"" + field + "\" hasFreqs is false, but TermsEnum.totalTermFreq()=" + termsEnum . totalTermFreq ( ) + " (should be -1)" ) ; } } if ( hasOrd ) { long ord = - 1 ; try { ord = termsEnum . ord ( ) ; } catch ( UnsupportedOperationException uoe ) { hasOrd = false ; } if ( hasOrd ) { final long ordExpected = status . delTermCount + status . termCount - termCountStart ; if ( ord != ordExpected ) { throw new RuntimeException ( "ord mismatch: TermsEnum has ord=" + ord + " vs actual=" + ordExpected ) ; } } } int lastDoc = - 1 ; int docCount = 0 ; boolean hasNonDeletedDocs = false ; long totalTermFreq = 0 ; while ( true ) { final int doc = postings . nextDoc ( ) ; if ( doc == DocIdSetIterator . NO_MORE_DOCS ) { break ; } visitedDocs . set ( doc ) ; int freq = - 1 ; if ( hasFreqs ) { freq = postings . freq ( ) ; if ( freq <= 0 ) { throw new RuntimeException ( "term " + term + ": doc " + doc + ": freq " + freq + " is out of bounds" ) ; } totalTermFreq += freq ; } else { if ( postings . freq ( ) != 1 ) { throw new RuntimeException ( "term " + term + ": doc " + doc + ": freq " + freq + " != 1 when Terms.hasFreqs() is false" ) ; } } if ( liveDocs == null || liveDocs . get ( doc ) ) { hasNonDeletedDocs = true ; status . totFreq ++ ; if ( freq >= 0 ) { status . totPos += freq ; } } docCount ++ ; if ( doc <= lastDoc ) { throw new RuntimeException ( "term " + term + ": doc " + doc + " <= lastDoc " + lastDoc ) ; } if ( doc >= maxDoc ) { throw new RuntimeException ( "term " + term + ": doc " + doc + " >= maxDoc " + maxDoc ) ; } lastDoc = doc ; int lastPos = - 1 ; int lastOffset = 0 ; if ( hasPositions ) { for ( int j = 0 ; j < freq ; j ++ ) { final int pos = postings . nextPosition ( ) ; if ( pos < 0 ) { throw new RuntimeException ( "term " + term + ": doc " + doc + ": pos " + pos + " is out of bounds" ) ; } if ( pos > IndexWriter . MAX_POSITION ) { throw new RuntimeException ( "term " + term + ": doc " + doc + ": pos " + pos + " > IndexWriter.MAX_POSITION=" + IndexWriter . MAX_POSITION ) ; } if ( pos < lastPos ) { throw new RuntimeException ( "term " + term + ": doc " + doc + ": pos " + pos + " < lastPos " + lastPos ) ; } lastPos = pos ; BytesRef payload = postings . getPayload ( ) ; if ( payload != null ) { assert payload . isValid ( ) ; } if ( payload != null && payload . length < 1 ) { throw new RuntimeException ( "term " + term + ": doc " + doc + ": pos " + pos + " payload length is out of bounds " + payload . length ) ; } if ( hasOffsets ) { int startOffset = postings . startOffset ( ) ; int endOffset = postings . endOffset ( ) ; if ( ! isVectors ) { if ( startOffset < 0 ) { throw new RuntimeException ( "term " + term + ": doc " + doc + ": pos " + pos + ": startOffset " + startOffset + " is out of bounds" ) ; } if ( startOffset < lastOffset ) { throw new RuntimeException ( "term " + term + ": doc " + doc + ": pos " + pos + ": startOffset " + startOffset + " < lastStartOffset " + lastOffset ) ; } if ( endOffset < 0 ) { throw new RuntimeException ( "term " + term + ": doc " + doc + ": pos " + pos + ": endOffset " + endOffset + " is out of bounds" ) ; } if ( endOffset < startOffset ) { throw new RuntimeException ( "term " + term + ": doc " + doc + ": pos " + pos + ": endOffset " + endOffset + " < startOffset " + startOffset ) ; } } lastOffset = startOffset ; } } } } if ( hasNonDeletedDocs ) { status . termCount ++ ; } else { status . delTermCount ++ ; } final long totalTermFreq2 = termsEnum . totalTermFreq ( ) ; final boolean hasTotalTermFreq = hasFreqs && totalTermFreq2 != - 1 ; if ( docCount != docFreq ) { throw new RuntimeException ( "term " + term + " docFreq=" + docFreq + " != tot docs w/o deletions " + docCount ) ; } if ( hasTotalTermFreq ) { if ( totalTermFreq2 <= 0 ) { throw new RuntimeException ( "totalTermFreq: " + totalTermFreq2 + " is out of bounds" ) ; } sumTotalTermFreq += totalTermFreq ; if ( totalTermFreq != totalTermFreq2 ) { throw new RuntimeException ( "term " + term + " totalTermFreq=" + totalTermFreq2 + " != recomputed totalTermFreq=" + totalTermFreq ) ; } } if ( hasPositions ) { for ( int idx = 0 ; idx < 7 ; idx ++ ) { final int skipDocID = ( int ) ( ( ( idx + 1 ) * ( long ) maxDoc ) / 8 ) ; postings = termsEnum . postings ( postings , PostingsEnum . ALL ) ; final int docID = postings . advance ( skipDocID ) ; if ( docID == DocIdSetIterator . NO_MORE_DOCS ) { break ; } else { if ( docID < skipDocID ) { throw new RuntimeException ( "term " + term + ": advance(docID=" + skipDocID + ") returned docID=" + docID ) ; } final int freq = postings . freq ( ) ; if ( freq <= 0 ) { throw new RuntimeException ( "termFreq " + freq + " is out of bounds" ) ; } int lastPosition = - 1 ; int lastOffset = 0 ; for ( int posUpto = 0 ; posUpto < freq ; posUpto ++ ) { final int pos = postings . nextPosition ( ) ; if ( pos < 0 ) { throw new RuntimeException ( "position " + pos + " is out of bounds" ) ; } if ( pos < lastPosition ) { throw new RuntimeException ( "position " + pos + " is < lastPosition " + lastPosition ) ; } lastPosition = pos ; if ( hasOffsets ) { int startOffset = postings . startOffset ( ) ; int endOffset = postings . endOffset ( ) ; if ( ! isVectors ) { if ( startOffset < 0 ) { throw new RuntimeException ( "term " + term + ": doc " + docID + ": pos " + pos + ": startOffset " + startOffset + " is out of bounds" ) ; } if ( startOffset < lastOffset ) { throw new RuntimeException ( "term " + term + ": doc " + docID + ": pos " + pos + ": startOffset " + startOffset + " < lastStartOffset " + lastOffset ) ; } if ( endOffset < 0 ) { throw new RuntimeException ( "term " + term + ": doc " + docID + ": pos " + pos + ": endOffset " + endOffset + " is out of bounds" ) ; } if ( endOffset < startOffset ) { throw new RuntimeException ( "term " + term + ": doc " + docID + ": pos " + pos + ": endOffset " + endOffset + " < startOffset " + startOffset ) ; } } lastOffset = startOffset ; } } final int nextDocID = postings . nextDoc ( ) ; if ( nextDocID == DocIdSetIterator . NO_MORE_DOCS ) { break ; } if ( nextDocID <= docID ) { throw new RuntimeException ( "term " + term + ": advance(docID=" + skipDocID + "), then .next() returned docID=" + nextDocID + " vs prev docID=" + docID ) ; } } if ( isVectors ) { break ; } } } else { for ( int idx = 0 ; idx < 7 ; idx ++ ) { final int skipDocID = ( int ) ( ( ( idx + 1 ) * ( long ) maxDoc ) / 8 ) ; postings = termsEnum . postings ( postings , PostingsEnum . NONE ) ; final int docID = postings . advance ( skipDocID ) ; if ( docID == DocIdSetIterator . NO_MORE_DOCS ) { break ; } else { if ( docID < skipDocID ) { throw new RuntimeException ( "term " + term + ": advance(docID=" + skipDocID + ") returned docID=" + docID ) ; } final int nextDocID = postings . nextDoc ( ) ; if ( nextDocID == DocIdSetIterator . NO_MORE_DOCS ) { break ; } if ( nextDocID <= docID ) { throw new RuntimeException ( "term " + term + ": advance(docID=" + skipDocID + "), then .next() returned docID=" + nextDocID + " vs prev docID=" + docID ) ; } } if ( isVectors ) { break ; } } } } if ( minTerm != null && status . termCount + status . delTermCount == 0 ) { throw new RuntimeException ( "field=\"" + field + "\": minTerm is non-null yet we saw no terms: " + minTerm ) ; } final Terms fieldTerms = fields . terms ( field ) ; if ( fieldTerms == null ) { } else { long fieldTermCount = ( status . delTermCount + status . termCount ) - termCountStart ; if ( false && hasFreqs == false ) { checkTermRanges ( field , maxDoc , fieldTerms , fieldTermCount ) ; } final Object stats = fieldTerms . getStats ( ) ; assert stats != null ; if ( status . blockTreeStats == null ) { status . blockTreeStats = new HashMap < > ( ) ; } status . blockTreeStats . put ( field , stats ) ; if ( sumTotalTermFreq != 0 ) { final long v = fields . terms ( field ) . getSumTotalTermFreq ( ) ; if ( v != - 1 && sumTotalTermFreq != v ) { throw new RuntimeException ( "sumTotalTermFreq for field " + field + "=" + v + " != recomputed sumTotalTermFreq=" + sumTotalTermFreq ) ; } } if ( sumDocFreq != 0 ) { final long v = fields . terms ( field ) . getSumDocFreq ( ) ; if ( v != - 1 && sumDocFreq != v ) { throw new RuntimeException ( "sumDocFreq for field " + field + "=" + v + " != recomputed sumDocFreq=" + sumDocFreq ) ; } } final int v = fieldTerms . getDocCount ( ) ; if ( v != - 1 && visitedDocs . cardinality ( ) != v ) { throw new RuntimeException ( "docCount for field " + field + "=" + v + " != recomputed docCount=" + visitedDocs . cardinality ( ) ) ; } if ( lastTerm != null ) { if ( termsEnum . seekCeil ( lastTerm . get ( ) ) != TermsEnum . SeekStatus . FOUND ) { throw new RuntimeException ( "seek to last term " + lastTerm . get ( ) + " failed" ) ; } if ( termsEnum . term ( ) . equals ( lastTerm . get ( ) ) == false ) { throw new RuntimeException ( "seek to last term " + lastTerm . get ( ) + " returned FOUND but seeked to the wrong term " + termsEnum . term ( ) ) ; } int expectedDocFreq = termsEnum . docFreq ( ) ; PostingsEnum d = termsEnum . postings ( null , PostingsEnum . NONE ) ; int docFreq = 0 ; while ( d . nextDoc ( ) != DocIdSetIterator . NO_MORE_DOCS ) { docFreq ++ ; } if ( docFreq != expectedDocFreq ) { throw new RuntimeException ( "docFreq for last term " + lastTerm . get ( ) + "=" + expectedDocFreq + " != recomputed docFreq=" + docFreq ) ; } } long termCount = - 1 ; if ( fieldTermCount > 0 ) { termCount = fields . terms ( field ) . size ( ) ; if ( termCount != - 1 && termCount != fieldTermCount ) { throw new RuntimeException ( "termCount mismatch " + termCount + " vs " + fieldTermCount ) ; } } if ( hasOrd && status . termCount - termCountStart > 0 ) { int seekCount = ( int ) Math . min ( 10000L , termCount ) ; if ( seekCount > 0 ) { BytesRef [ ] seekTerms = new BytesRef [ seekCount ] ; for ( int i = seekCount - 1 ; i >= 0 ; i -- ) { long ord = i * ( termCount / seekCount ) ; termsEnum . seekExact ( ord ) ; long actualOrd = termsEnum . ord ( ) ; if ( actualOrd != ord ) { throw new RuntimeException ( "seek to ord " + ord + " returned ord " + actualOrd ) ; } seekTerms [ i ] = BytesRef . deepCopyOf ( termsEnum . term ( ) ) ; } for ( int i = seekCount - 1 ; i >= 0 ; i -- ) { if ( termsEnum . seekCeil ( seekTerms [ i ] ) != TermsEnum . SeekStatus . FOUND ) { throw new RuntimeException ( "seek to existing term " + seekTerms [ i ] + " failed" ) ; } if ( termsEnum . term ( ) . equals ( seekTerms [ i ] ) == false ) { throw new RuntimeException ( "seek to existing term " + seekTerms [ i ] + " returned FOUND but seeked to the wrong term " + termsEnum . term ( ) ) ; } postings = termsEnum . postings ( postings , PostingsEnum . NONE ) ; if ( postings == null ) { throw new RuntimeException ( "null DocsEnum from to existing term " + seekTerms [ i ] ) ; } } } } } } int fieldCount = fields . size ( ) ; if ( fieldCount != - 1 ) { if ( fieldCount < 0 ) { throw new RuntimeException ( "invalid fieldCount: " + fieldCount ) ; } if ( fieldCount != computedFieldCount ) { throw new RuntimeException ( "fieldCount mismatch " + fieldCount + " vs recomputed field count " + computedFieldCount ) ; } } if ( doPrint ) { msg ( infoStream , String . format ( Locale . ROOT , "OK [%d terms; %d terms/docs pairs; %d tokens] [took %.3f sec]" , status . termCount , status . totFreq , status . totPos , nsToSec ( System . nanoTime ( ) - startNS ) ) ) ; } if ( verbose && status . blockTreeStats != null && infoStream != null && status . termCount > 0 ) { for ( Map . Entry < String , Object > ent : status . blockTreeStats . entrySet ( ) ) { infoStream . println ( "      field \"" + ent . getKey ( ) + "\":" ) ; infoStream . println ( "      " + ent . getValue ( ) . toString ( ) . replace ( "\n" , "\n      " ) ) ; } } return status ; }
checks fields api is consistent with itself . searcher is optional , to verify with queries . can be null .
