搜索爲將 -- IKAnalyzer -- lucene6.6適配

前言

在中文分詞器中, IKAnalyzer 作的是相對不錯的,有着細度分割和智能使用兩個模式 。
可是,這個版本由於太陳舊,做者再也不維護,(項目估計是。。。),因此與如今的Lucene 6.6 版本差距有些大。因此,我就根據網上各位大神的文章,加上本身對 API 與源碼的閱讀,稍微的進行了改動,能夠簡單的運行。
注: 這裏的簡單是指,能夠簡單的運行源碼 中的簡單案例。git

正文

項目介紹

  1. IKAnaylzer版本: IK Analyzer 2012FFgithub

感謝提供的分詞源碼 http://git.oschina.net/wltea/...數組

  1. lucene 版本:lucene 6.60iphone

代碼改動

1.對IKTokenizer的改動

源碼ide

/**
   * Lucene 4.0 Tokenizer適配器類構造函數
   * @param in
   * @param useSmart
   */
  public IKTokenizer(Reader in, boolean useSmart) {
    super(in);
    offsetAtt = addAttribute(OffsetAttribute.class);
    termAtt = addAttribute(CharTermAttribute.class);
    typeAtt = addAttribute(TypeAttribute.class);
    _IKImplement = new IKSegmenter(input, useSmart);
  }

經查閱 lucene 源碼
Tokenizer類的構造器已經再也不接收 Reader 源碼以下函數

protected Tokenizer() {
        this.input = ILLEGAL_STATE_READER;
        this.inputPending = ILLEGAL_STATE_READER;
    }

    protected Tokenizer(AttributeFactory factory) {
        super(factory);
        this.input = ILLEGAL_STATE_READER;
        this.inputPending = ILLEGAL_STATE_READER;
    }

所以改動 IKTokenizer 類 ,以下學習

public IKTokenizer( boolean useSmart) {
        super();
        offsetAtt = addAttribute(OffsetAttribute.class);
        termAtt = addAttribute(CharTermAttribute.class);
        typeAtt = addAttribute(TypeAttribute.class);
        //傳入 IKSegmenter 的 input Reader  流,會被 父類 Tokenizer 類的無參構造器
        //初始化爲 this.input = ILLEGAL_STATE_READER;
        _IKImplement = new IKSegmenter(input, useSmart);
    }

去除了 Reader 形參 。 默認調用 父類 的 無參構造函數 Tokenizer()
注:在該博客下發現,還須要配置分詞器工廠類,所以還要多增長一段構造器代碼,以下測試

//方便建立 工廠類
    public IKTokenizer(AttributeFactory factory, boolean useSmart) {
        super(factory);
        offsetAtt = addAttribute(OffsetAttribute.class);
        termAtt = addAttribute(CharTermAttribute.class);
        typeAtt = addAttribute(TypeAttribute.class);
        _IKImplement = new IKSegmenter(input, useSmart);
    }

2. 對IKAnalyzer 的改動

源碼ui

/**
   * 重載Analyzer接口,構造分詞組件
   */
  @Override
  protected TokenStreamComponents createComponents(String fieldName, final Reader in) {
    Tokenizer _IKTokenizer = new IKTokenizer(in, this.useSmart());
    return new TokenStreamComponents(_IKTokenizer);
  }

lucene 6.6 關於 Analyzer 接口中 關於 createComponents() 方法的源碼this

protected abstract Analyzer.TokenStreamComponents createComponents(String var1);

結合上文中對 IKTokenizer 源碼的改動,所以須要去除 參數 Reader in
改動的代碼 以下:

/**
     * 重載Analyzer接口,構造分詞組件
     */
    @Override
    protected TokenStreamComponents createComponents(String fieldName) {
        Tokenizer _IKTokenizer = new IKTokenizer(this.useSmart());
        return new Analyzer.TokenStreamComponents(_IKTokenizer);
    }

3. 對SWMCQueryBuilder 的改動

源碼以下:

// 藉助lucene queryparser 生成SWMC Query
    QueryParser qp = new QueryParser(Version.LUCENE_43, fieldName, new StandardAnalyzer(
        Version.LUCENE_43));
    qp.setDefaultOperator(QueryParser.AND_OPERATOR);
    qp.setAutoGeneratePhraseQueries(true);

因爲新版本的 lucene 已經不在使用 Version 類 進行定義,(個人上一篇lucene6.6 學習心得說的很清楚)所以須要將之移除。
移除後,改動版本以下:

//藉助lucene queryparser 生成SWMC Query
        QueryParser qp = new QueryParser(fieldName, new StandardAnalyzer());
        qp.setDefaultOperator(QueryParser.AND_OPERATOR);
        qp.setAutoGeneratePhraseQueries(true);

4. 對IKQueryExpressionParser 的改動

IKQueryExpressionParser 類中方法 BooleanQuery ,在近期的 lucene 中有了較大改動,不知道的話,能夠 查閱個人上一篇文章lucene6.6 學習心得.
所以源碼中對 IKQueryExpressionParser 類中關於 BooleanQuery 的方法都須要進行更改。
由於方法中代碼過多 , 所以,我選取其中比較關鍵的幾個地方,進行展現。
關鍵源碼以下:

private Query toBooleanQuery(Element op) {
BooleanQuery resultQuery = new BooleanQuery();
Query q2 = this.querys.pop();
Query q1 = this.querys.pop();
BooleanClause[] clauses = ((BooleanQuery) q1).getClauses();
resultQuery.add(c);
return resultQuery;
}

改動代碼以下:
1.數組版本

private Query toBooleanQuery(Element op){
BooleanQuery.Builder builder = new BooleanQuery.Builder();
Query q2 = this.querys.pop();    
Query q1 = this.querys.pop();

 //由於,我看源碼,並無發現會增刪的地方 ,因而直接轉成了數組 
//迭代器版本的在下文
if(q1 instanceof BooleanQuery){    
    BooleanClause[] clauses =(BooleanClause[]) ((BooleanQuery)q1).clauses().toArray();
 if(clauses.length > 0
    && clauses[0].getOccur() == Occur.MUST){
    for(BooleanClause c : clauses){
        builder.add(c);
    }
    }else{
    builder.add(q1,Occur.MUST);
    }

     return builder.build();
}

2.迭代器版本

private Query toBooleanQuery(Element op){
BooleanQuery.Builder builder = new BooleanQuery.Builder();

Query q2 = this.querys.pop();    
Query q1 = this.querys.pop();

if(q1 instanceof BooleanQuery){
    Iterator<BooleanClause> clauses = ((BooleanQuery) q1).iterator();
    while (clauses.hasNext()) {
    BooleanClause clause = clauses.next();
    if (clause.getOccur() == Occur.MUST) {
    builder.add(clause);
    } else {
    builder.add(q1,Occur.MUST);
    }
}    

return builder.build();
}

5. 項目運行

打開包中的測試代碼
1.IKAnalzyerDemo
運行結果以下圖

輸入圖片說明
2.LuceneIndexAndSearchDemo
運行結果以下圖

輸入圖片說明

5. 源碼與整合包的下載

源碼與整合包 已經上傳至個人 GitHub 上,有興趣的能夠去那裏下載,不嫌棄的話,Star 一下 ,也是能夠的哦~

相關文章
相關標籤/搜索