lucene自定义分词器

小黄书的分词很久就写好了,但是怎么结合lucene呢?别着急下面就开始。

首先要实现一个Analyzer的抽象类:

public class NLPAnalyzer extends Analyzer {

	@Override
	protected TokenStreamComponents createComponents(String field) {
		return new TokenStreamComponents(new NLPTokenizer());
	}
	
}

代码非常简单,主要就是NLPTokenizer这个东西非常重要的,里面就是实现分词的代码:

public class NLPTokenizer extends Tokenizer {

	@Override
	public boolean incrementToken() throws IOException {
        	// 内置input获取文本内容“你喜欢吃苹果吗?”
		clearAttributes(); // 清空
		CharTermAttribute term = addAttribute(CharTermAttribute.class);
		term.append("分词");
		return true;
	}
	
}

上面的代码并没有分词,因为分词我在其他地方实现了。

最重要的就是incrementToken这个方法,会一直调用这个方法。

返回值:true表示已经分词完成;false表示未完成。

获取分词的文本内容,可以通过内置的input参数获取。

下面是使用:

public static void main(String[] args) throws IOException {
	NLPAnalyzer analyzer = new NLPAnalyzer();
	new AnalyzerTest();
	TokenStream tokenStream = analyzer.tokenStream("content", "你喜欢吃苹果吗?");
	tokenStream.reset();
	while (tokenStream.incrementToken()) {
		CharTermAttribute charTermAttribute = tokenStream.getAttribute(CharTermAttribute.class);
		System.out.println(new String(charTermAttribute.buffer(), 0, charTermAttribute.length()));
	}
	analyzer.close();
}

注意上面要调用reset这个方法,否者会提示:

Exception in thread "main" java.lang.IllegalStateException: TokenStream contract violation: reset()/close() call missing, reset() called multiple times, or subclass does not call super.reset(). Please see Javadocs of TokenStream class for more information about the correct consuming workflow.

后面输出关键词的时候也需要使用new String(charTermAttribute.buffer(), 0, charTermAttribute.length()),否则会出现多余的字符串。

上面的代码如果只是用来分词是没有问题的,如果你需要使用到lucene创建索引,那么就会出现下面这样的一个错误:

Exception in thread "main" java.lang.NullPointerException
	at org.apache.lucene.index.TermsHashPerField.add(TermsHashPerField.java:150)
	at org.apache.lucene.index.DefaultIndexingChain$PerField.invert(DefaultIndexingChain.java:661)
	at org.apache.lucene.index.DefaultIndexingChain.processField(DefaultIndexingChain.java:344)
	at org.apache.lucene.index.DefaultIndexingChain.processDocument(DefaultIndexingChain.java:300)
	at org.apache.lucene.index.DocumentsWriterPerThread.updateDocument(DocumentsWriterPerThread.java:234)
	at org.apache.lucene.index.DocumentsWriter.updateDocument(DocumentsWriter.java:450)
	at org.apache.lucene.index.IndexWriter.updateDocument(IndexWriter.java:1475)
	at org.apache.lucene.index.IndexWriter.addDocument(IndexWriter.java:1254)
	at com.acgist.nlp.query.lucene.IndexWriterUtils.addIndex(IndexWriterUtils.java:24)
	at com.acgist.test.SearchTest.main(SearchTest.java:13)

这个的原因是:

CharTermAttribute term = addAttribute(CharTermAttribute.class);

这段代码不能定义到方法体内,而要定义为类变量才可以的:

private CharTermAttribute term;

这样就OK了。

但是分词好像又有点问题,成了一个一个的了。
下次来搞了,有点累。