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

1、结果高亮

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

高亮显示处理流程图:

处理流程.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、词频率排序

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容