- 浏览: 2183592 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (682)
- 软件思想 (7)
- Lucene(修真篇) (17)
- Lucene(仙界篇) (20)
- Lucene(神界篇) (11)
- Solr (48)
- Hadoop (77)
- Spark (38)
- Hbase (26)
- Hive (19)
- Pig (25)
- ELK (64)
- Zookeeper (12)
- JAVA (119)
- Linux (59)
- 多线程 (8)
- Nutch (5)
- JAVA EE (21)
- Oracle (7)
- Python (32)
- Xml (5)
- Gson (1)
- Cygwin (1)
- JavaScript (4)
- MySQL (9)
- Lucene/Solr(转) (5)
- 缓存 (2)
- Github/Git (1)
- 开源爬虫 (1)
- Hadoop运维 (7)
- shell命令 (9)
- 生活感悟 (42)
- shell编程 (23)
- Scala (11)
- MongoDB (3)
- docker (2)
- Nodejs (3)
- Neo4j (5)
- storm (3)
- opencv (1)
最新评论
-
qindongliang1922:
粟谷_sugu 写道不太理解“分词字段存储docvalue是没 ...
浅谈Lucene中的DocValues -
粟谷_sugu:
不太理解“分词字段存储docvalue是没有意义的”,这句话, ...
浅谈Lucene中的DocValues -
yin_bp:
高性能elasticsearch ORM开发库使用文档http ...
为什么说Elasticsearch搜索是近实时的? -
hackWang:
请问博主,有用solr做电商的搜索项目?
Solr中Group和Facet的用法 -
章司nana:
遇到的问题同楼上 为什么会返回null
Lucene4.3开发之第八步之渡劫初期(八)
转载请注明,原创地址,谢谢配合!
http://qindongliang1922.iteye.com/blog/1953409
高亮功能一直都是全文检索的一项非常优秀的模块,在一个标准的搜索引擎中,高亮的返回命中结果,几乎是必不可少的一项需求,因为通过高亮,我们可以在我们的搜索界面上快速标记出用户的检索关键词,从而减少了用户自己寻找想要的结果,在一定程度上大大提高了用户的体验性和友好度。
那么,散仙今天就来看下我们在Lucene中,怎么实现高亮,以及高亮的几种实现方式。
首先散仙还是喜欢老生常谈的来补充下高亮需要的熟悉的基本知识,当然如果你只是需要实现效果,而不关注它的底层API,那么可以忽略此部分,不过散仙还是要友好的提示一下,如果使用过程中出了点小问题,不会API,可是不容易解决的,除非你愿意各种google。
要使用高亮,首先就得从索引时开始,因为需要高亮的字段,需要准确的获取位置信息,以及一些偏移量,如果信息不准确,那么可能在结果中,就会出现一些莫名其妙的错位,反映到网页上就是标注了不该标注的字,没有标注该标的内容,所以这一点还是需要注意一下,在索引的时候,我们需要使用项向量记录各个token的位置信息,这很简单,代码如下:
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 | 索引,分词,存储 |
由此看来,需要进行高亮的内容,是一定要存储的,可能有一些比较大的文本,会比较占索引空间,从而影响检索性能,当然我们也可以使用外部存储,关系型数据库,nosql什么的都可以,此时,高亮可能就需要做另一些处理了,散仙在下文会介绍。
下面我们来看下,高亮的需要用到的一些基本的类
类 | 释义 |
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,测试普通高亮的核心代码:
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); }
输出结果如下
高亮的片段 =====>中国是一个<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条测试数据:
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); } }
结果如下,注意有多种颜色标识:
高亮的片段是:中国<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的高亮部分的内容,散仙就总结到这里了,如果有什么不足之处,欢迎各位道友指出。大部分场景下,使用普通高亮就可以完成了,当然无论使用那种方式,只要能满足我们的业务就好了,很简单的道理,会抓住老鼠的猫,就是好猫。
感谢耐下心读到此处的朋友^_^, Lucene交流群:324714439
转载请注明,原创地址,谢谢配合!
http://qindongliang1922.iteye.com/blog/1953409
评论
2 楼
章司nana
2017-12-29
遇到的问题同楼上 为什么会返回null
1 楼
seven_zhao
2015-01-12
你好,为什么我在使用你的FastVectorHighlighter代码进行高亮的时候,如果使用高亮显示那么可以查询出结果,如果使用高亮显示,结果为NUll,请问你遇见过这种问题吗?
主要代码如下:
Analyzer a = new StandardAnalyzer();
FileIndexUtils fiu = new FileIndexUtils();
IndexSearcher search = fiu.getSearcher();
String[] fields = new String[]{"title","content"};
MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, a);
try {
Query query = parser.parse("java");
TopDocs tds = search.search(query, 20);
FragListBuilder fragListBuilder = new SimpleFragListBuilder();
//注意下面的构造函数里,使用的是颜色数组,用来支持多种颜色高亮
// 可以在这里定义高亮关键词的样式,比如:
// 改BaseFragmentsBuilder.COLORED_PRE_TAGS为new String[]{"<EM>"}
// 改BaseFragmentsBuilder.COLORED_POST_TAGS为new String[]{"</EM>"}
FragmentsBuilder fragmentsBuilder = new ScoreOrderFragmentsBuilder(BaseFragmentsBuilder.COLORED_PRE_TAGS,BaseFragmentsBuilder.COLORED_POST_TAGS);
FastVectorHighlighter fvh = new FastVectorHighlighter(true,true, fragListBuilder, fragmentsBuilder);
FieldQuery fq = fvh.getFieldQuery(query);
System.out.println("命中--》"+tds.totalHits);
for(ScoreDoc sd:tds.scoreDocs){
System.out.println("title:"+search.doc(sd.doc).get("title"));
String highTitle = fvh.getBestFragment(fq, search.getIndexReader(), sd.doc,"title", 100);
System.out.println("highTitle-->"+highTitle);
}
} catch (ParseException e) {
e.printStackTrace();
} catch(IOException ioe){
ioe.printStackTrace();
}
主要代码如下:
Analyzer a = new StandardAnalyzer();
FileIndexUtils fiu = new FileIndexUtils();
IndexSearcher search = fiu.getSearcher();
String[] fields = new String[]{"title","content"};
MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, a);
try {
Query query = parser.parse("java");
TopDocs tds = search.search(query, 20);
FragListBuilder fragListBuilder = new SimpleFragListBuilder();
//注意下面的构造函数里,使用的是颜色数组,用来支持多种颜色高亮
// 可以在这里定义高亮关键词的样式,比如:
// 改BaseFragmentsBuilder.COLORED_PRE_TAGS为new String[]{"<EM>"}
// 改BaseFragmentsBuilder.COLORED_POST_TAGS为new String[]{"</EM>"}
FragmentsBuilder fragmentsBuilder = new ScoreOrderFragmentsBuilder(BaseFragmentsBuilder.COLORED_PRE_TAGS,BaseFragmentsBuilder.COLORED_POST_TAGS);
FastVectorHighlighter fvh = new FastVectorHighlighter(true,true, fragListBuilder, fragmentsBuilder);
FieldQuery fq = fvh.getFieldQuery(query);
System.out.println("命中--》"+tds.totalHits);
for(ScoreDoc sd:tds.scoreDocs){
System.out.println("title:"+search.doc(sd.doc).get("title"));
String highTitle = fvh.getBestFragment(fq, search.getIndexReader(), sd.doc,"title", 100);
System.out.println("highTitle-->"+highTitle);
}
} catch (ParseException e) {
e.printStackTrace();
} catch(IOException ioe){
ioe.printStackTrace();
}
发表评论
-
Lucene4.3开发之第十步之渡劫后期(十)
2014-01-15 20:23 4633转载请务必注明,原创 ... -
Lucene4.3开发之第九步之渡劫中期(九)
2014-01-13 21:41 4067转载请务必注明,原创地址,谢谢配合! http://qind ... -
Lucene4.3开发之插曲之落寞繁华
2013-11-07 19:22 4358转载请注明,原创地址,谢谢配合! http://qindon ... -
Lucene4.3开发之第七步之合体后期(七)
2013-09-16 20:17 4495转载请注明原创地址: http://qindongliang1 ... -
Lucene4.3开发之插曲之烽火连城
2013-09-06 18:12 5939转载请注明,原创地址,谢谢配合! http://qindon ... -
Lucene4.3开发之第六步之分神中期(六)
2013-08-30 20:17 6247转载请注明,原创地址,谢谢配合! http://qindo ... -
Lucene4.3开发之插曲之斗转星移
2013-08-26 18:08 4579允许转载,转载请注明原创地址: http://qindo ... -
Lucene4.3开发之插曲之包容万物
2013-08-20 15:23 7920允许转载,转载请注明原创地址: http://qindong ... -
Lucene4.3开发之第五步之融丹筑基(五)
2013-08-14 17:57 8559本文章允许转载,转载请注明原创地址 http://qin ... -
Lucene4.3开发之第四步之脱胎换骨(四)
2013-08-09 18:40 9950为防止,一些小网站私自盗用原文,请支持原创 原文永久链 ... -
Lucene4.3开发之第三步之温故知新(三)
2013-08-07 18:30 5043前面几篇笔者已经把Lucene的最基本的入门,介绍完了,本篇就 ... -
Lucene4.3开发之第二步初入修真(二)
2013-07-29 18:23 8011上次笔者简单介绍下了,Lucene的入门搭建以及一个添加的De ... -
Lucene4.3开发之第一步小试牛刀(一)
2013-07-25 16:47 8294首页,本篇适合对于刚 ... -
lucene开发序幕曲之luke神器
2013-07-25 11:28 8405lucene是一款很优秀的全 ... -
lucene4.x的分组实现
2013-06-24 11:51 4561lucene在4.x之前,没有实现分组的功能,如果业务中有需要 ... -
solr4.2的入门部署
2013-06-24 11:00 2864solr 4.2的入门配置 第一步,从官网上下载下 ...
相关推荐
第8章 公众平台开发技巧 199 8.1 图文消息使用详解 199 8.1.1 单图文消息的实现 199 8.1.2 多图文消息的实现 200 8.1.3 图文消息使用注意事项 201 8.2 公众账号无响应的处理 202 8.2.1 公众账号...
第8章 开源软件之服务器软件 101 8.1 apache http服务器 101 8.2 tomcat 103 8.3 jetty 104 8.4 geronimo 105 8.5 jboss 108 8.6 glassfish 109 8.7 mysql 111 8.8 postgresql 114 8.9 derby 116 8.10 filezilla ...
第8章 网络购物车(jsp+servlet+javabean) 8.1 网络购物车原理 8.2 实现网络购物车功能 8.3 小结 第9章 搜索引擎(lucene+web spider) 9.1 关于搜索引擎的基本概念 9.2 网络蜘蛛(web spider) ...
### Solr开发指南知识点概述 #### 一、Solr简介 **1.1.1 官网介绍** Solr是一款由Apache基金会维护的开源搜索引擎服务器,其核心是基于Lucene的Java实现。Solr提供了丰富的功能,如层级搜索、命中高亮显示、支持...
获取数据是构建搜索引擎的第一步。数据来源多样,包括网页、数据库和本地文件等。 - **3.1 自己的网络蜘蛛**:通过自定义爬虫抓取网页数据。 - **3.2 抓取数据库中的内容**:利用JDBC等技术抓取数据库中的信息。 - ...
#### 八、集成LUCENE全文搜索引擎 **8.1 创建搜索索引** - 学习如何利用Lucene创建全文搜索索引。 **8.2 至 8.5 搜索引擎配置** - 探讨如何配置搜索引擎的各项参数,如文档类型、分析器等。 以上是关于OpenCMS...
#### 第8章 集成LUCENE全文搜索引擎 ##### 8.1 创建搜索索引 - **过程**: - 定义索引结构。 - 分析文本内容,提取关键词。 - 构建索引。 ##### 8.2 搜索引擎配置-概述 - **配置项**: - 索引位置: 存储索引文件...
#### 8. 集成LUCENE全文搜索引擎 ##### 8.1 创建搜索索引 - **索引构建**: - 分析文本数据。 - 建立倒排索引。 - **索引优化**: - 删除无意义词汇。 - 规范化处理。 ##### 8.2 搜索引擎配置-概述 - **配置要点...