question: 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 ; }
target:  checks Fields api is consistent with itself. searcher is optional, to verify with queries. Can be null.