zoukankan      html  css  js  c++  java
  • docValues文件结构源码分析

    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。
  • 相关阅读:
    聚类分析理论之TwoSteps理论篇+实践篇【转载】
    游戏运营杂谈之——>怎么做一份数据日报【转载】
    名词解释CPC、CPM、CPA.......【转载】
    小白学数据分析>数据指标 累计用户数的使用
    Clementine的源节点学习【转载】
    在clementine基于两步聚类算法的次日留存分析探索【转载】
    百度联盟与Google AdSense的比较【转载】
    SAS:商业智能从BI走向BA
    11、位段
    3、SHELL控制语句
  • 原文地址:https://www.cnblogs.com/vsop/p/14569692.html
Copyright © 2011-2022 走看看