自己动手实现 lucene 搜索代码高亮显示

Lucene高亮显示实现
本文介绍了一种在Lucene搜索结果中实现自定义高亮显示的方法,通过去除HTML标签、匹配关键词并高亮显示,同时对高亮后的文本进行分割重组以优化展示效果。

lucene 搜索时候,为增加用户体验一般都会加代码高亮显示, lucene提供了代码高亮显示的插件--highlighter  这个插件相信很多人都用过,所以此处我们不做讨论,我们这里自己写代码实现类似的效果,经过努力俺实现了.

 

这里我先说说我的思路 最后上代码:

1.首先将搜索结果过滤掉所有的html标签,搜索结果里如果包含标签对于截取字符长度等非常麻烦,甚至会造成你的页面结构混乱,所以索性全部过滤掉.

2.在符合搜索关键字的地方套红  比如 搜索:"博客园,程序员的家园",搜索博客园 套红后的结果就是 "<font color=red>博客园</font>,程序员的家园"

3.对套红后的字符串进行分割得到String[] ,这里要说明下分割的方式 比如 abcd  假如我们用 b作为分割点 则分割后的结果是 string[0] = a  ;string[1]= cd

而我这里所说的分割要得到的结果是:string[0] = a  ;string[1]= bcd  也就是分割点包含在数组中,这里是关键.

4.将分割的各个段合并得到结果.

 

以上就是我的思路 怎么? 是不是看到迷迷糊糊啊,呵呵 我的文笔有限啊 可能说的不清楚,我们来套着代码说:

     protected String startTag =   " <font color=red> " ;
    
protected String endTag =   " </font> " ;

 这里就是定义套红的方式 我这里不啰嗦了

     protected int maxNumFragmentsRequired = 40 ;
    
protected int maxNumFragmentsRequired = 5 ;

 这里定义分割后每段最大长度和最多显示几段,应该能够理解吧

 

protected  String PatternText  = " (?=(?: " + startTag + " [\\s\\S]+? " + endTag + " )+) " ;;

 这里可是关键哦 呵呵 这个正则的作用就是来分割字符串用的.

 


public  String gettextfragmenter(String input)
    {

      //最多保留几段

        int _maxNumFragmentsRequired = maxNumFragmentsRequired;

        String result = "";

 

        Pattern pattern = Pattern.compile(PatternText,Pattern.MULTILINE);        

//使用上面定义的正则将文本分割,关键部分

        String[] textfragmenter = pattern.split(input);

//如果定义的段数大于分割后的实际段数

         if (textfragmenter.length < _maxNumFragmentsRequired)
        {
            _maxNumFragmentsRequired 
=  textfragmenter.length;

        }

//下面一个循环将结果重组成我们需要的结果

         for ( int  i = 0 ;i < _maxNumFragmentsRequired;i ++ )
        {
            String str 
=  textfragmenter[i].length() > textFragmenterlegth  ?  textfragmenter[i].substring( 0 , textFragmenterlegth) + " " : textfragmenter[i];
            result 
+= str;
        }
        
return  result;        
    }

    //doc :document fields:搜索的fieldsname的集合 words:搜索的关键词集合

    public  Document highlighter(Document doc,String[] fields,String[] words)
    {
        
if (words != null )
        {
            String deleteTag 
=  endTag  +  startTag;
            String[] hlwords 
=   new  String[words.length];
            
for ( int  i = 0 ;i < words.length;i ++ )
            {
                hlwords[i] 
=  startTag  +  words[i]  +  endTag;
            }
            
            
for (String field : fields)
            {    
                
int  j = 0 ;

                Field fField = doc.getField(field);

//这里就是我说的替换掉所有的html标签

                String value  =  fField.stringValue().replaceAll( " <[^>]+>|&[^;]+; " , "" );
                
for ( int  i = 0 ;i < words.length;i ++ )
                {
                    
if (value  !=   null   &&  value.length()  >  words[i].length()) {
                        value 
=  value.replaceAll(words[i],hlwords[i]);
                        j
++ ;
                    }
                }
                
if (j  >   0 ) {

                    if(j > 1) value = value.replaceAll(deleteTag, "");

//调用我说 的分割重组方法

                    value  =  gettextfragmenter(value);
                    fField.setValue(value);
                }
            }
        }
        
return  doc;
    }


public String gettextfragmenter(String input)
    {
        
int _maxNumFragmentsRequired = maxNumFragmentsRequired;
        String result 
= "";
        Pattern pattern 
= Pattern.compile(PatternText,Pattern.MULTILINE);        
        String[] textfragmenter 
= pattern.split(input);
        
if(textfragmenter.length<_maxNumFragmentsRequired)
        {
            _maxNumFragmentsRequired 
= textfragmenter.length;
        }
        
for(int i=0;i<_maxNumFragmentsRequired;i++)
        {
            String str 
= textfragmenter[i].length()>textFragmenterlegth ? textfragmenter[i].substring(0, textFragmenterlegth)+"": textfragmenter[i];
            result 
+=str;
        }
        
return result;        
    }
    
    
public Document highlighter(Document doc,String[] fields,String[] words)
    {
        
if(words!=null)
        {
            String deleteTag 
= endTag + startTag;
            String[] hlwords 
= new String[words.length];
            
for(int i=0;i<words.length;i++)
            {
                hlwords[i] 
= startTag + words[i] + endTag;
            }
            
            
for(String field : fields)
            {    
                
int j=0;
                Field fField 
= doc.getField(field);
                String value 
= fField.stringValue().replaceAll("<[^>]+>|&[^;]+;","");
                
for(int i=0;i<words.length;i++)
                {
                    
if(value != null && value.length() > words[i].length()) {
                        value 
= value.replaceAll(words[i],hlwords[i]);
                        j
++;
                    }
                }
                
if(j > 0) {
                    
if(j > 1) value = value.replaceAll(deleteTag, "");
                    value 
= gettextfragmenter(value);
                    fField.setValue(value);
                }
            }
        }
        
return doc;
    }

 

OK 就是这样了 我认为需要加注释的地方,我也都加了注释了.怎么样这样实现是不是很简单呢,比起 highlighter 来说仅仅两个方法搞定,呵呵自己动手丰衣足食啊

当然我没有测试这样做的性能上会比highlighter快或者慢,因为时间紧迫呵呵 如果哪个兄台测试了麻烦告诉我一声.


下面看看我用的搜索结果的截图:



 

一个四个省略号哦.

有些朋友仅仅使用了套红也就是仅仅replaceall 那样会造成假如你的文本太长 你想substr的时候,很可能你的套红根本没有显示出来 原因很简单 被你cut掉了 呵呵 而这个就不会,可以避免上述情况.

ok 就到这里了

 

 


    protected static final String HL_FORMATER_START_TAG_DEFAAULT = "<font color=red>";
    
protected static final String HL_FORMATER_END_TAG_DEFAAULT = "</font>";

转载于:https://www.cnblogs.com/suyuan/archive/2008/07/30/1256775.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值