Lucene写自己的Analyzer 博客分类: lucenejava系统架构
程序员文章站
2024-03-23 17:03:28
...
实现一个简单的分析器(Analyzer)的例子如下所示:]
一般在Tokenizer的子类实际执行词语的切分。需要设置的值有:和词相关的属性termAtt、和位置相关的属性offsetAtt。在搜索结果中高亮显示查询词时,需要用到和位置相关的属性。但是在切分用户查询词时,一般不需要和位置相关的属性。Tokenizer的子类需要重写incrementToken方法。通过incrementToken方法遍历Tokenizer分析出的词,当还有词可以获取时,返回true;已经遍历到结尾时,返回false。
基于属性的方法把无用的词特征和想要的词特征分隔开。每个TokenStream在构造时增加它想要的属性。在TokenStream的整个生命周期中都保留一个属性的引用。这样在获取所有和TokenStream实例相关的属性时,可以保证属性的类型安全。
在TokenStream.incrementToken()方法中,一个token流仅仅操作在构造方法中声明过的属性。例如,如果只要分词,则只需要TermAttribute。其他的属性,例如PositionIncrementAttribute或者PayloadAttribute都被这个TokenStream忽略掉了,因为这时不需要其他的属性。
虽然也可以通过termAtt对象中的term方法返回词,但这个方法返回的是字符串,直接返回字符数组的termBuffer方法性能更好。下面是采用正向最大长度匹配实现的一个简单的Tokenizer。
public class MyAnalyzer extends Analyzer { public TokenStream tokenStream(String fieldName, Reader reader) { //以空格方式切分Token TokenStream stream = new WhitespaceTokenizer(reader); //删除过短或过长的词,例如 in、of、it stream = new LengthFilter(stream, 3, Integer.MAX_VALUE); //给每个词标注词性 stream = new PartOfSpeechAttributeImpl.PartOfSpeechTagging Filter(stream); return stream; } }
一般在Tokenizer的子类实际执行词语的切分。需要设置的值有:和词相关的属性termAtt、和位置相关的属性offsetAtt。在搜索结果中高亮显示查询词时,需要用到和位置相关的属性。但是在切分用户查询词时,一般不需要和位置相关的属性。Tokenizer的子类需要重写incrementToken方法。通过incrementToken方法遍历Tokenizer分析出的词,当还有词可以获取时,返回true;已经遍历到结尾时,返回false。
基于属性的方法把无用的词特征和想要的词特征分隔开。每个TokenStream在构造时增加它想要的属性。在TokenStream的整个生命周期中都保留一个属性的引用。这样在获取所有和TokenStream实例相关的属性时,可以保证属性的类型安全。
protected CnTokenStream(TokenStream input) { super(input); termAtt = (TermAttribute) addAttribute(TermAttribute.class); }
在TokenStream.incrementToken()方法中,一个token流仅仅操作在构造方法中声明过的属性。例如,如果只要分词,则只需要TermAttribute。其他的属性,例如PositionIncrementAttribute或者PayloadAttribute都被这个TokenStream忽略掉了,因为这时不需要其他的属性。
public boolean incrementToken() throws IOException { if (input.incrementToken()) { final char[] termBuffer = termAtt.termBuffer(); final int termLength = termAtt.termLength(); if (replaceChar(termBuffer, termLength)) { termAtt.setTermBuffer(output, 0, outputPos); } return true; } return false; }
虽然也可以通过termAtt对象中的term方法返回词,但这个方法返回的是字符串,直接返回字符数组的termBuffer方法性能更好。下面是采用正向最大长度匹配实现的一个简单的Tokenizer。
public class CnTokenizer extends Tokenizer { private static TernarySearchTrie dic = new TernarySearchTrie("SDIC.txt"); //词典 private TermAttribute termAtt;// 词属性 private static final int IO_BUFFER_SIZE = 4096; private char[] ioBuffer = new char[IO_BUFFER_SIZE]; private boolean done; private int i = 0;// i是用来控制匹配的起始位置的变量 private int upto = 0; public CnTokenizer(Reader reader) { super(reader); this.termAtt = ((TermAttribute) addAttribute(TermAttribute.class)); this.done = false; } public void resizeIOBuffer(int newSize) { if (ioBuffer.length < newSize) { // Not big enough; create a new array with slight // over allocation and preserve content final char[] newnewCharBuffer = new char[newSize]; System.arraycopy(ioBuffer, 0, newCharBuffer, 0, ioBuffer. length); ioBuffer = newCharBuffer; } } @Override public boolean incrementToken() throws IOException { if (!done) { clearAttributes(); done = true; upto = 0; i = 0; while (true) { final int length = input. read(ioBuffer, upto, ioBuffer. length - upto); if (length == -1) break; upto += length; if (upto == ioBuffer.length) resizeIOBuffer(upto * 2); } } if (i < upto) { char[] word = dic.matchLong(ioBuffer, i, upto); // 正向最大长度匹配 if (word != null)// 已经匹配上 { termAtt.setTermBuffer(word, 0, word.length); i += word.length; } else { termAtt.setTermBuffer(ioBuffer, i, 1); ++i;// 下次匹配点在这个字符之后 } return true; } return false; } }
推荐阅读
-
Lucene写自己的Analyzer 博客分类: lucenejava系统架构
-
Lucene 分词解读(一) 博客分类: lucenejava系统架构
-
java.lang.OutOfMemoryError: unable to create new native thread 博客分类: javalinux系统架构lucene Java的性能监控工具profileunable to create new native threadJVMPI an experimental interfaceis no longer supported
-
java.lang.OutOfMemoryError: unable to create new native thread 博客分类: javalinux系统架构lucene Java的性能监控工具profileunable to create new native threadJVMPI an experimental interfaceis no longer supported