日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

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

系統(tǒng) 1682 0

?

上接《 索引創(chuàng)建(2):DocumentWriter處理流程一

?

1.3.2 第二車間——DocInverterPerField

?

DocInverterPerField 負責對DocFieldProcessorPerThread對象的Fieldable[]數(shù)組的內(nèi)容建立倒排索引,也就是處理同名字的所有Field。但實際上這個類主要解決的是前期工作,比如分詞,統(tǒng)計位置信息等。倒排索引結(jié)構(gòu)的核心的工作由 TermsHashPerField FreqProxTermsWriterPerField (第三車間 ) 來完成。這兩個類將在后面的專題中再提及。

?

DocInverterPerField 核心方法是processFields(Fieldable[] fields)。它負責這幾個方面的工作:

(1)將field的value值切分成一個個term

(2)調(diào)用FieldInvertState類來存儲和統(tǒng)計當前field的所有term出現(xiàn)的位置position和offset信息,并計算該field的boost分值,為所有相同名字的fields的boost與文檔的boost的乘積。

(3) 調(diào)用 TermsHashPerField和 FreqProxTermsWriterPerField 每個term 加入倒排索引結(jié)構(gòu)。

?

?

Part I src code:

     public void processFields(final Fieldable[] fields, final int count)  {

    //FieldInvertState類的職責就是跟蹤將要加入索引(index)結(jié)構(gòu)中的詞語的位置(position/offset)
   ?//首先初始化FieldInvertState類的數(shù)據(jù)域。
    fieldState.reset(docState.doc.getBoost());
    
    //確定Field允許的最大詞語數(shù)量10000
    final int maxFieldLength = docState.maxFieldLength;

    //確定fields數(shù)組是否需要索引(isIndexed)
    //如果有一個field需要索引,則doInvert=true
    final boolean doInvert = consumer.start(fields, count);

    //取出fields[]中的取出當前field(這些field名字相同)
    for(int i=0;i<count;i++) {
        final Fieldable field = fields[i];
        //當前field需要索引且整個fields數(shù)組都需要檢索
        if (field.isIndexed() && doInvert) {
             
             //如果有多個同名的field,則將后面的field的value接到前面的field之后
             //即field[1]的第一個token的詞語位置要從field[0]開始算起。             
             if (fieldState.length > 0)
                  fieldState.position += docState.analyzer.getPositionIncrementGap(fieldInfo.name);
       

             //當前field不需要分詞
             if(!field.isTokenized()) {
                   ....
                   //則直接將整個field的值交給TermsHashPerField建立索引
                   consumer.start(field);
                   try {
                         consumer.add();
                         success = true;
                   } finally {
                   if (!success)
                       docState.docWriter.setAborting();
                   ....
              }else {//當前field需要分詞
                   final TokenStream stream;
                   //確定field在創(chuàng)建的時候是否已經(jīng)有了一個內(nèi)容詞語的tokenStream
                   final TokenStream streamValue = field.tokenStreamValue();
                   //field已經(jīng)有分好詞的tokenStream
                   if (streamValue != null) 
                        stream = streamValue;
                   else {//field沒有分好詞的tokenStream
                       final Reader reader;
                       //確定field的內(nèi)容是否是Reader類型
                       final Reader readerValue = field.readerValue();
                       //field內(nèi)容是Reader類型
                       if (readerValue != null)
                           reader = readerValue;
                       else {
                           //filed內(nèi)容不是Reader類型,則判斷是否是String
                           String stringValue = field.stringValue();
                           if (stringValue == null)
                               throw new IllegalArgumentException("field must have either TokenStream, String or Reader value");
                           perThread.stringReader.init(stringValue);
                           reader = perThread.stringReader;
                       }
                    //用分析器處理當前field(進行分詞和過濾),并加入到postingTable
                    stream = docState.analyzer.reusableTokenStream(fieldInfo.name, reader);
                  }


               ......第二部分源碼.....


        }//end if(需要索引)
        
        consumer.finish();
        endConsumer.finish();

    }//end for(每一個field)
}//end processFields
  

?

第一部分源碼的主要作用就是根據(jù)每一個需要檢索的field的不同操作方式進行處理。如果field不需要分詞,則直接將filed交給 TermsHashPerField建立索引結(jié)構(gòu)(code line: 30, 32)。如果field需要分詞,則首先判斷field的value是不是Reader類型(分析器Analyzer只接受Reader類型數(shù)據(jù)),不是則將value字符串值包裝成Reader類型(code line:57)。再讓Analyzer分詞得到TokenStream stream(code line : 61)。然后將stream中的每一個token交給 TermsHashPerField建立索引結(jié)構(gòu)(請看后面的第二部分代碼)。

?

我們用上一節(jié)的doc1的例子來查看這個stream的結(jié)果,其中doc1通過上一節(jié)加工成了DocFieldProcessorPerThread fields[]數(shù)組。而fields[0]就是指doc1中名字為cotent的field集合,這個集合有兩個content field。

?

content field 1: The lucene is a good IR. I hope I can lean.

stream 的結(jié)果顯示(已經(jīng)去停用詞了):

token?
? type?
offset
pos
lucene <ALPHANUM> (4,10)
2
good <ALPHANUM> (16,20)
3
ir <ALPHANUM> (21,23) 1
i <ALPHANUM> (25,26)
1
hope <ALPHANUM> (27,31) 1
i <ALPHANUM> (32,33)
1
can <ALPHANUM> (34,37)
1
lean <ALPHANUM> (38,42) 1

?

content field 2: Lucene 3.0 like a teacher. I love it.

stream 的結(jié)果顯示(已經(jīng)去停用詞了):

token? type
offset pos
lucene <ALPHANUM> (0,7) 1
3.0 <NUM> (8,11) 1
like <ALPHANUM> (12,16) 1
teacher <ALPHANUM> (19,26) 2
i <ALPHANUM> (28,29) 1
love <ALPHANUM> (30,34) 1

?


Part II src code:

    ...... 第一部分.....

// 將TokenStream內(nèi)部指針指向第一個token
stream.reset();

final int startLength = fieldState.length;

try {
   //記錄當前token首字母在文本中的位置,如果token是TokenStream中的第一個詞語,則offsetEnd=-1
   int offsetEnd = fieldState.offset-1;
   //獲取分詞后tokenStream的每一個token的全部信息
   boolean hasMoreTokens = stream.incrementToken();

    fieldState.attributeSource = stream;
   //得到當前token的OffsetAttribute屬性信息
   OffsetAttribute offsetAttribute =fieldState.attributeSource.addAttribute(OffsetAttribute.class);
   //得到當前token的PositionIncrementAttribute屬性信息
   PositionIncrementAttribute posIncrAttribute =fieldState.attributeSource.addAttribute(PositionIncrementAttribute.class);
   //利用TermsHashPerField將每一個token加入倒排索引結(jié)構(gòu)
   consumer.start(field);      
   for(;;) {
      //tokenStream結(jié)束
      if (!hasMoreTokens) break;
      
      //得到當前token的positionIncreament屬性
      final int posIncr = posIncrAttribute.getPositionIncrement();     
      //此時fieldState.position表示當前token所在原文本中的詞語位置,即token前面有多少個詞語
     ?fieldState.position += posIncr;
      //positionIncreament屬性計算的時候就是相隔的詞語數(shù)量+1,因此統(tǒng)計當前token前面的詞語數(shù)量的時候,要減1
      if (fieldState.position > 0) {
                fieldState.position--;
      }
      
      if (posIncr == 0)
                fieldState.numOverlap++;
      try {
          //利用TermsHashPerField將當前token以及fieldState當前所記錄的位置信息一并加入進倒排索引結(jié)構(gòu)中           
          consumer.add();
           success = true;
      } finally {
           if (!success)
               docState.docWriter.setAborting();
      }
      //準備記錄下一個token,因此將當前token算入進去
      fieldState.position++;
      //記錄當前token的尾字母在原文本中所在的位置
     ?offsetEnd = fieldState.offset + offsetAttribute.endOffset();       
      //fieldState.length記錄了當前已經(jīng)處理了的token數(shù)量,如果超過了允許的最大數(shù)量,則后面的詞語將被丟棄,不再加入到索引中。
      if (++fieldState.length >= maxFieldLength) {
                if (docState.infoStream != null)
                  docState.infoStream.println("maxFieldLength " +maxFieldLength+ " reached for field " + fieldInfo.name + ", ignoring following tokens");
                break;
       }

      //取下一個token
      hasMoreTokens = stream.incrementToken();
    }
    stream.end();
            
 } finally {
     stream.close();
 }
  
?

第二部分源碼的主要作用就是循環(huán)得到stream(第一部分代碼)中的每一個token(code line: 21),計算token在原始文本中的位置(code line: 28,31),并保存在fieldState.position和fieldState.offset中。同時token和fieldState中的統(tǒng)計信息交給 TermsHashPerField建立倒排索引結(jié)構(gòu)(code line: 38)。

?

總結(jié) ,下圖 展示了 DocInverterPerField 的作用。它會把不需要分詞的field以紅色方框的結(jié)構(gòu)(field value)傳給 TermsHashPerField FreqProxTermsWriterPerField 來建立索引。而把需要分詞的content field變成一個個藍色方框的結(jié)構(gòu)(token && position)來建立索引,接下來就是對token建立倒排索引的過程了。請參見《 索引創(chuàng)建(4):DocumentWriter 處理流程三 》。

?

注意,上圖藍色方框的箭頭并不是指 DocInverterPerField會把他們建立成鏈表結(jié)構(gòu)。事實上,這些箭頭只是為了表明一個個token依次被 TermsHashPerField加入索引結(jié)構(gòu)的。另外,相同名字的field中的詞語會依次處理,就如同上面fields[0]和fields[1]。

?

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


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

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

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

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 丁青县| 隆昌县| 定兴县| 孟州市| 阳谷县| 仁化县| 云南省| 隆安县| 宁陵县| 通化县| 广平县| 西充县| 乌拉特前旗| 加查县| 玉山县| 宿迁市| 房产| 荣成市| 台东市| 镇坪县| 永春县| 东丽区| 四会市| 花莲市| 棋牌| 成武县| 大荔县| 乌海市| 东乡县| 文山县| 集贤县| 武义县| 桂阳县| 遂溪县| 淮滨县| 时尚| 资兴市| 宜兴市| 陵川县| 本溪市| 藁城市|