DefaultIndexingChain.flush.writeDocValues时,遍历fields,调用field的DocValuesWriter.flush,如: SortedDocValuesWriter.flush.
addSortedField时,获取该field的DocValuesConsumer(Lucene80DocValuesFormat使用Lucene80DocValuesConsumer)写docValues.
docValues按照values类型分为: NumericDocValuesField, BinaryDocValuesField, SortedDocValuesField, SortedSetDocValues, SortedNumericDocValues.
本文主要分析SortedDocValuesField.
Lucene80DocValuesConsumer
state: segmentState.
data: dvd,docValues data. Lucene80DocValuesFormat.
meta: dvm, docValues metadata. Lucene80DocValuesFormat.
maxDoc: 该segment doc数量.
addSortedField
写一个field的docValues.
metadata写入该field的fieldNumber, DocValues类型(numeric, binary, sorted, sorted_set, sorted_numeric).
doAddSortedField
写docIDs(docIDs < maxDocs才写), ords, values(termsEnum), terms index.
EmptyDocValuesProducer.getSorted获取BufferedSortedDocValues.
BufferedSortedDocValues:docIterator,valueCount,values(termsEnum(sorted)),currentDocOrd(from ordMap),currentDocValue.
例如:docs(value)为: 0(wang),1(zhang),2(NULL),3(long),则:
docs:0,1,3
ords:1,2,0
values(使用termsEnum):long, wang, zhang.因排序,遍历时可知values ord(0, 1, 2)。
numDocsWithField: 3,遍历values的docsWithField, 计算该field有value的docs数量.
1:写docIDs(roaring bit map)
1.1: numDocsWithField为0时
该field没有value,不用存。docsWithFieldOffset为-2.
1.2: numDocsWithField等于segment docs数量时
每个doc都用值,不用存docIDs,直接存ords和values。
1.3: numDocsWithField小于segment docs数量时,
获取dvd的offset,作为docsWithFieldOffset写入dvm。
1.3.1: IndexedDISI(DocIdSetIterator).writeBitSet使用roaring bit map写docIDs.
遍历values,取高2bytes,作为blockID(roaring bit map), 低2bytes作为value, 写该block的FixedBitSet.
根据docID取到新block时,flush prevBlock. blockCardinality记录该block的doc数量. totalCardinality记录该field的docs总数量.
jumps记录各个block的offset和doc数量.
IndexedDISI.flush写blockID,该block的docIDs: doc数量 >= 4096时, 写bitmap(write long); 否则直接写docID的低2bytes(write short).
写完docIDs的blocks后, IndexedDISI.flush写jumps(只有一个block时,不用写jumps).
docsWithFieldLength(docIDs' roaring bitmap, blocks' jumps)写入dvm.
jumpTableentryCount(block count)写入dvm.
numDocsWithField(docs count)写入dvm。
2:写ords(bitPack)
2.1: valueCount <= 1时
不需要写ord,dvm写入ords' bitsPerValue, offset, length都为0。
2.2: valueCount > 1时
valueCount - 1为最大的ord,作为ords' bitsPerValue写入dvm。
dvd写入ords之前的filePointer为ords' offset写入dvm。
遍历values,使用DirectWriter(写原始值,占bitsPerValue)将current doc ord写入dvd。
dvd写入ords之后的filePointer - offset为ords' length写入dvm。
3:写values(termsEnum, 与prevTerm求prefix,写term suffix)
addTermsDict写values(termsEnum).
dvm写valueCount, terms(values) block shift(4, 每16个terms一个block), direct monotonic block shift.
numBlocks:根据valueCount和block mask, block shift计算所需block数量。valueCount除以16(mask + 1)。
遍历termsEnum,每16个terms作为一个block写入dvd,每个block的startPointer写入dvm。详细如下:
写每个block的第一个term前, 使用DirectMonotonicWriter写该block之前terms的length(lengths产生的block meta写入dvm,lengths作为data写入dvd)。
block的第一个term写length(VInt), term.bytes。
记录term maxLength(all terms cross blocks),prevTerm.
block第二个term开始,计算与prevTerm的prefixLength,将Min(suffixLength - 1, 15)高4bits,Min(prefixLength, 15)低4bits,作为token写入dvd(Byte),
prefixLength,suffixLength大于15,16时,将差值写入dvd(VInt)。
Lucene80DocValuesProducer$TermsDict.next读取term时,从token中取出prefixLength,suffixLength,若等于15,16从dvd读取差值并加上。
只将term的suffix写入dvd(Bytes).
dvm写term maxLength, terms在dvd中的startPointer, length。写每个terms block之前的terms' lengths的startPointer,length。
prev terms length + terms在dvd中的startPointer即为该block的startPointer.
4:写values索引(与prevTerm的prefix + 1),Lucene80DocValuesProducer.seekCeil时使用.
writeTermsIndex写values索引,流程类似写values。
dvm写terms index shift(10, 每1024个terms写前缀索引).
numBlocks: 根据valueCount和block mask, block shift计算所需block数量。valueCount除以1024。
遍历termsEnum,每第1024*N个term,记录索引。
使用DirectMonotonicWriter写term前terms index的length/offset(lengths产生的block meta写入dvm,lengths作为data写入dvd)。
term与prevTerm求的sortKeyLength: 公共前缀length + 1。term的sortKeyLength个bytes作为terms index,写入dvd。
prevTerm: ball, term: banana. 写入: ban。
DirectMonotonicWriter写入总terms index的length/offset。
dvm写入terms index在dvd的start pointer, length。写每个term index之前的terms' index lengths的startPointer,length.
prev terms index length + terms index在dvd的start pointer即为该terms index的startPointer.
读取
numDocsWithField: 该field有值的doc数量。
numDocsWithField大于0且小于maxDoc(segment doc数)时:
1: docIDs(roaring bitmap), 该docID是否在该field有值。
2: ords中读取该docID位置的ord。
3: values(sorted)读取ord位置的value。
numDocsWithField等于maxDoc(segment doc数)时:
直接2,3即可。
Lucene80DocValuesProducer
reader
TermsDict.next读取term
其他
DirectWriter
直接写caller传入的原始值,占bitsPerValue。
caller可求delta压缩: numeric values使用;ords直接写原始值。
DirectMonotonicWriter
递增,每个block写与expected(num * 平均变化量)的delta,占每个block的bitsPerValue。