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.Tokenizertoken是分词组件,tokenStream 是一些token序列组成的。tokeizer是抽象类。public abstract class Tokenizerextends TokenStream。
analysis通过对文本的分析来建立TokenStream(分词数据流),tokenStream是有一个个token(单个分词)组成。所以说analyzer就代表着从文本数据中抽取索引词(term)的一种策略。
token和term的关系:
- 收集带建索引的原始文档(document)
- 将原始文档传递给词条化工具(tokenizer)进行文本词条化
- 将得到的词条(token)传递给语言分析工具(linguistic Modules)处理得到term
- 得到的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);
}
}