1、结果高亮
Lucene对高亮显示提供 了两种实现模式,Highlighter和FastVectorHighlighter。FastVectorHighlighter速度快,功能更完美。但其是有一定条件的,在使用FastVectorHighlighter创建索引时,需要存储Field分词信息(TermVector.WITH_POSITIONS_OFFSETS),而Highlighter是不需要这个前提条件的。
高亮显示处理流程图:
(1)、获取原始文档,需在生成索引时设置Store.YES属性,且若在索引域中指定TermVector.WITH_POSITIONS_OFFSETS属性,则能大大加速获取过程。同时lucene提供TokenSources类,若创建索引时已存在Store.YES信息,则可以直接获取到文档的TokenStream信息;若不存在,则需要通过Analyzer去获取实现。
(2)、利用Fragmenter对文档信息进行切分处理。这个过程也非常重要,因为通过Fragmenter处理,可将原文档中冗余的信息过滤,从而选择需要的内容,进行后续的操作。
(3)、Lucene提供QueryScorer和SpanScorer类来对每一个切片进行评分,以便选出最符合搜索条件的文档内容。
(4)、将最后选定的文档内容进行编码处理。
(5)、对编码后的文档进行格式化处理,包括加粗、改变现实字体颜色等。
(6)、对修改完成的内容进行编译,就能完成高亮显示文本输出。
高亮显示代码示例:
public class HighlighterSearcher {
public static void search(String indexDir, String q) throws IOException, ParseException {
// 得到读取索引文件的路径
Directory dir = FSDirectory.open(Paths.get(indexDir));
// 通过Dir得到路径下所有文件
IndexReader reader = DirectoryReader.open(dir);
// 建立索引查询器
IndexSearcher searcher = new IndexSearcher(reader);
// 实例化分析器
Analyzer analyzer = new StandardAnalyzer();
/********建立查询解析器********/
// 第一个参数是要查询的字段; 第二个参数市分析器Analyzer
TermQuery query = new TermQuery(new Term("name", q));
Scorer scorer = new QueryScorer(query);
SimpleHTMLFormatter formatter = new SimpleHTMLFormatter("<span class=\"highlight\">", "</span>");
Highlighter high = new Highlighter(formatter, scorer);
long start = System.currentTimeMillis();
/********开始查询********/
// 第一个参数是通过传过来的参数来查找得到的query; 第二个参数是要查询出的行数
TopDocs hits = searcher.search(query, 10);
// 计算索引结束时间
long end = System.currentTimeMillis();
System.out.println("匹配 " + q + ",查询到 " + hits.totalHits + " 个记录, 用时:" + (end - start));
// 遍历hits.scoreDocs,得到scoreDoc
// scoreDoc:得分文档,即得到的文档 scoreDocs:代表topDocs这个文档数组
for (ScoreDoc scoreDoc : hits.scoreDocs) {
Document doc = searcher.doc(scoreDoc.doc);
try {
TokenStream tokenStream = new CJKAnalyzer().tokenStream("name", new StringReader(doc.get("name")));
System.out.println(high.getBestFragment(tokenStream, doc.get("name")));
} catch (Exception e) {
e.printStackTrace();
}
}
//关闭reader
reader.close();
}
}
输出结果示例:
匹配 lucene,查询到 8 hits 个记录, 用时:56
<span class="highlight">Lucene</span>
<span class="highlight">Lucene</span> 实战(第2版).pdf
《从<span class="highlight">Lucene</span>到Elasticsearch 全文检索实战》.pdf
《从<span class="highlight">Lucene</span>到Elasticsearch 全文检索实战》.pdf
<span class="highlight">Lucene</span>搜索引擎开发权威经典.pdf
从<span class="highlight">Lucene</span>到Elasticsearch:全文检索实战@www.java1234.com.pdf
<span class="highlight">Lucene</span>搜索引擎开发进阶实战www.java1234.com.pdf
解密搜索引擎技术实战 <span class="highlight">LUCENE</span> & JAVA精华版 第3版@www.java1234.com.pdf
2、词频统计
词频统计(TF),就是在一个给定的文本、文档或者词库中,给定的一个关键词在该文本、文档或者词库中出现的次数。词频统计,就是针对这些关键词出现的次数,按照不同的统计方法,进行一个有效的统计。
2.1、域值排序
域值排序即为按照权重排序,权重值越大,其匹配程度越高,排序就靠前。域值排序需要使用search(Query,Filter,Sort)方法,若排序后不需要过滤结果,可将Filter设置为null。通常,接受Sort对象参数的Search方法不会对匹配文档进行评分,因此在实现search的过程中,综合考虑通过域值排序无需就行评分操作。而且评分操作会造成系统性能大量损耗。
2.2、索引顺序排序
如果需要实现索引顺序排序,可以借助searcher方法中的Sort.INDEXORDER作为参数来实现。对于按照索引顺序排序的搜索结果,文档顺序一旦建立就不会改变了,如果重新更新索引文档,之前的索引就失效了,新的文档会生成新的id,然后重新排序。所以,在实际的程序应用中,这种操作的可行性不高,意义不大,因此也很少被采用。在程序开发中若没有选择任何排序方式,则Lucene会根据文档的评分来完成排序工作,其实评分排序是Lucene默认的排序方式。
2.3、相关性排序
按照相关程度对结果进行的降序排列,也可称为默认评分排序。即按照关键字与搜索的内容匹配或意思符合程度高低进行排序。当然,相关性排序也可以按照升序排序,但是应用不多,因此很少被提及。相关性排序是通过将 Sort 对象参数设为 null ,然后传递给相关方法或者使用默认排序方法来实现的。每种调用方法都会返回默认评分的排序结果。由于我们在使用 Sort 对象时会产生额外的开销,所以要尽可能地使用 search ( Query , int )方法来达到排序的目的。
2.4、词频率排序
根据词出现的频率进行排序,有点类似域值排序,需要引入计数来根据关键词(字)在被搜索内容(句子、文本或文章)中出现的频率(次数)进行统计,然后根据统计出来的重复率按由高到低的顺序来进行排序,这时就关联上了相关性排序,更多与关键字相关的内容排在了最前面。因此,根据词频率的排序,就像是综合了域排序和相关性排序的方法,对关键字搜索结果进行优化后显示出来的。