在Lucene或Solr中实现高亮的策略

Posted 我是攻城师

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在Lucene或Solr中实现高亮的策略相关的知识,希望对你有一定的参考价值。

一:功能背景

最近要做个高亮的搜索需求,以前也搞过,所以没啥难度,只不过原来用的是Lucene,现在要换成Solr而已,在Lucene4.x的时候,散仙在以前的文章中也分析过如何在搜索的时候实现高亮,主要有三种方式,具体内容,请参考散仙以前的2篇文章:
第一:在Lucene4.3中实现高亮的方式
http://qindongliang.iteye.com/blog/1953409
第二:在Solr4.3中服务端高亮的方式
http://qindongliang.iteye.com/blog/2034270



二:方案探究

从整体来讲,主要有2种实现方式,第一就是前台展示数据时使用js高亮,第二就是服务端高亮后返回给前台

后端高亮的流程:



前端高亮的流程:

在Lucene或Solr中实现高亮的策略


三:优劣分析

后端高亮:
性能:并发量大的情况下,可能对服务器的性能造成一定影响。
可靠性:高,在浏览器禁用js脚本情况下,仍可以正常显示
前端高亮:
性能:由客户端渲染,相对性能稍高
可靠性:低,在浏览器禁用js脚本情况下,高亮失效

四:注意事项

前台高亮时,需要把句子分词后的词组,返回给前台js,便于正则替换,关于把句子分词,可以用lucene也可以用solr,方式分别如下(代码显示比较乱,可以直接点击底部左下角阅读原文):
在Lucene中:

Java代码 在Lucene或Solr中实现高亮的策略 在Lucene或Solr中实现高亮的策略在Lucene或Solr中实现高亮的策略

  1. /***

  2. *

  3. * @param analyzer 分词器

  4. * @param text 分词句子

  5. * @throws Exception

  6. */

  7. public static void analyzer(Analyzer analyzer,String text)throws Exception{

  8. TokenStream ts = analyzer.tokenStream("name",text);

  9. CharTermAttribute term=ts.addAttribute(CharTermAttribute.class);

  10. ts.reset();

  11. while(ts.incrementToken()){

  12. System.out.println(term.toString());

  13. }

  14. ts.end();

  15. ts.close();

  16. }

/***
	 * 
	 * @param analyzer 分词器
	 * @param text  分词句子
	 * @throws Exception
	 */
	public static void analyzer(Analyzer analyzer,String text)throws Exception{
		        TokenStream ts = analyzer.tokenStream("name",text);
		        CharTermAttribute term=ts.addAttribute(CharTermAttribute.class);
		        ts.reset();
		        while(ts.incrementToken()){
		            System.out.println(term.toString());
		        }
		        ts.end();
		        ts.close();
	}



在solr中,方式1:

