Lucene token解析

本文深入介绍了Lucene的各个核心模块,包括分析模块、索引模块、存储模块等,并详细解释了TokenStream的工作原理及其在搜索过程中的作用。

Lucene模块分析:

Lucene的 analysis 模块主要负责词法分析及语言处理而形成Term.

Lucene的 index 模块主要负责索引的创建,里面有IndexWriter.

Lucene的 store 模块主要负责索引的读写。

Lucene的 QueryParser 主要负责语法分析。

Lucene的 search 模块主要负责对索引的搜索。

Lucene的 similarity 模块主要负责对相关性打分的实现。

Lucene源码组件:

org.apache.lucene.analysis 语言分析器,主要用于的切词,支持中文主要是扩展此类

org.apache.lucene.document 索引存储时的文档结构管理,类似于关系型数据库的表结构

org.apache.lucene.index 索引管理,包括索引建立、删除等

org.apache.lucene.store 数据存储管理,主要包括一些底层的I/O操作

org.apache.lucene.search 搜索管理,根据搜索条件进行查询

org.apache.lucene.util 一些公用类

org.apache.lucene.queryParser 查询分析器,实现查询关键词间的运算,如与、或、非等

TokenStrem的形成:

|extended by org.apache.lucene.analysis.TokenStream  
      |extended by org.apache.lucene.analysis.Tokenizer

token是分词组件,tokenStream 是一些token序列组成的。tokeizer是抽象类。public abstract class Tokenizerextends TokenStream。

analysis通过对文本的分析来建立TokenStream(分词数据流),tokenStream是有一个个token(单个分词)组成。所以说analyzer就代表着从文本数据中抽取索引词(term)的一种策略。

token和term的关系:

  1. 收集带建索引的原始文档(document)
  2. 将原始文档传递给词条化工具(tokenizer)进行文本词条化
  3. 将得到的词条(token)传递给语言分析工具(linguistic Modules)处理得到term
  4. 得到的term传递给索引组件indexer进行构造倒排索引

TokenStream作用:

tokenstream是从doucment的域(field)中抽取的一个个分词而组成的一个数据流。tokenstream中是一个个的分词。而每个分词优势由一个个的属性组成。

tokenstream的作用就是从给入的文本中不断解析础token,具体的做法是tokenStream有方法incrementToken,每次调用,将产生待分析文本的下一个token.

TokenStream的两个方法:

public boolean incrementToken(){}:用于得到下一个token

public void reset(){}:重置该分词器,使得此TokenStrean可以重新开始返回各个分词。

使用场景;

QueryParser parser = new QueryParser(Version.LUCENE_36, field, analyzer);

Query query = parser.parse(queryString);

Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_47);

String text = "利用 Lucene 进行搜索就像建立索引一样也是非常方便的。";

TokenStream tokenStream = analyzer.tokenStream("keyword", text);

tokenStream.reset();

while(tokenStream.incrementToken()) {
    CharTermAttribute charTermAttribute = tokenStream.getAttribute(CharTermAttribute.class);    

    System.out.println(charTermAttribute.toString());
}

Token信息的保存:

TokenStream是继承于AttributeSource,其包含Map,保存从class到对象的映射,从而可以保存不同类型的对象的值。

CharTermAttribute:保存Token字符串的内容

PositionIncrementAttribute:保存位置信息,表示tokenStream中的当前token与前一个token在实际的原文本中相隔的词语数量。

OffsetAttribute:用来保存偏移量信息

TypeAttribute:用来保存Token的类型信息

TermAttribute: 表示token的字符串信息

PositionIncrementAttribute解析:

Source:I'm a student. these are apples     
TokenSteam: [1:  I'm ]  [2:a]   [3:student]     [4:these]   [5:are ]   [6:apples]

      PositionIncrementAttribute:表示tokenStream中的当前token与前一个token在实际的原文本中相隔的词语数量
      比如: 在tokenStream中[2:a] 的前一个token是[1: I’m ] ,它们在原文本中相隔的词语数是1,则token=”a”的PositionIncrementAttribute值为1。如果token是原文本中的第一个词,则默认值为1。因此上面例子的PositionIncrementAttribute结果就全是1了。
       如果我们使用停用词表来进行过滤之后的话:TokenSteam就会变成: [1: I’m ] [2:student] [3:apples],这时student的PositionIncrementAttribute值就不会再是1,而是与[1: I’m ]在原文本中相隔词语数量=2,而apples则变成了5。
      那么这个属性有什么用呢,用处很大的。假如我们想搜索一个短语student apples(假如有这个短语)。很显然,用户是要搜索出student apples紧挨着出现的文档。这个时候我们找到了某一篇文档(比如上面例子的字符串)都含有student
apples。但是由于apples的PositionIncrementAttribute值是5,说明肯定没有紧挨着,这样也就能够轻易解决短语搜索的问题了。

IKAnalyzerDemo.java

package org.algorithm;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
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.core.SimpleAnalyzer;
import org.apache.lucene.analysis.core.StopAnalyzer;
import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
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;
import org.apache.lucene.util.Version;

public class IKAnalyzerDemo04 {

    /*
     * Lucene自带分词器进行分词操作
     * */
    public static void getIKAnalyzer(String str,Analyzer analyzer){
        try{
            //将一个字符串创建成Token流,第一个参数只是标识性,没有实际作用
            TokenStream stream = analyzer.tokenStream("", new StringReader(str));
            //获取词与词之间的位置增量
            PositionIncrementAttribute position = stream.addAttribute(PositionIncrementAttribute.class);
            //获取各个单词之间的偏移量
            OffsetAttribute offseta = stream.addAttribute(OffsetAttribute.class);
            //获取当前分词的类型
            TypeAttribute typea = stream.addAttribute(TypeAttribute.class);
            //保存相应词汇的内容
            CharTermAttribute cta = stream.addAttribute(CharTermAttribute.class);
            stream.reset(); //重置分词器,使得tokenstream可以重新返回各个分词
            while(stream.incrementToken()){
                System.out.print("位置增量:"+position.getPositionIncrement()+" |");

                System.out.print(cta+" |"+offseta.startOffset()+" - "+offseta.endOffset()+" |"+typea);

                System.out.println();
            }
            System.out.println();

        }catch(IOException e){
            e.printStackTrace();
        }
    }

    @SuppressWarnings("resource")
    public static void main(String[] args) throws IOException {

        String path = "c:\\292.txt";//加载本地txt文件
        StringBuffer sb = new StringBuffer();
        BufferedReader br = new BufferedReader(new FileReader(new File(path)));
        String temp = "";
        while((temp = br.readLine()) != null){
            sb.append(temp);
            sb.append("\r\n");
        }
        String str = sb.toString();


        Analyzer analyzer1 = new StandardAnalyzer(Version.LUCENE_40);
        Analyzer analyzer2 = new StopAnalyzer(Version.LUCENE_40);
        Analyzer analyzer3 = new SimpleAnalyzer(Version.LUCENE_40);
        Analyzer analyzer4 = new WhitespaceAnalyzer(Version.LUCENE_40);

        getIKAnalyzer(str,analyzer1);
        getIKAnalyzer(str,analyzer2);
        getIKAnalyzer(str,analyzer3);
        getIKAnalyzer(str,analyzer4);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值