- 浏览: 2146816 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (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 4557转载请务必注明,原创 ... -
Lucene4.3开发之第九步之渡劫中期(九)
2014-01-13 21:41 4020转载请务必注明,原创地址,谢谢配合! http://qind ... -
Lucene4.3开发之插曲之落寞繁华
2013-11-07 19:22 4307转载请注明,原创地址,谢谢配合! http://qindon ... -
Lucene4.3开发之第七步之合体后期(七)
2013-09-16 20:17 4426转载请注明原创地址: http://qindongliang1 ... -
Lucene4.3开发之插曲之烽火连城
2013-09-06 18:12 5897转载请注明,原创地址,谢谢配合! http://qindon ... -
Lucene4.3开发之第六步之分神中期(六)
2013-08-30 20:17 6196转载请注明,原创地址,谢谢配合! http://qindo ... -
Lucene4.3开发之插曲之斗转星移
2013-08-26 18:08 4535允许转载,转载请注明原创地址: http://qindo ... -
Lucene4.3开发之插曲之包容万物
2013-08-20 15:23 7863允许转载,转载请注明原创地址: http://qindong ... -
Lucene4.3开发之第五步之融丹筑基(五)
2013-08-14 17:57 8500本文章允许转载,转载请注明原创地址 http://qin ... -
Lucene4.3开发之第四步之脱胎换骨(四)
2013-08-09 18:40 9885为防止,一些小网站私自盗用原文,请支持原创 原文永久链 ... -
Lucene4.3开发之第三步之温故知新(三)
2013-08-07 18:30 4979前面几篇笔者已经把Lucene的最基本的入门,介绍完了,本篇就 ... -
Lucene4.3开发之第二步初入修真(二)
2013-07-29 18:23 7970上次笔者简单介绍下了,Lucene的入门搭建以及一个添加的De ... -
Lucene4.3开发之第一步小试牛刀(一)
2013-07-25 16:47 8236首页,本篇适合对于刚 ... -
lucene开发序幕曲之luke神器
2013-07-25 11:28 8325lucene是一款很优秀的全 ... -
lucene4.x的分组实现
2013-06-24 11:51 4505lucene在4.x之前,没有实现分组的功能,如果业务中有需要 ... -
solr4.2的入门部署
2013-06-24 11:00 2814solr 4.2的入门配置 第一步,从官网上下载下 ...
相关推荐
Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。Lucene是一套用于全文检索和搜寻的开源程式库,由Apache软件基金会...
lucene4.3增删改查的的一个工具类,对新手来说是一份不可多得的入门资料。
全文检索lucene 4.3 所用到的3个jar包,包含lucene-queryparser-4.3.0.jar、 lucene-core-4.3.0.jar、lucene-analyzers-common-4.3.0.jar。
lucene4.3 按坐标距离排序,里面写了个简单的例子。运行就行
lucene4.3源代码 censed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information ...
使用lucene需要检索时,需要导入jar包,下载全资源文件,进去找就可以
1.XunTa是在lucene4.3上创建的通过“知识点”来找人的搜人引擎。 输入一个关键词(或组合),XunTa返回一个排名列表,排在前面的人是与该关键词(组合)最相关的“达人”。 可访问 http://www.xunta.so立即体验...
关于lucene的IKAnalyzer分词器以及与lucene4.3共同使用时发生的问题解决包
基于lucene的开发JavaEE项目 基于lucene的开发JavaEE项目 基于lucene的开发JavaEE项目 基于lucene的开发JavaEE项目 基于lucene的开发JavaEE项目
Lucene3.4开发入门.pdf
lucene应用开发揭秘 第四讲
Lucene开发详解.pdf,详细介绍Lucene的开发
Lucene.net开发最全文档 包含英文原api + 中文api
lucene2.9开发指南是为了帮助初级开发人员而编写整理的资料,包括了所有的核心技术,希望对大家有帮助
Lucene开发手册
lucene 的开发包6.6
搜索引擎 lucene开发流程介绍,开发全文检索系统,
闲着无聊做的lucene的知识管理,基本的lucene的用法都有。
Lucene搜索引擎开发权威经典(附盘源码)【于天恩】.zip
教大家使用lucene进行简单的开发,贴出了主要的源码和注释.