Lucene-分詞器(2)

Lucene-分詞器API

 1.  org.apache.lucene.analysi.Analyzer

    分析器,分詞器組件的核心API,它的職責:構建真正對文本進行分詞處理的TokenStream(分詞處理器)。通過調用它的如下兩個方法,得到輸入文本的分詞處理器

    public final TokenStream tokenStream(String fieldName, Reader reader)

    public final TokenStream tokenStream(String fieldName, String text)

 2.TokenStreamComponents  createComponents(String fieldName)

          Analizer中唯一的抽象方法,擴展點。通過提供該方法的實現來實現自己的Analyzer。

          返回值爲 TokenStreamComponents  分詞處理器組件。

       參數說明:fieldName,如果我們需要爲不同的字段創建不同的分詞處理器組件,則可根據這個參數來判斷。否則,就用不到這個參數。

3.TokenStreamComponents

     分詞處理器組件:這個類中封裝有供外部使用的TokenStream分詞處理器。提供了對source()sink(供外部使用分詞處理器)兩個屬性的訪問方法。

4.org.apache.lucene.analysis.TokenStream

     分詞器處理項,負責對輸入文本完成分詞、處理。

    TokenStream 的兩類子類

    Tokenizer:分詞器,輸入是Reader字符流的TokenStream,完成從流中分出分項
    TokenFilter:分項過濾器,它的輸入是另一個TokenStream,完成對從上一個TokenStream中流出的token的特殊處理。
    TokenStream 繼承了 AttributeSource

    Attribute 屬性 ,TokenAttribute  分項屬性(分項信息),如 分項的詞、詞的索引位置等等。這些屬性通過不同的Tokenizer        /TokenFilter處理統計得出。不同的Tokenizer/TokenFilter組合,就會有不同的分項信息。

5.AttributeSource使用規則說明

1、某個TokenStream實現中如要存儲分項屬性,通過AttributeSource的兩個add方法之一,往AttributeSource中加入屬性對象。
<T extends Attribute> T addAttribute(Class<T> attClass)
該方法要求傳人你需要添加的屬性的接口類(繼承Attribute),返回對應的實現類實例給你。從接口到實例,這就是爲什麼需要AttributeFactory的原因。
void addAttributeImpl(AttributeImpl att)
2、加入的每一個Attribute實現類在AttributeSource中只會有一個實例,分詞過程中,分項是重複使用這一實例來存放分項的屬性信息。重複調用add方法添加它返回已存儲的實例對象。
3、要獲取分項的某屬性信息,則需持有某屬性的實例對象,通過addAttribute方法或getAttribure方法獲得Attribute對象,再調用實例的方法來獲取、設置值
4、在TokenStream中,我們用自己實現的Attribute,默認的工廠。當我們調用這個add方法時,它怎麼知道實現類是哪個?這裏有一定規則要遵守:
     1)、自定義的屬性接口 MyAttribute  繼承 Attribute
     2)、自定義的屬性實現類必須繼承 Attribute,實現自定義的接口MyAttribute
     3)、自定義的屬性實現類必須提供無參構造方法
     4)、爲了讓默認工廠能根據自定義接口找到實現類,實現類名需爲 接口名+Impl 。


6.TokenStream 的使用步驟。

1、從tokenStream獲得你想要獲得分項屬性對象(信息是存放在屬性對象中的)
2、調用 tokenStream 的 reset() 方法,進行重置。因爲tokenStream是重複利用的。
3、循環調用tokenStream的incrementToken(),一個一個分詞,直到它返回false
4、在循環中取出每個分項你想要的屬性值。
5、調用tokenStream的end(),執行任務需要的結束處理。
6、調用tokenStream的close()方法,釋放佔有的資源。

7.Lucene提供的分詞器

1)<!-- Lucene提供的中文分詞器模塊,lucene-analyzers-smartcn -->
<dependency>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-analyzers-smartcn</artifactId>
    <version>7.3.0</version>
</dependency>

2)IKAnalyzer

開源、輕量級的中文分詞器,應用比較多,最先是作爲lucene上使用而開發,後來發展爲獨立的分詞組件。

只提供到Lucene 4.0版本的支持。我們在4.0以後版本Lucene中使用就需要簡單集成一下。
<!-- ikanalyzer 中文分詞器  -->
<dependency>
    <groupId>com.janeluo</groupId>
    <artifactId>ikanalyzer</artifactId>
    <version>2012_u6</version>
    <exclusions>
    <exclusion>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-core</artifactId>
    </exclusion>
    <exclusion>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-queryparser</artifactId>
    </exclusion>
    <exclusion>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-analyzers-common</artifactId>
    </exclusion>
    </exclusions>
</dependency>

<!--  lucene-queryparser 查詢分析器模塊 -->
<dependency>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-queryparser</artifactId>
    <version>7.3.0</version>
</dependency>

8.擴展 IKAnalyzer的停用詞

