欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Lucene写自己的Analyzer 博客分类: lucenejava系统架构

程序员文章站 2024-03-23 17:03:28
...
实现一个简单的分析器(Analyzer)的例子如下所示:]
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;  
        }  
    }