Lucene5中编写自定义同义词分词器(基于IK中文分词器)

编写一个专门获取同义词的引擎:

package com.daelly.sample.lucene.analyzer.custom;

import java.io.IOException;

public interface SynonymEngine {
	String[] getSynonyms(String s) throws IOException;
}

package com.daelly.sample.lucene.analyzer.custom;

import java.io.IOException;
import java.util.HashMap;

public class SimpleSynonymEngine implements SynonymEngine {
	
	private static HashMap<String, String[]> map = new HashMap<>();
	
	{
		map.put("我", new String[]{"俺","咱"});
		map.put("中国", new String[]{"天朝"});
		map.put("广州", new String[]{"五羊城"});
	}

	@Override
	public String[] getSynonyms(String s) throws IOException {
		return map.get(s);
	}

}


编写同义词filter

package com.daelly.sample.lucene.analyzer.custom;

import java.io.IOException;
import java.util.Stack;

import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
import org.apache.lucene.util.AttributeSource;

public class SynonymFilter extends TokenFilter {
	
	public static final String TOKEN_TYPE_SYNONYM = "SYNONYM";
	
	private final Stack<String> synonymStack;
	private SynonymEngine synonymEngine;
	private AttributeSource.State current;
	
	private final CharTermAttribute termAttr;
	private final PositionIncrementAttribute posIncrAttr;

	protected SynonymFilter(TokenStream input, SynonymEngine engine) {
		super(input);
		synonymStack = new Stack<>();
		this.synonymEngine = engine;
		
		this.termAttr = addAttribute(CharTermAttribute.class);
		this.posIncrAttr = addAttribute(PositionIncrementAttribute.class);
	}

	@Override
	public boolean incrementToken() throws IOException {
		if(!synonymStack.isEmpty()) {
			String syn = synonymStack.pop();
			restoreState(current);
			//这是4.x的写法
			//termAttr.setTermBuffer(syn);
			//这是5.x的写法
			termAttr.copyBuffer(syn.toCharArray(), 0, syn.length());
			posIncrAttr.setPositionIncrement(0);
			return true;
		}
		
		if(!input.incrementToken()) {
			return false;
		}
		
		//当前的token有同义词,将当前token的状态记录下来
		//调到下一个token的时候恢复这个状态,将同义词插入到位置偏移量为0的上个位置
		//为什么要到下一个token再处理我也不是很懂
		if(addAliasesToStack()) {
			current = captureState();
		}
		return true;
	}

	/*
	 * 
	 */
	private boolean addAliasesToStack() throws IOException {
		String termVal = termAttr.toString();
		String[] synonyms = synonymEngine.getSynonyms(termVal);
		
		if(synonyms == null) {
			return false;
		}
		
		for (String synonym : synonyms) {
			synonymStack.push(synonym);
		}
		return true;
	}
}


编写analyzer:

package com.daelly.sample.lucene.analyzer.custom;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.Tokenizer;
import org.wltea.analyzer.lucene.IKTokenizer;

public class SynonymAnalyzer extends Analyzer {
	
	private final SynonymEngine engine;
	
	public SynonymAnalyzer(SynonymEngine engine) {
		this.engine = engine;
	}

	@Override
	protected TokenStreamComponents createComponents(String fieldName) {
		Tokenizer tokenizer = new IKTokenizer(true);
		TokenStream tokenStream = new SynonymFilter(tokenizer, engine);
		return new TokenStreamComponents(tokenizer,tokenStream);
	}

}

编写测试:

package com.daelly.sample.lucene;

import static org.junit.Assert.assertEquals;

import java.io.IOException;

import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.junit.Before;
import org.junit.Test;

import com.daelly.sample.lucene.analyzer.custom.SimpleSynonymEngine;
import com.daelly.sample.lucene.analyzer.custom.SynonymAnalyzer;

public class CommonAnalyzerTest {

	Directory dir;

	@Before
	public void setUp() throws Exception {
		dir = new RAMDirectory();
		IndexWriterConfig conf = new IndexWriterConfig(new SynonymAnalyzer(new SimpleSynonymEngine()));
		IndexWriter writer = new IndexWriter(dir, conf );
		Document doc = new Document();
		doc.add(new TextField("content", "我来自中国广州", Field.Store.YES));
		writer.addDocument(doc);
		writer.close();
	}

	@Test
	public void test1() throws IOException {
		Term term = new Term("content", "天朝");
		Query query = new TermQuery(term);
		IndexReader reader = DirectoryReader.open(dir);
		IndexSearcher searcher = new IndexSearcher(reader);
		TopDocs docs = searcher.search(query, 10);
		assertEquals(1, docs.totalHits);
	}
	