Ik中默認的停用詞很少,可擴展它。可從網址: https://github.com/cseryp/stopwords,下載一份比較全的停用詞。
Ik中停用詞的擴展步驟:
1、在類目錄下創建IK的配置文件:IKAnalyzer.cfg.xml
2、在配置文件中增加配置擴展停用詞文件的節點:
 <entry key=“ext_stopwords”>my_ext_stopword.dic</entry>  
   如有多個,以“;”間隔
3、在類目錄下創建我們的擴展停用詞文件 my_ext_stopword.dic
4、編輯該文件加入停用詞,一行一個
注:文件編碼一定是UTF-8

    

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">  
<properties>  
	<comment>IK Analyzer 擴展配置</comment>
	<!--在這裏配置自己的擴展字典 -->
	<entry key="ext_dict">ext.dic</entry> 
	
	<!--在這裏配置自己的擴展停止詞字典-->
	<entry key="ext_stopwords">my_ext_stopword.dic</entry>
</properties>

自定義分分詞器實現

package com.dongsheng.lucene.dslucene.lucene;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.util.Attribute;
import org.apache.lucene.util.AttributeImpl;
import org.apache.lucene.util.AttributeReflector;

import java.io.IOException;

/***
 *@author dongsheng
 *@date 2020/2/19 16:47
 *@version 1.0.0
 *@Description
 */
public class MyWhitespaceAnalyzer extends Analyzer {

    @Override
    protected TokenStreamComponents createComponents(String fieldName) {
        Tokenizer source = new MyWhitespaceTokenizer();
        TokenStream filter = new MyLowerCaseTokenFilter(source);
        return new TokenStreamComponents(source, filter);
    }

    
    //自定義分詞器讀取
    static class MyWhitespaceTokenizer extends Tokenizer {
        // 需要記錄的屬性
        // 詞
        MyCharAttribute charAttr = this.addAttribute(MyCharAttribute.class);

        char[] buffer = new char[255];
        int length = 0;
        int c;

        @Override
        public boolean incrementToken() throws IOException {
            // 清除所有的詞元屬性
            clearAttributes();
            length = 0;
            while (true) {
                c = this.input.read();

                if (c == -1) {
                    if (length > 0) {
                        // 複製到charAttr
                        this.charAttr.setChars(buffer, length);
                        return true;
                    } else {
                        return false;
                    }
                }

                if (Character.isWhitespace(c)) {
                    if (length > 0) {
                        // 複製到charAttr
                        this.charAttr.setChars(buffer, length);
                        return true;
                    }
                }

                buffer[length++] = (char) c;
            }
        }

    }

    //自定義分詞項
    public static class MyLowerCaseTokenFilter extends TokenFilter {
        public MyLowerCaseTokenFilter(TokenStream input) {
            super(input);
        }
        MyCharAttribute charAttr = this.addAttribute(MyCharAttribute.class);

        @Override
        public boolean incrementToken() throws IOException {
            boolean res = this.input.incrementToken();
            if (res) {
                char[] chars = charAttr.getChars();
                int length = charAttr.getLength();
                if (length > 0) {
                    for (int i = 0; i < length; i++) {
                        chars[i] = Character.toLowerCase(chars[i]);
                    }
                }
            }
            return res;
        }

    }

    public static interface MyCharAttribute extends Attribute {
        void setChars(char[] buffer, int length);

        char[] getChars();

        int getLength();

        String getString();
    }

    public static class MyCharAttributeImpl extends AttributeImpl
            implements MyCharAttribute {
        private char[] chatTerm = new char[255];
        private int length = 0;

        @Override
        public void setChars(char[] buffer, int length) {
            this.length = length;
            if (length > 0) {
                System.arraycopy(buffer, 0, this.chatTerm, 0, length);
            }
        }

        public char[] getChars() {
            return this.chatTerm;
        }

        public int getLength() {
            return this.length;
        }

        @Override
        public String getString() {
            if (this.length > 0) {
                return new String(this.chatTerm, 0, length);
            }
            return null;
        }

        @Override
        public void clear() {
            this.length = 0;
        }

        @Override
        public void reflectWith(AttributeReflector reflector) {

        }

        @Override
        public void copyTo(AttributeImpl target) {

        }
    }

    public static void main(String[] args) {
      //中間空格的代替|
        String text = "An AttributeSource contains a list of different AttributeImpls, and methods to add and get them. ";

        try (Analyzer ana = new MyWhitespaceAnalyzer();
             TokenStream ts = ana.tokenStream("test", text);) {
            MyCharAttribute ca = ts.getAttribute(MyCharAttribute.class);
            ts.reset();
            while (ts.incrementToken()) {
                System.out.print(ca.getString() + "|");
            }
            ts.end();
            System.out.println();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

結果輸出:

an|attributesource|contains|a|list|of|different|attributeimpls,|and|methods|to|add|and|get|them.| 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章