在Lucene的org.apache.lucene.search.highlight包中提供了关于高亮显示检索关键字的工具。
高亮显示模块需要两个独立的输入:完整的原始文本以用来提供操作数据,以及来源于该文本的一个TokenStream。为了创建TokenStream,你必须对文本进行重新分析,此时需要使用与索引期间相同的分析器进行。
package test; import java.io.File; import java.io.IOException; import java.io.StringReader; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.document.Document; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexReader; import org.apache.lucene.queryparser.classic.ParseException; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.highlight.Fragmenter; import org.apache.lucene.search.highlight.Highlighter; import org.apache.lucene.search.highlight.InvalidTokenOffsetsException; import org.apache.lucene.search.highlight.QueryScorer; import org.apache.lucene.search.highlight.SimpleHTMLFormatter; import org.apache.lucene.search.highlight.SimpleSpanFragmenter; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import org.wltea.analyzer.lucene.IKAnalyzer; public class Seacher { // 索引保存路径 public static String indexDir = "d:/LuceneIndex"; public static void main(String[] args) throws ParseException, InvalidTokenOffsetsException, IOException { // 新建 IndexSearcher Directory dir = FSDirectory.open(new File(indexDir)); IndexReader reader = DirectoryReader.open(dir); IndexSearcher searcher = new IndexSearcher(reader); // 搜索条件 IKAnalyzer analyzer = new IKAnalyzer(); analyzer.setUseSmart(true); QueryParser parser = new QueryParser("title", analyzer); Query query = parser.parse("如何设计一个电商网站"); // 搜索结果 TopDocs hits = searcher.search(query, 10); System.out.println(hits.scoreDocs.length); // 高亮显示 /** * 创建QueryScorer * Fragmenter输出的是文本片段序列, * 而Highlighter必须从中挑选出最适合的一个或多个片段呈现给客户, * 为了做到这点,Highlighter会要求Java接口Scorer来对每个片段进行评分 * QueryTermScorer 基于片段中对应Query的项数进行评分 * QueryScorer只对促成文档匹配的实际项进行评分 */ QueryScorer qs = new QueryScorer(query); /** 自定义标注高亮文本标签 */ SimpleHTMLFormatter sh = new SimpleHTMLFormatter("<span style='color:red;'>", "</span>"); /** * 创建Fragmenter 作用是将原始字符串拆分成独立的片段 * SimpleSpanFragmenter 是尝试将让片段永远包含跨度匹配的文档 * SimpleFragmenter 是负责将文本拆分封固定字符长度的片段,但它并处理子边界(默认100) * NullFragmenter 整个字符串作为单个片段返回,这适合于处理title域和前台文本较短的域 */ Fragmenter fragmenter = new SimpleSpanFragmenter(qs); Highlighter highlighter = new Highlighter(sh, qs); highlighter.setTextFragmenter(fragmenter); // 获取搜索结果 for (ScoreDoc scoreDoc : hits.scoreDocs) { Document doc = searcher.doc(scoreDoc.doc); String title = doc.get("title"); if (title != null) { TokenStream ts = analyzer.tokenStream("title", new StringReader(title)); String val = highlighter.getBestFragment(ts, title); System.out.println(doc.get("id") + " : " + val); } } } }