Java代码 在Lucene或Solr中实现高亮的策略 在Lucene或Solr中实现高亮的策略在Lucene或Solr中实现高亮的策略

  1. /***

  2. * 根据字段类型分词并打印分词结果

  3. * @param text

  4. */

  5. public static void showAnalysisType(String text)throws Exception{

  6. String fieldType="ik";//分词类型

  7. //调用服务

  8. FieldAnalysisRequest request = new FieldAnalysisRequest("/analysis/field");

  9. //设置类型

  10. request.addFieldType(fieldType);

  11. //设置待分词的句子

  12. request.setFieldValue(text);

  13. //sc=private static HttpSolrClient sc=new HttpSolrClient("http://localhost:8983/solr/one");

  14. //得到结果

  15. FieldAnalysisResponse response =request.process(sc);

  16. //得到对应的Analysis

  17. Analysis as = response.getFieldTypeAnalysis(fieldType);

  18. List<String> results = new ArrayList<String>();

  19. //使用guava的库,将iteratro对象转换为List对象

  20. List<AnalysisPhase> list=Lists.newArrayList(as.getIndexPhases().iterator());

  21. //取某一个fitler的分词结果,因为一个fieldtype很有可能配置了多个filter,每一步经过

  22. //filter的结果都不一样,所以此处,要指定一个获取分词结果的filter,跟因为有关

  23. //所以散仙这里就写list.size-1了,注意此处的值,并不是固定的

  24. for(TokenInfo token:list.get(list.size()-1).getTokens()){

  25. //得到分词数据结果

  26. results.add(token.getText());

  27. }

  28. }

	/***
	 * 根据字段类型分词并打印分词结果
	 * @param text
	 */
	public static void showAnalysisType(String text)throws Exception{
	
		String fieldType="ik";//分词类型
		//调用服务
		FieldAnalysisRequest request = new FieldAnalysisRequest("/analysis/field");
		//设置类型
		request.addFieldType(fieldType);
		//设置待分词的句子 
		request.setFieldValue(text);
		//sc=private static HttpSolrClient sc=new HttpSolrClient("http://localhost:8983/solr/one");
		//得到结果
	    FieldAnalysisResponse response =request.process(sc);
	    //得到对应的Analysis
	    Analysis as = response.getFieldTypeAnalysis(fieldType);
	    List<String> results = new ArrayList<String>();
	    //使用guava的库,将iteratro对象转换为List对象
        List<AnalysisPhase> list=Lists.newArrayList(as.getIndexPhases().iterator());
        //取某一个fitler的分词结果,因为一个fieldtype很有可能配置了多个filter,每一步经过
        //filter的结果都不一样,所以此处,要指定一个获取分词结果的filter,跟因为有关
        //所以散仙这里就写list.size-1了,注意此处的值,并不是固定的
	     for(TokenInfo token:list.get(list.size()-1).getTokens()){
	    	 //得到分词数据结果
	    	 results.add(token.getText());
	     }
	     
	}



在solr中,方式2:

Java代码 在Lucene或Solr中实现高亮的策略 在Lucene或Solr中实现高亮的策略

  1. /***

  2. * 根据字段名分词并打印分词结果

  3. * @param text

  4. */

  5. public static void showAnalysis(String text)throws Exception{

  6. //此处是字段名

  7. String fieldName="cpyName";

  8. //固定写法

  9. FieldAnalysisRequest request = new FieldAnalysisRequest("/analysis/field");

  10. //添加field

  11. request.addFieldName(fieldName);

  12. //设置需要分词的句子

  13. request.setFieldValue(text);

  14. //请求solr服务得到结果

  15. FieldAnalysisResponse response =request.process(sc);

  16. //封装结果,返回,可能供其后续调用的业务处理

  17. List<String> results = new ArrayList<String>();

  18. //根据字段名获取结果

  19. Analysis as=response.getFieldNameAnalysis(fieldName);

  20. //使用guava工具包,转iterator为List

  21. List<AnalysisPhase> list=Lists.newArrayList(as.getIndexPhases().iterator());

  22. //打印分词结果

  23. for(TokenInfo token:list.get(list.size()-1).getTokens()){

  24. System.out.println(token.getText());

  25. }

  26. }

/***
	 * 根据字段名分词并打印分词结果
	 * @param text
	 */
	public static void showAnalysis(String text)throws Exception{
		 //此处是字段名
		 String fieldName="cpyName";
		 //固定写法
		 FieldAnalysisRequest request = new FieldAnalysisRequest("/analysis/field");
		 //添加field
		 request.addFieldName(fieldName);
		 //设置需要分词的句子
		 request.setFieldValue(text);
		 //请求solr服务得到结果
	     FieldAnalysisResponse response =request.process(sc);
	     //封装结果,返回,可能供其后续调用的业务处理
	     List<String> results = new ArrayList<String>();
	     //根据字段名获取结果 
	     Analysis as=response.getFieldNameAnalysis(fieldName);
	     //使用guava工具包,转iterator为List
	     List<AnalysisPhase> list=Lists.newArrayList(as.getIndexPhases().iterator());
	     //打印分词结果
	     for(TokenInfo token:list.get(list.size()-1).getTokens()){
	    	 System.out.println(token.getText());
	     }
	     
	}


以上是关于在Lucene或Solr中实现高亮的策略的主要内容,如果未能解决你的问题,请参考以下文章

Solr、sunburnt (python) 和高亮显示:操作方法?

Solr 高亮是不是还可以指示返回的片段在原始字段中的位置或偏移量?

lucene和solr的区别

solr和lucene是什么关系

选择 solr/lucene 提交策略

教你使用solr搭建你的全文检索