Lucene 自定義分詞器


 

本文主要介紹Lucene的常用概念,並自定義一個分詞器

1 環境介紹

  系統:win10

  lucene版本:7.3.0   https://lucene.apache.org/

  jdk:1.8

2 lucene 簡介

   lucene是最受歡迎的java開源全文搜索引擎開發工具包,提供了完整的查詢引擎和索引引擎,是Apache的子項目。在應用中為數據庫中的數據提供全文檢索實現

   也可以開發獨立的搜索引擎服務,系統。

   架構圖如下:

上層application層,左邊 為lucene提供數據收集,右邊為用戶提供搜索的入口

下層lucene,為數據提供索引的存儲,索引的查詢等功能

3 分詞器

    分析器(org.apache.lucene.analysis.Analyzer),分詞器組件的核心api ,用來構建真正的對文本進行分詞處理的TokenStrem (分詞處理器),在Analyzer 這個類中我們看到,有唯一的一個可以擴展的抽象方法

     

   我們在擴展自己的analyzer的時候 要重載這個方法,改方法的參數fieldName表示字段名。不同的字段有不同的處理方式,根據字段名來區分。

   TokenStreamComponents 是一個內部類,提供了兩個構造方法

     

    

 

   TokenStream 

    從上面的構造方法的參數中,我們可以看到,我們至少要提供一個Tokenizer 參數。那現在看看Tokenizer 和TokenStream 這兩個類。TokenStream,負責對輸入的文本進行分詞和處理,分詞分出的每一項叫token 

    實際上TokenStream 有兩種類型的子類分別用於分詞和處理 。 一類是 Tokenizer分詞器,完成從輸入的reader字符流中分出分項,  還有一類是 TokenFilter,分項過濾器,對分出的分項進行特性處理。

    TokenFilter是采用的裝飾器模式。如果我們需要對分詞進行各種處理,我們只需要按照我們的處理順序一層層包裹即可。

    在TokenStrem中有個抽象方法

    

     在我們實現自己的分詞器的時候要實現這個方法,來告訴我們自己的分詞規則和處理規則。返回值為false的時候表示分詞結束。

 

    AttributeSource

    TokenStream 繼承AttributeSource. 該方法用來存放Attribute 並且提供了對應的設置和取值方法。那Attribute是用來干什么的呢?

    在我們用Tokenizer 和TokenStream 對分詞進行了分項,並且對每個分項進行了了處理了之后,每個分項都會產生相應的信息,比如這個分項的文本是什么,位置是多少。這些都是要存儲起來的,那這些信息就是

    存儲在Attribute中的,AttributeFactory是用來創建attribute的工廠方法。不需要我們去創建。

    

    TokenStream的使用步驟:

    1 從tokenStream獲得你想要的分項屬性對象(attribute)用來存放分項信息。

    2 調用tokenStream的reset方法,進行重置,因為tokenStream是重復利用的。

    3 循環調用tokenStream的increamentToken方法,一個個分項,知道返回false

    4 在循環中取出你每個分項想要的屬性

    5  調用tokenStream的end方法,接受處理。

    5  調用tokenStream的close方法,釋放資源。

 

4 實現自己的分詞器

   4.1定義自己的分詞屬性

**
* 每個分詞的屬性
*/
public interface MyCharAttribute extends Attribute {
/**
* 賦值
* @param buffer 要被復制的數組
* @param length 復制的長度
*/
void setChars(char[] buffer, int length);

/**
* 獲取分詞數組
* @return
*/
char[] getChars();

/**
* 獲取分詞長度
* @return
*/
int getLength();

/**
* 獲取分詞的字符串
* @return
*/
String getString();
}

   4.2 實現上面抽象方法

       主要命名規則必須是 xxxImpl,lucence內部是以字符串拼接的形式去實現的

**
* 命名規則必須是 xxxImpl
*/
public 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, chatTerm, 0, length);
}
}

@Override
public char[] getChars() {
return chatTerm;
}

@Override
public int getLength() {
return length;
}

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

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

@Override
public void reflectWith(AttributeReflector attributeReflector) {

}

@Override
public void copyTo(AttributeImpl attribute) {

}
}

  4.3 實現自己的分詞器

/**
* 定義如何分詞
*/
public class MyTokenizer extends Tokenizer {

//里面是通過工廠方法 得到實例
MyCharAttribute attribute = this.addAttribute(MyCharAttribute.class);

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

/**
* 判斷是否有需要分詞的項 每次讀取一個單詞
* 如果有 會把這個分出來的詞 設置到MyCharAttribute中
*/
@Override
public boolean incrementToken() throws IOException {
// 清除所有的詞項屬性
clearAttributes();
length = 0;
while (true) {
//這個input 就是要解析的文本流
c = input.read();
//是否到末尾
if (c == -1) {
if (length > 0) {
// 復制到charAttr
attribute.setChars(buffer, length);
return true;
} else {
return false;
}
}

//是否是空格 英文單詞之間通過空格區分
if (Character.isWhitespace(c)) {
if (length > 0) {
// 復制到charAttr
attribute.setChars(buffer, length);
return true;
}
}

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

   4.4 定義分詞處理器

**
* 分詞處理器 這里是全部轉小寫
*/
public class MyTokenFilter extends TokenFilter {

protected MyTokenFilter(TokenStream input) {
super(input);
}

MyCharAttribute charAttr = this.addAttribute(MyCharAttribute.class);

@Override
public boolean incrementToken() throws IOException {
boolean res = 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;
}
}

 4.5 使用自定義分詞器

public class MyAnalyzer extends Analyzer{
@Override
protected TokenStreamComponents createComponents(String s) {
Tokenizer source = new MyTokenizer();
//攔截連1 轉小寫
TokenStream filter1 = new MyTokenFilter(source);
return new TokenStreamComponents(source,filter1);
}

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 MyAnalyzer(); TokenStream ts = ana.tokenStream("aa", 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();
}

}
}

   4.6 運行結果

   

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM