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 ...
随机推荐
- jquery 的combobox 处理级联
随笔---jquery 的combobox 处理级联 ------------------------html------------- <select id="groupId&quo ...
- SSH Secure Shell 无法登录:server responded "algorithm negotiation failed”
SSH Secure Shell Client 连接 ubuntu系统报错 修改ssh的配置文件 /etc/ssh/sshd_config在配置文件中添加: Ciphers aes128-cbc,ae ...
- 【计算机网络】wireshark抓包分析1
学习计算机网络很久了,但总是局限于书本知识,感觉get不到重点.经师兄建议用wireshark抓包分析看看. 我自己以前并没有做过抓包分析,所以这篇博文可能会有很多错误,只是我自己的一个记录,路过的亲 ...
- happens-before规则
happens-before原则: happens-before它是判断数据是否存在竞争.线程是否安全的主要依据.为了保证线程安全我们可以让2个操作具有happens-before关系.(JDK5 开 ...
- k8s 组件架构
一.整体架构 kubernetes分为 master节点和工作节点,前者是管理节点,后者是容器运行的节点.其中master节点主要有3个重要组件,分别是APIServer,sheduler和contr ...
- 提取windows用户明文密码
前段时间mimikatz热传,主要是因为可以直接提取当前登录用户明文密码. 其实,有个更厉害的神器,无需那么多命令操作,一个命令搞定: C:\>wce -w WCE v1.3beta (Wind ...
- Tomcat 服务器基本知识
Tomcat下载安装和配置 下载 下载地址: http://tomcat.apache.org tomcat服务器分为很多版本, 其中包括windows版和linux版 ...
- 分享HTTP Status 404(The requested resource is not available)的几种解决方案解决方法
下面是直接copy的,如果有什么疑问or补充,请不吝指教! 原文地址:http://www.myexception.cn/java-web/1480013.html 这个问题搞了我两天的时间,找了各种 ...
- 51nod 1240 莫比乌斯函数【数论+莫比乌斯函数】
1240 莫比乌斯函数 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 莫比乌斯函数,由德国数学家和天文学家莫比乌斯提出.梅滕斯(Mertens)首先使用 ...
- cogs 双服务点设置
4. 双服务点设置 ☆ 输入文件:djsb.in 输出文件:djsb.out 简单对比时间限制:1 s 内存限制:128 MB 问题描述为了进一步普及九年义务教育,政府要在某乡镇建立两 ...