6、分詞(lucene筆記)

一、概述

1.1 分詞的基本過程

首先是TokenStream通過接收一個StringReader流將需要進行分詞的內容讀入進來,TokenStream有兩個子抽象類TokenizerTokenFilter。讀入的過程為:StringReader流經過Tokenizer接收輸入流并根據輸入流進行詞切分,然后會經過多個TokenFilterTokenStream進行過濾,例如去掉一些索引詞、替代同義索引詞等操作,最后生成TokenStream

1.2 Tokenizer

1

Tokenizer主要負責接收Reader字節流,將Reader進行分詞操作,即將一組數據劃分不同的語匯單元。KeyWordTokenizer是關鍵詞分詞,StandardTokenizer是標準分詞,CharTokenizer是字符分詞,WhitespaceTokenizer是空白分詞,LetterTokenizer是標點分詞,LowerCaseTokenizer是小寫分詞(將各個語匯單元轉換成小寫)。
這里我們說明一下WhitespaceTokenizerLetterTokenizer,比如有這樣一句內容:how are you I’m a teacher。那么前者會分成這樣:how、 are、 you、 I’m、 a、 teacher,而后者會分成:how、 are、 you、 I 、m、 a、 teacher

1.3 TokenFilter

2

TokenFilter類繼承于TokenStream,其輸入是另一個TokenStream,主要職責是對TokenStream進行過濾,例如去掉一些索引詞、替代同義索引詞等操作。上面給出各類過濾器,這里只是作為了解,后面再細說。

二、入門示例(工程lucene_analyzer01

AnalyzerUtils.java

package cn.itcast.util;
import java.io.IOException;
import java.io.StringReader;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
import org.apache.lucene.analysis.tokenattributes.TypeAttribute;

public class AnalyzerUtils {
    public static void displayToken(String str, Analyzer analyzer) {
        try {
            //首先我們使用分詞器analyzer將相關數據(這里比如是內容gcontent)進行分詞,這樣得到一個詞匯流
            //然后我們給這個流做一個標記,可以用來遍歷此流
            TokenStream stream = analyzer.tokenStream("content",new StringReader(str));//這就是一個詞匯流
            CharTermAttribute cta = stream.addAttribute(CharTermAttribute.class);//相當于一個標記,隨著流增加
            while (stream.incrementToken()) {
                System.out.print("[" + cta + "]");
            }
            System.out.println();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

測試:TestAnalyzer.java

@Test
public void test01(){
    Analyzer analyzer1 = new StandardAnalyzer(Version.LUCENE_35);//標準分詞器
    Analyzer analyzer2 = new StopAnalyzer(Version.LUCENE_35);//停用分詞器
    Analyzer analyzer3 = new SimpleAnalyzer(Version.LUCENE_35);//簡單分詞器
    Analyzer analyzer4 = new WhitespaceAnalyzer(Version.LUCENE_35);//空格分詞器
    
    String text = "this is my house,I am come form Xian,My email is "
            + "xxx@qq.com,and my qq is 154625554";
    AnalyzerUtils.displayToken(text, analyzer1);
    AnalyzerUtils.displayToken(text, analyzer2);
    AnalyzerUtils.displayToken(text, analyzer3);
    AnalyzerUtils.displayToken(text, analyzer4);
}

說明:可以看到我們構造一個TokenStream 流,此流接收兩個參數,第一個參數表示要進行分詞的域(這里隨便),而第二個參數就是一個StringReader流。而CharTermAttribute 相當于流中的一個標記,隨著流而增減,用戶我們遍歷流中各個語匯單元。而相關的分詞器我們通過參數傳入進去。分詞結果為:

3

從結果我們可以看到各個分詞器的作用和區別。下面我們再測試一下中文分詞:

@Test
public void test02(){
    //對中文分詞不適用
    Analyzer analyzer1 = new StandardAnalyzer(Version.LUCENE_35);//標準分詞器
    Analyzer analyzer2 = new StopAnalyzer(Version.LUCENE_35);//停用分詞器
    Analyzer analyzer3 = new SimpleAnalyzer(Version.LUCENE_35);//簡單分詞器
    Analyzer analyzer4 = new WhitespaceAnalyzer(Version.LUCENE_35);//空格分詞器
    
    String text = "西安市雁塔區";
    AnalyzerUtils.displayToken(text, analyzer1);
    AnalyzerUtils.displayToken(text, analyzer2);
    AnalyzerUtils.displayToken(text, analyzer3);
    AnalyzerUtils.displayToken(text, analyzer4);
}

測試結果為:


4

可見一般的分詞器對中文分詞作用不大。

下面看語匯單元的一些屬性:
AnalyzerUtils.java

public static void displayAllTokenInfo(String str, Analyzer analyzer){
    try {
        TokenStream stream = analyzer.tokenStream("content", new StringReader(str));
        PositionIncrementAttribute pia = stream.addAttribute(PositionIncrementAttribute.class);
        OffsetAttribute oa = stream.addAttribute(OffsetAttribute.class);
        CharTermAttribute cta = stream.addAttribute(CharTermAttribute.class);
        TypeAttribute ta = stream.addAttribute(TypeAttribute.class);

        while (stream.incrementToken()) {
            System.out.print("位置增量: " + pia.getPositionIncrement());//詞與詞之間的空格
            System.out.print(",單詞: " + cta + "[" + oa.startOffset() + "," + oa.endOffset() + "]");
            System.out.print(",類型: " + ta.type()) ;
            System.out.println();
        }
        System.out.println();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

測試

@Test
public void test03(){
    //對中文分詞不適用
    Analyzer analyzer1 = new StandardAnalyzer(Version.LUCENE_35);//標準分詞器
    Analyzer analyzer2 = new StopAnalyzer(Version.LUCENE_35);//停用分詞器
    Analyzer analyzer3 = new SimpleAnalyzer(Version.LUCENE_35);//簡單分詞器
    Analyzer analyzer4 = new WhitespaceAnalyzer(Version.LUCENE_35);//空格分詞器
    
    String text = "how are you thank you";
    System.out.println("************標準分詞器***************");
    AnalyzerUtils.displayAllTokenInfo(text, analyzer1);
    System.out.println("************停用分詞器***************");
    AnalyzerUtils.displayAllTokenInfo(text, analyzer2);
    System.out.println("************簡單分詞器***************");
    AnalyzerUtils.displayAllTokenInfo(text, analyzer3);
    System.out.println("*************空格分詞器**************");
    AnalyzerUtils.displayAllTokenInfo(text, analyzer4);
}

說明:

  • 語匯單元類型TypeAttribute:語匯單元的類型,一般有wordALPHANUM兩種類型。
  • 語匯單元偏移量OffsetAttribute:就是起始字符和終止字符之間的偏移量。這里我們舉例說明,比如對how are you thank you進行分詞,那么各個語匯單元之間的偏移量為
    5
  • 語匯單元位置增量PositionIncrementAttribute:位置增量就是語匯單元之間的距離,比如上面的分詞如果不將某些語匯濾除,那么各個語匯單元之間的位置增量都是1,但是如果有些單元被濾掉,比如are關鍵詞,那么howyou之間的位置增量則為2。我們看測試結果為:
    6
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容