Lucene分词器
Lucene分析器的基类为Analyzer,Analyzer包含两个核心组件:Tokenizer和 TokenFilter。自定义分析器必须实现Analyzer类的抽象方法createComponents(String)来定义TokenStreamComponents。在调用方法tokenStream(String, Reader)的时候,TokenStreamComponents会被重复使用。
自定义分析器首先需要继承Analyzer类,代码如下:
public class HAnalyzer extends Analyzer {
/*
* 默认不使用停用单词
* */
private boolean useStopWords;
private CharArraySet stopWords;
public HAnalyzer() {
useStopWords = false;
}
public HAnalyzer(CharArraySet stopWords) {
useStopWords = true;
this.stopWords = stopWords;
}
@Override
protected TokenStreamComponents createComponents(String fieldName) {
LetterTokenizer tokenizer = new LetterTokenizer();
if(useStopWords) {
return new TokenStreamComponents(tokenizer , new HStopTokenFilter(tokenizer, stopWords));
}
return new TokenStreamComponents(tokenizer);
}
}
Analyzer两个核心组件:Tokenizer和 TokenFilter,实现如下:
/*
* 分词解析器,需要定义Token属性CharTermAttribute offsetAttribute
* */
public class LetterTokenizer extends Tokenizer { /*
* 词元文本属性
* */
private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class); /*
* 词元位移属性
* */
private final OffsetAttribute offsetAtt = addAttribute(OffsetAttribute.class); /*
* Token文本最大长度
* */
private static final int MAX_WORD_LEN = 255; /*
* Buffer Size
* */
private static final int IO_BUFFER_SIZE = 4096; private char[] ioBuffer = new char[IO_BUFFER_SIZE]; /*
* Token分隔符集合
* */
private char[] splitChars = {' ',',','.','!'}; /*
* 当前字符串在原字符串中的位置
* */
private int offset = 0; /*
* 当前字符在这一次读取的字符串中的位置
* */
private int bufferIndex = 0; /*
* 每次读取字符串的长度
* */
private int dataLen = 0; @Override
public boolean incrementToken() throws IOException {
clearAttributes(); // 清除前一个Token的所有属性
int length = 0; // 单词的长度
int start = bufferIndex;
char []buffer = termAtt.buffer();
while(true) {
if(bufferIndex >= dataLen) { // 分词处理到ioBuffer末尾时,继续从input读取数据
offset += dataLen;
dataLen = input.read(ioBuffer);
if(dataLen == -1) { // 在Reader读取结束
dataLen = 0;
if(length > 0) { // 虽然从input读取完数据,ioBuffer处理的字符 还没有生成Token
break;
} else {
return false;
}
}
bufferIndex = 0; // 指向ioBuffer的起始位置
}
/**处理ioBuffer读取的字符*/
final char ch = ioBuffer[bufferIndex++];
if(isTokenChar(ch)) { // ch分隔符,形成Token,跳出循环
if(length == 0) {
start = offset + bufferIndex - 1;
} else if(length == buffer.length) {
buffer = termAtt.resizeBuffer(length + 1);
}
if(length == MAX_WORD_LEN) {
break;
}
break;
} else {
buffer[length++] = normalize(ch); // CharTermAttribute文本赋值
}
}
termAtt.setLength(length);
offsetAtt.setOffset(correctOffset(start), correctOffset(start + length));
return true;
} /*
* 规整化--->转为小写
* */
protected char normalize(char ch) {
return Character.toLowerCase(ch);
} /*
* 如果字符ch是分隔符,返回true
* */
protected boolean isTokenChar(char ch) {
for(char c : splitChars) {
if(ch == c) {
return true;
}
}
return false;
} }
/*
* 过滤TokenStream,需要更改Token的PositionIncrementAttribute属性
* */
public class HStopTokenFilter extends TokenFilter { /*
* TokenStream流Token文本属性
* */
private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class); /*
* 当前Token与前一个Token位移差属性
* */
private PositionIncrementAttribute posIncrAtt = addAttribute(PositionIncrementAttribute.class); private int skippedPositions; /*
* 停用单词集合
* */
private CharArraySet stopWords; protected HStopTokenFilter(TokenStream input) {
super(input);
} public HStopTokenFilter(TokenStream input , CharArraySet stopWords) {
this(input);
this.stopWords = stopWords;
} @Override
public boolean incrementToken() throws IOException {
clearAttributes(); // 清除上个Token所有属性
skippedPositions = 0;
while(input.incrementToken()) {
if(filter()) { // 过滤掉当前Token,修改skippedPositions
skippedPositions += posIncrAtt.getPositionIncrement();
} else { // 当前Token不可过滤,如果前一个Token被过滤,需修改当前Token的PositionIncrementAttribute属性
if(skippedPositions != 0) {
posIncrAtt.setPositionIncrement(posIncrAtt.getPositionIncrement() + skippedPositions);
}
return true;
}
}
return false;
} private boolean filter() {
return stopWords.contains(termAtt.buffer() , 0 , termAtt.length());
}
}
通过自定义的HAnalyzer,可以完成文本分析,示例如下:
public class Main {
public static void main(String []args) {
HAnalyzer analyzer = new HAnalyzer();
TokenStream ts = null;
try {
ts = analyzer.tokenStream("myfield", new StringReader("I am a student.My name is Tom!"));
//获取词元位置属性
OffsetAttribute offset = ts.addAttribute(OffsetAttribute.class);
//获取词元文本属性
CharTermAttribute term = ts.addAttribute(CharTermAttribute.class);
//重置TokenStream(重置StringReader)
ts.reset();
//迭代获取分词结果
while (ts.incrementToken()) {
System.out.println(offset.startOffset() + " - " + offset.endOffset() + " : " + term.toString() );
}
//关闭TokenStream(关闭StringReader)
ts.end();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Lucene分词器的更多相关文章
- Lucene学习-深入Lucene分词器,TokenStream获取分词详细信息
Lucene学习-深入Lucene分词器,TokenStream获取分词详细信息 在此回复牛妞的关于程序中分词器的问题,其实可以直接很简单的在词库中配置就好了,Lucene中分词的所有信息我们都可以从 ...
- Lucene系列三:Lucene分词器详解、实现自己的一个分词器
一.Lucene分词器详解 1. Lucene-分词器API (1)org.apache.lucene.analysi.Analyzer 分析器,分词器组件的核心API,它的职责:构建真正对文本进行分 ...
- lucene分词器与搜索
一.分词器 lucene针对不同的语言和虚伪提供了许多分词器,我们可以针对应用的不同的需求使用不同的分词器进行分词.我们需要注意的是在创建索引时使用的分词器与搜索时使用的分词器要保持一致.否则搜索的结 ...
- 学习笔记(三)--Lucene分词器详解
Lucene-分词器API org.apache.lucene.analysi.Analyzer 分析器,分词器组件的核心API,它的职责:构建真正对文本进行分词处理的TokenStream(分词处理 ...
- lucene 分词器
分词器 作用:切分关键词的. 在什么地方使用到了:在建立索引和搜索时. 原文:An IndexWriter creates and maintains an index. 1,切分: An Index ...
- lucene分词器中的Analyzer,TokenStream, Tokenizer, TokenFilter
分词器的核心类: Analyzer:分词器 TokenStream: 分词器做优点理之后得到的一个流.这个流中存储了分词的各种信息,能够通过TokenStream有效的获取到分词单元. 下面是把文件流 ...
- Lucene.net(4.8.0)+PanGu分词器问题记录一:分词器Analyzer的构造和内部成员ReuseStategy
前言:目前自己在做使用Lucene.net和PanGu分词实现全文检索的工作,不过自己是把别人做好的项目进行迁移.因为项目整体要迁移到ASP.NET Core 2.0版本,而Lucene使用的版本是3 ...
- Lucene 03 - 什么是分词器 + 使用IK中文分词器
目录 1 分词器概述 1.1 分词器简介 1.2 分词器的使用 1.3 中文分词器 1.3.1 中文分词器简介 1.3.2 Lucene提供的中文分词器 1.3.3 第三方中文分词器 2 IK分词器的 ...
- Lucene.net(4.8.0) 学习问题记录一:分词器Analyzer的构造和内部成员ReuseStategy
前言:目前自己在做使用Lucene.net和PanGu分词实现全文检索的工作,不过自己是把别人做好的项目进行迁移.因为项目整体要迁移到ASP.NET Core 2.0版本,而Lucene使用的版本是3 ...
随机推荐
- 解决:centos7.3 tomcat7启动巨慢问题
目前公司大部分服务器操作系统还是centos6.5,tomcat用的是7,平时基本上没什么问题,启动也比较快,但是,最近有部分项目服务器更新至centos7.3 ,有些机器启动tomcat的时候巨慢无 ...
- Newtonsoft.Json 序列化和反序列化 以及时间格式
1.JSON序列化 string JsonStr= JsonConvert.SerializeObject(Entity); eg: A a=new A(); a.Name="Elain ...
- 【SQL】持久性存储模块PSM
1. 创建PSM函数和过程 创建过程: CREATE PROCEDURE 名字 (参数) 局部声明: 过程体: 创建函数: CREATE FUNCTION 名字 (参数) RETURNS 类型 局部声 ...
- poj 1947(树形DP+背包)
Rebuilding Roads Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 10663 Accepted: 4891 ...
- poj 1654(利用叉积求面积)
Area Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 17937 Accepted: 4957 Description ...
- centos7当中的systemd及systemctl(节选)
全面进入centos7时代,这个东东是需要系统了解的. http://blog.jobbole.com/85070/?utm_source=blog.jobbole.com&utm_mediu ...
- PHP无限极分类详谈
当你学习php无限极分类的时候,大家都觉得一个字“难”我也觉得很难,所以,现在都还在看,因为工作要用到,所以,就必须得研究研究. 到网上一搜php无限极分类,很多,但好多都是一个,并且,写的很乱,代码 ...
- 【cocos2d-js官方文档】三、Bake功能使用说明
设计意图 在游戏开发的过程中,经常会遇到作为UI或者不怎么修改的背景的层(Layer), 这些层内容并不怎么变动. 而在游戏的渲染过程中,这些层往往又会消耗大量的渲染时间,特别是比较复杂的UI界面,比 ...
- 【转】进程、线程、 GIL全局解释器锁知识点整理
转自:https://www.cnblogs.com/alex3714/articles/5230609.html 本节内容 操作系统发展史介绍 进程.与线程区别 python GIL全局解释器锁 线 ...
- Ubuntu下安装 Phantomjs
1.安装phantomjs —-下载程序文件 wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.7-linux-x8 ...