高亮功能一直都是全文检索的一项很是优秀的模块,在一个标准的搜索引擎中,高亮的返回命中结果,几乎是必不可少的一项需求,由于经过高亮,咱们能够在咱们的搜索界面上快速标记出用户的检索关键词,从而减小了用户本身寻找想要的结果,在必定程度上大大提升了用户的体验性和友好度。
那么,今天就来看下咱们在Lucene中,怎么实现高亮,以及高亮的几种实现方式。
首先仍是喜欢老生常谈的来补充下高亮须要的熟悉的基本知识,固然若是你只是须要实现效果,而不关注它的底层API,那么能够忽略此部分,不过仍是要友好的提示一下,若是使用过程当中出了点小问题,不会API,但是不容易解决的,除非你愿意各类google。
要使用高亮,首先就得从索引时开始,由于须要高亮的字段,须要准确的获取位置信息,以及一些偏移量,若是信息不许确,那么可能在结果中,就会出现一些莫名其妙的错位,反映到网页上就是标注了不应标注的字,没有标注该标的内容,因此这一点仍是须要注意一下,在索引的时候,咱们须要使用项向量记录各个token的位置信息,这很简单,代码以下:
html
FieldType type=new FieldType(TextField.TYPE_STORED); type.setStoreTermVectorOffsets(true);//记录相对增量 type.setStoreTermVectorPositions(true);//记录位置信息 type.setStoreTermVectors(true);//存储向量信息 type.freeze();//阻止改动信息 Field field=new Field("字段名", "值", type);//示例
简单说下,TextField的2个枚举变量的意思
前端
变量名 | 释义 |
TYPE_NOT_STORED | 索引,分词,不存储 |
TYPE_STORED | 索引,分词,存储 |
类 | 释义 |
SimpleHTMLFormatter | 经常使用的格式化Html标签器,提供一个构造函数传入高亮颜色标签,默认使用黑色 |
TokenSources | 提供静态方法,支持从数据源中获取TokenStream,进行token处理 |
Highlighter | 负责获取匹配上的高亮片断 |
QueryScorer | 对命中结果进行评分操做 |
Fragmenter | 将原始字符串拆分红独立的片断 |
NullFragmenter | 对较短的域进行总体高亮 |
FastVectorHighlighter | 基于快速高亮 |
Encoder | 提供一些实现类,对html文本操做,如,去掉一些特殊匹配符号<,> and so on,及一些其余的非ASCII特殊字符。 |
id:1 name: 中国是一个伟大的国家,咱们中国人都是好样的哈哈,中国永远是强大的 content: 你好人民 id:2 name: 咱们有一个家它的名字是中国 content: 中国的大地,富饶 id:3 name: 咱们的中国,咱们的大地都是人民的但愿的 content: 若是不在片断中生成一些字段的话 id:4 name: 2014年此时此刻你在作什么的啊 content: 哈哈锄禾日当午 id:5 name: 当你孤单时你会想起谁,你想不想找我的来陪 content: 我永远不孤单啊
1,测试普通高亮的核心代码:
java
String filed="name"; QueryParser query=new QueryParser(Version.LUCENE_44, filed, new IKAnalyzer(false)); Query q=query.parse("伟大的中国");//测试字段 TopDocs top=searcher.search(q, 100); QueryScorer score=new QueryScorer(q, filed);//传入评分 SimpleHTMLFormatter fors=new SimpleHTMLFormatter("<span style=\"color:red;\">", "</span>");//定制高亮标签 Highlighter highlighter=new Highlighter(fors,score);//高亮分析器 // highlighter.setMaxDocCharsToAnalyze(1);//设置高亮处理的字符个数 for(ScoreDoc sd:top.scoreDocs){ Document doc=searcher.doc(sd.doc); String name=doc.get(filed); TokenStream token=TokenSources.getAnyTokenStream(searcher.getIndexReader(), sd.doc, filed, new IKAnalyzer(true));//获取tokenstream Fragmenter fragment=new SimpleSpanFragmenter(score); highlighter.setTextFragmenter(fragment); String str=highlighter.getBestFragment(token, name);//获取高亮的片断,能够对其数量进行限制 System.out.println("高亮的片断 =====>"+str); }
输出结果以下ajax
高亮的片断 =====>中国是一个<span style="color:red;">伟大</span><span style="color:red;">的</span>国家,咱们中国人都是好样<span style="color:red;">的</span>哈哈,<span style="color:red;">中国</span>永远是强大<span style="color:red;">的</span> 高亮的片断 =====>咱们<span style="color:red;">的</span><span style="color:red;">中国</span>,咱们<span style="color:red;">的</span>大地都是人民<span style="color:red;">的</span>但愿<span style="color:red;">的</span> 高亮的片断 =====>咱们有一个家它<span style="color:red;">的</span>名字是<span style="color:red;">中国</span>
2,快速高亮,FastVectorHighlighter,这个类可能会消耗更多的存储空间,来换取更好的性能,固然除了性能上提高外,它还有一个很是炫的功能,支持多种颜色标记,高亮关键字,除此以外还支持Ngram的域,以及智能合并相邻高亮短语.
咱们来看下散仙快速高亮的3条测试数据: sql
id:2 name: 中国(China),位于东亚,是一个以华夏文明为主体、中华文化为基础,以汉族为主要种族的统一多民族国家,通用汉语。中国疆域内的各个民族统称为中华民族,龙是中华民族的象征。 content: 中国是世界四大文明古国之一,有着悠久的历史,距今约5000年前,以中原地区为中心开始出现聚落组织进而成国家和朝代,后历经屡次演变和朝代更迭,持续时间较长的朝代有夏、商、周、汉、晋、唐、宋、元、明、清等 id:1 name: 中国的自古以来就是一个很是伟大的民族 content: 中国是一个世界人口大国,拥有13亿多的人口. id:3 name: 没有根的野草,飘忽的命运 content: 谁像你当我宝,什么也作到,旧爱数足一块布,在这一刻写句号,只想跟你终老.
核心代码以下:数据库
Query q=query.parse("伟大的中华民族"); TopDocs top=searcher.search(q, 100); //QueryScorer score=new QueryScorer(q, filed); //SimpleHTMLFormatter fors=new SimpleHTMLFormatter("<span style=\"color:red;\">", "</span>");//定制高亮标签 //Highlighter highlighter=new Highlighter(fors,score);//高亮分析器 //FastVectorHighlighter fastHighlighter=new FastVectorHighlighter(); FragListBuilder fragListBuilder=new SimpleFragListBuilder(); //注意下面的构造函数里,使用的是颜色数组,用来支持多种颜色高亮 FragmentsBuilder fragmentsBuilder= new ScoreOrderFragmentsBuilder(BaseFragmentsBuilder.COLORED_PRE_TAGS,BaseFragmentsBuilder.COLORED_POST_TAGS); FastVectorHighlighter fastHighlighter2=new FastVectorHighlighter(true, true, fragListBuilder, fragmentsBuilder); FieldQuery querys=fastHighlighter2.getFieldQuery(q);//reader是传入的流 // highlighter.setMaxDocCharsToAnalyze(1);//设置高亮处理的字符个数 for(ScoreDoc sd:top.scoreDocs){ String snippt=fastHighlighter2.getBestFragment(querys, reader, sd.doc,filed,300); if(snippt!=null){ System.out.println("高亮的片断是:"+snippt); } }
结果以下,注意有多种颜色标识:
json
高亮的片断是:中国<b style="background:lawngreen">的</b>自古以来就是一个很是<b style="background:yellow">伟大</b><b style="background:lawngreen">的</b>民族 高亮的片断是:中国(China),位于东亚,是一个以华夏文明为主体、中华文化为基础,以汉族为主要种族<b style="background:lawngreen">的</b>统一多民族国家,通用汉语。中国疆域内<b style="background:lawngreen">的</b>各个民族统称为<b style="background:aquamarine">中华民族</b>,龙是<b style="background:aquamarine">中华民族</b><b style="background:lawngreen">的</b>象征。 高亮的片断是:没有根<b style="background:lawngreen">的</b>野草,飘忽<b style="background:lawngreen">的</b>命运
3.下面来着重说一下,高亮的第三种方式,前台高亮,散仙在上文曾提过,基于高亮的字段,必须的存储,不然没法实现高亮标注,固然这种说法,只是对于后台高亮而言的,那么对于大文本状况下,存储到索引里是很是浪费空间的,并且还有可能会影响到检索速度,因此就提出了,第三种方式。
在前台进行高亮,而后大文本字段,能够存储在外部其余的数据源里面,须要标记时,能够直接根据ID,或者某个字段,读取数据而后经过JS正则在前端替换检索的关键词便可,在这以前须要作的一步就是,使用ajax把检索的关键词,传入后台进行分词,而后将结果返回前台,进行对分词后的数据,进行匹配替换,再加上颜色标记,就能够在前台实现高亮了,这也是前台高亮的实现原理,这种作法,在某些业务场景下,能够大大减小服务器压力,经过客户端减压,以及不用再存储一些向量信息,从而对系统的性能的提升,也是有很大帮助的。
下面给出一个前台高亮的截图,注意用的是快速高亮的索引。
数组
附上前台高亮的核心代码
服务器
$.ajax({ type :"post", url: "getContent", data:"str="+str, dataType:"json", async:false, success:function(msg){ // alert(msg); $("#div").empty(); $.each(msg, function(i, n) { var temp=""; for(var i=0;i<shu.length;i++){ if(shu[i]!=""){ n.name=n.name.replace(new RegExp(shu[i],'g'), "<span style=\"color:red;\">"+shu[i]+"</span>"); } } $("#div").append("[*]"+n.name+" "); $("#div").append("[*]=============================== ") }); } });
至此,有关Lucene的高亮部分的内容,散仙就总结到这里了,若是有什么不足之处,欢迎各位道友指出。大部分场景下,使用普通高亮就能够完成了,固然不管使用那种方式,只要能知足咱们的业务就行了,很简单的道理,会抓住老鼠的猫,就是好猫。app
感谢耐下心读到此处的朋友^_^, Lucene交流群:324714439