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>";