黄色网页视频 I 影音先锋日日狠狠久久 I 秋霞午夜毛片 I 秋霞一二三区 I 国产成人片无码视频 I 国产 精品 自在自线 I av免费观看网站 I 日本精品久久久久中文字幕5 I 91看视频 I 看全色黄大色黄女片18 I 精品不卡一区 I 亚洲最新精品 I 欧美 激情 在线 I 人妻少妇精品久久 I 国产99视频精品免费专区 I 欧美影院 I 欧美精品在欧美一区二区少妇 I av大片网站 I 国产精品黄色片 I 888久久 I 狠狠干最新 I 看看黄色一级片 I 黄色精品久久 I 三级av在线 I 69色综合 I 国产日韩欧美91 I 亚洲精品偷拍 I 激情小说亚洲图片 I 久久国产视频精品 I 国产综合精品一区二区三区 I 色婷婷国产 I 最新成人av在线 I 国产私拍精品 I 日韩成人影音 I 日日夜夜天天综合

【Lucene3.0 初窺】索引創(chuàng)建(2):DocumentWrite

系統(tǒng) 1938 0

上接 《索引創(chuàng)建(1): IndexWriter索引器》

?

1.3?? 索引創(chuàng)建過(guò)程

?

DocumentsWriter是由IndexWriter調(diào)用來(lái)負(fù)責(zé)對(duì)多個(gè)document建立索引的核心類(lèi),但整個(gè)索引過(guò)程并不是由一個(gè)對(duì)象來(lái)完成的。而是有一系列的對(duì)象組成的處理鏈(IndexingChain)來(lái)完成的(這個(gè)過(guò)程就像流水線生產(chǎn)汽車(chē))。 下面是DocumentWriter開(kāi)始建立索引的源代碼。

    //由IndexWriter調(diào)用的方法
boolean addDocument(Document doc, Analyzer analyzer){
      return updateDocument(doc, analyzer, null);
}

boolean updateDocument(Document doc, Analyzer analyzer, Term delTerm){
    final DocumentsWriterThreadState state = getThreadState(doc, delTerm);
    final DocState docState = state.docState;
    docState.doc = doc;
    docState.analyzer = analyzer;
    boolean success = false;
    try {
          //調(diào)用處理鏈的源頭DocFieldProcessorPerThread開(kāi)始對(duì)Document對(duì)象建立索引結(jié)構(gòu)
          final DocWriter perDoc = state.consumer.processDocument();

          finishDocument(state, perDoc);
          success = true;
     } 
      .......
} 

  

?

1.3.1? 第一車(chē)間——DocFieldProcessorPerThread

?

DocFieldProcessorPerThread類(lèi)是索引創(chuàng)建處理鏈的第一步。其基本任務(wù):將document對(duì)象原料中所有相同名字的field合并成一個(gè) DocFieldProcessorPerThread對(duì)象 ,然后更新FieldInfo信息,最后對(duì)不同名字的Field構(gòu)成一個(gè) DocFieldProcessorPerThread[]對(duì)象數(shù)組。這個(gè)數(shù)組就是下一個(gè)車(chē)間DocInverterPerField要加工的原料了。

?

DocFieldProcessorPerThread類(lèi)完成第一步處理的核心方法就是processDocument()。在介紹這個(gè)方法之前,我們先來(lái)看看兩個(gè)重要的類(lèi)DocFieldProcessorPerField和FieldInfo

?

(1) DocFieldProcessorPerField 類(lèi)是一個(gè)合并了相同名字Field的類(lèi)(可見(jiàn)下圖黃色區(qū)域)。它是后面 DocInverterPerField 要處理的單位原料。源碼如下:

    final class DocFieldProcessorPerField {

      final DocFieldConsumerPerField consumer;
     //記錄field的名字、是否要檢索,是否要存儲(chǔ)等信息
     final FieldInfo fieldInfo;
     //指向下一個(gè)DocFieldProcessorPerField的指針
     DocFieldProcessorPerField next;
     int lastGen = -1;
     //包含相同名字的field的數(shù)量
     int fieldCount;
     //包含的相同名字的field
     Fieldable[] fields = new Fieldable[1];

    public DocFieldProcessorPerField(final DocFieldProcessorPerThread perThread, final FieldInfo fieldInfo) {
         this.consumer = perThread.consumer.addField(fieldInfo);
         this.fieldInfo = fieldInfo;
    }

    public void abort() {
         consumer.abort();
    }
}

  
?

