搜索引擎Lucene(6):查询结果高亮及词频提取

1、结果高亮

Lucene对高亮显示提供 了两种实现模式,Highlighter和FastVectorHighlighter。FastVectorHighlighter速度快,功能更完美。但其是有一定条件的,在使用FastVectorHighlighter创建索引时,需要存储Field分词信息(TermVector.WITH_POSITIONS_OFFSETS),而Highlighter是不需要这个前提条件的。

高亮显示处理流程图:

9795603-2431daeda3d2310f.png
处理流程.png

(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> &amp; 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、词频率排序

根据词出现的频率进行排序,有点类似域值排序,需要引入计数来根据关键词(字)在被搜索内容(句子、文本或文章)中出现的频率(次数)进行统计,然后根据统计出来的重复率按由高到低的顺序来进行排序,这时就关联上了相关性排序,更多与关键字相关的内容排在了最前面。因此,根据词频率的排序,就像是综合了域排序和相关性排序的方法,对关键字搜索结果进行优化后显示出来的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值