	@Test
	public void test2() throws IOException {
		Term term = new Term("content", "俺");
		Query query = new TermQuery(term);
		IndexReader reader = DirectoryReader.open(dir);
		IndexSearcher searcher = new IndexSearcher(reader);
		TopDocs docs = searcher.search(query, 10);
		assertEquals(1, docs.totalHits);
	}
	
	@Test
	public void test3() throws IOException {
		Term term = new Term("content", "五羊城");
		Query query = new TermQuery(term);
		IndexReader reader = DirectoryReader.open(dir);
		IndexSearcher searcher = new IndexSearcher(reader);
		TopDocs docs = searcher.search(query, 10);
		assertEquals(1, docs.totalHits);
	}

}


测试结果,同义词分词器生效。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目录 序言: 1 第一章 LUCENE基础 2 1.1 索引部分的核心类 2 1.2 分词部分的核心类 2 1.3 搜索部分的核心类 2 第二章 索引建立 3 2.1 创建Directory 3 2.2 创建Writer 3 2.3 创建文档并且添加索引 4 2.4 查询索引的基本信息 5 2.5 删除和更新索引 5 (1) 使用writer删除 5 (2) 使用reader删除 5 (3) 恢复删除 5 (4) 彻底删除 6 (5) 更新索引 6 (6) 手动优化 6 2.6 索引文件作用 7 第三章 搜索功能 8 3.1 简单搜索 8 (1) 创建IndexReader 8 (2) 创建IndexSearcher 8 (3) 创建Term和TermQuery 9 (5) 根据TopDocs获取ScoreDoc 9 (6) 根据ScoreDoc获取相应文档 9 3.2 其他搜索 9 (1) 范围查询(TermRangeQuery) 10 (2) 数字查询(NumericRangeQuery) 11 (3) 前缀查询(PrefixQuery) 11 (4) 通配符查询(WildcardQuery) 11 (5) 多条件查询(BooleanQuery) 12 (6) 短语查询(PhraseQuery) 12 (7) 模糊查询(FuzzyQuery) 12 3.3 QueryParser 13 (1) 创建QueryParser 13 (2) 各种匹配方式 13 3.4 分页搜索 14 (1) 普通分页 14 (2) searchAfter分页 15 第四章 分词基础 17 4.1 分词效果 17 (1) 准备分词输出类 17 (2) 创建分词器 18 (3) 英文分词效果 18 (4) 中文分词效果 19 4.2 分词原理 21 (1) TokenStream 21 (2) Tokenizer 22 (3) TokenFilter 23 4.3 分词属性 23 (1) 分词属性查看 24 (2) 分词属性对比 25 4.4 自定义分词器 26 (1) 自定义Stop分词器 26 (2) 实现简单同义词索引 27 第五章 高级搜索 32 5.1 搜索排序 34 (1) 建立搜索类 34 (2) 默认排序 35 (3) 根据评分排序 35 (4) 根据索引号排序 36 (5) 根据文件大小排序 36 (6) 根据日期排序 37 (7) 根据文件名排序(倒序) 37 (8) 多条件排序 38 5.2 搜索过滤 39 (1) 建立搜索类 39 (2) 文本域范围过滤(TermRangeFilter) 40 (3) 数字域范围过滤(NumericRangeFilter) 40 (4) 查询结果过滤(QueryWrapperFilter) 40 5.3 自定义评分 41 (1) 创建一个类继承CustomScoreQuery 41 (2) 创建一个类继承CustomScoreProvider 42 (3) 自定义评分效果测试 43 5.4 自定义QueryParser 44 (1) 限制低性能的QueryParser 44 (2) 扩展基于数字和日期的查询 45 (3) 自定义QueryParser效果测试 46 5.5 自定义过滤 49 (1) 分析需求,创建接口 49 (2) 创建过滤,继承Filter 50 (3) 实现接口,效果演示 52 第六章 LUCENE扩展 54 6.1 Luke 54 (1) 启动Luke 54 (2) 索引概述页面 55 (3) 查看索引信息 56 (4) 查询索引信息 57 6.2 Tika 58 (1) Tika的使用 58 (2) Tika的原理 59 6.3 高亮显示 61 (1) 自定义高亮标签 61 (2) 多个域高亮显示 62 6.4 近实时搜索 65 (1) 近实时搜索的创建 66 (2) 近实时搜索的使用 67

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值