(2) FieldInfo 類(lèi)并不是指一個(gè)Field的全部信息,而是相同名字的Field合并之后的信息。合并過(guò)程重要通過(guò)update()方法將Field的其他不同屬性統(tǒng)一起來(lái)(可見(jiàn)下圖藍(lán)色區(qū)域)。部分源碼如下:

    final class FieldInfo {
    //Field的相同名字
    String name;
    //是否要索引
    boolean isIndexed;
    //編號(hào)
    int number;
    ....
    //構(gòu)造器
    FieldInfo(..){
    ...
    } 
    //FieldInfo更新的準(zhǔn)則是:
    //原來(lái)的Field和新的Field有一個(gè)要索引(isIndexed=true),則更新后的也索引。
    //如果新的Field不需要索引,則其他操作指標(biāo)不變
    //如果新的Field需要索引,則只要有一個(gè)操作指標(biāo)為真,就更新后的也為真
    void update(...){
    ...
    }
}
  
?

下面我們重點(diǎn)看看processDocument()方法是如何把Document對(duì)象加工成DocFieldProcessorPerThread[]數(shù)組的。

    final class DocFieldProcessorPerThread extends DocConsumerPerThread {
//存儲(chǔ)最后處理的結(jié)構(gòu):DocFieldProcessorPerField[]數(shù)組
DocFieldProcessorPerField[] fields = new DocFieldProcessorPerField[1];
int fieldCount;

//以Field名字作為關(guān)鍵字的DocFieldProcessorPerField哈希表結(jié)構(gòu)
DocFieldProcessorPerField[] fieldHash = new DocFieldProcessorPerField[2];


/**
 * 擴(kuò)大DocFieldProcessorPerField的Hash表容量
 * 每一次擴(kuò)大到原來(lái)容量的2倍,并且將原來(lái)存儲(chǔ)的DocFieldProcessorPerField對(duì)象順序移動(dòng)到Hash的最大位置處
 * 比如:原來(lái)的容量為2,擴(kuò)大之后的容量為4,將fieldHash[1]->fieldHash[3],fieldHash[0]->fieldHash[2]
 */
private void rehash() {
....
}

/**
 *第一加工車(chē)間處理核心流程
 */
public DocumentsWriter.DocWriter processDocument() {
    //初始化各項(xiàng)數(shù)據(jù)
    consumer.startDocument();
    fieldsWriter.startDocument();

    //要處理的document對(duì)象
    final Document doc = docState.doc;
    assert docFieldProcessor.docWriter.writer.testPoint("DocumentsWriter.ThreadState.init start");

    //記錄處理過(guò)程中生成的DocFieldProcessorPerField的數(shù)量
    fieldCount = 0;

    //當(dāng)前的DocFieldProcessorPerField
    final int thisFieldGen = fieldGen++;

    final List<Fieldable> docFields = doc.getFields();
    final int numDocFields = docFields.size();

    for(int i=0;i<numDocFields;i++) {
        //得到doc的每個(gè)Field
        Fieldable field = docFields.get(i);
        final String fieldName = field.name();

        //以Field的名字為key,定位到fieldHash[]的位置號(hào)hashPos
        final int hashPos = fieldName.hashCode() & hashMask;
        //確定fieldHash[]上指定的hashPos位置是否已經(jīng)有了數(shù)據(jù),也就是是否產(chǎn)生沖突
        DocFieldProcessorPerField fp = fieldHash[hashPos];
        //如果Field的名字不同,但fieldHash[]的hashPos位置產(chǎn)生了Hash沖突,則采用Hash鏈表結(jié)構(gòu)加入到?jīng)_突位置上的鏈表末尾。
        while(fp != null && !fp.fieldInfo.name.equals(fieldName))
             fp = fp.next;
        //如果fieldHash[]的hashPos位置上沒(méi)有數(shù)據(jù),則將新的Field包裝成DocFieldProcessorPerField對(duì)象加入到Hash表中
        if (fp == null) {
            FieldInfo fi = fieldInfos.add(fieldName, field.isIndexed(), field.isTermVectorStored(),field.isStorePositionWithTermVector(), field.isStoreOffsetWithTermVector(),field.getOmitNorms(), false, field.getOmitTermFreqAndPositions());

            fp = new DocFieldProcessorPerField(this, fi);
            fp.next = fieldHash[hashPos];
            fieldHash[hashPos] = fp;
            totalFieldCount++;
            //如果DocFieldProcessorPerField的Hash表存儲(chǔ)總數(shù)量已經(jīng)嘗過(guò)了總?cè)萘康?/2,則擴(kuò)大容量
            if (totalFieldCount >= fieldHash.length/2)
                rehash();
         }else{ //如果產(chǎn)生了沖突,并且沖突位置上的Field的名字與要加入的Field名字相同,則更新沖突位置上的FieldInfo
             fp.fieldInfo.update(field.isIndexed(), field.isTermVectorStored(),
                            field.isStorePositionWithTermVector(), field.isStoreOffsetWithTermVector(),
                            field.getOmitNorms(), false, field.getOmitTermFreqAndPositions());
         }
      
          //如果具有相同名字的Field,則將同名的Field合并到同一個(gè)DocFieldProcessorPerField中的Fieldable[]中
          if (thisFieldGen != fp.lastGen) {
               fp.fieldCount = 0;
               //如果fields[]已經(jīng)存滿(mǎn),則擴(kuò)大2倍的fields[]的容量
               if (fieldCount == fields.length) {
               final int newSize = fields.length*2;
               DocFieldProcessorPerField newArray[] = new DocFieldProcessorPerField[newSize];
               System.arraycopy(fields, 0, newArray, 0, fieldCount);
               fields = newArray;
           }
        
           fields[fieldCount++] = fp;
           fp.lastGen = thisFieldGen;
        }
        //如果具有相同的Field名字,而DocFieldProcessorPerField中的Fieldable[]已經(jīng)存滿(mǎn),則擴(kuò)大2倍的此數(shù)組容量用于存放相同名字的Field
        if (fp.fieldCount == fp.fields.length) {
           Fieldable[] newArray = new Fieldable[fp.fields.length*2];
           System.arraycopy(fp.fields, 0, newArray, 0, fp.fieldCount);
           fp.fields = newArray;
        }
      
        fp.fields[fp.fieldCount++] = field;
        if (field.isStored()) {
            fieldsWriter.addField(field, fp.fieldInfo);
        }
   }
   //將fields數(shù)組按field名字排序
   quickSort(fields, 0, fieldCount-1);
   //調(diào)用下一加工車(chē)間DocInverterPerField對(duì)每個(gè)DocFieldProcessorPerField對(duì)象進(jìn)行處理
   for(int i=0;i<fieldCount;i++)
        fields[i].consumer.processFields(fields[i].fields, fields[i].fieldCount);

    .......
}
  
?

用個(gè)圖例來(lái)說(shuō)明一下DocFieldProcessorPerThread類(lèi)所做的工作。我們拿《 索引創(chuàng)建(1):IndexWriter索引器 》1.1節(jié)前期工作中的doc1來(lái)作為DocFieldProcessorPerThread的原料。

?

原料:Document doc1 (為了說(shuō)明相同F(xiàn)ield的合并工作,我們加了一個(gè)相同名字,值不同的content Field)

????? Field name ??????? Field value ? isIndex ? isStore
???????? name ??????????????? 1 ???? false ???? true
???????? path ????? e:\\content\\1.txt ???? false ???? true
??????? content The lucene is a good IR. I hope I can lean. ???? true ???? true
??????? content Lucene 3.0 like a teacher. I love it.
???? true ???? true

?

半成品: DocFieldProcessorPerField[] fields

注意,上圖中的DocFieldProcessorPerField的next域都指向了null。其實(shí),如果有Field1的名字name1與Field2的名字name2滿(mǎn)足? HashCode(name1)=HashCode(name2) && !name1.equals(name2) 的情況下。Field2所構(gòu)成的DocFieldProcessorPerField對(duì)象將加在Field1所構(gòu)成的DocFieldProcessorPerField對(duì)象的next鏈表后面。這種組織方法便于我們?cè)诤竺嬉v到的建立倒排索引的處理。

?

總結(jié): ? DocFieldProcessorPerThread 類(lèi)的作用就是把Document對(duì)象加工成 DocFieldProcessorPerField [] (上圖黃色區(qū)域) 。然后把每個(gè) DocField ProcessorPerThread .Fieldable[] (上圖紅色區(qū)域)

交給第二車(chē)間 DocInverterPerField processFields ( 《索引創(chuàng)建(3):DocmentWriter 處理流程二》 )方法來(lái)完成了。

?

【Lucene3.0 初窺】索引創(chuàng)建(2):DocumentWriter 處理流程一


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論