android+lucene实现全文检索并高亮关键字

来源:互联网 发布:网络教育属于什么教育 编辑:程序博客网 时间:2024/05/11 17:01

这里先假设读者对Lucene的使用比较熟悉的。

由于代码量比较多,这里我只写出一些关键的代码,全部源码请到这里下载:

android+lucene实现全文检索并高亮关键字

android+lucene实现全文检索并高亮关键字索引库

请将下载到的索引库解压后放到sdcard根目录下

源码里边的注释写的也比较详细

在andorid里实现字体高亮,若单独实现其实不是很难,但若和lucene结合使用,实现被搜索的关键字高亮,就有些麻烦事。原因在于,关键字高亮是有lucene提供的一个类(Highlighter)来管理。它的实现方式其实很简单,就是将关键字用html标签包裹起来。下边先来看一下几段关键性的代码

1.先定义一对html标签,用两个String常量来保存

[java] view plaincopy
  1. private static final String STARTTAG = "<font color='red'>";  
  2. private static final String ENDTAG = "</font>";  

2.通过SimpleHTMLFormatter类,我们可以设置高亮文本的样式,它返回一个Formatter类

[java] view plaincopy
  1. Formatter formatter = new SimpleHTMLFormatter(STARTTAG, ENDTAG);  

3.设置query对象,在query对象中,有查询的关键字

[java] view plaincopy
  1. Scorer scorer = new QueryScorer(query);  

4.新建一个Highlighter类,并设置参数

[java] view plaincopy
  1. Highlighter highlighter = new Highlighter(formatter, scorer);  
  2. // 设置高亮后的字符长度  
  3. highlighter.setTextFragmenter(new SimpleFragmenter(length));  
5.通过Highlighter类的getBestFragment方法匹配关键字,并将关键字包裹在关键字上
[java] view plaincopy
  1. String result = highlighter.getBestFragment(LuceneConfigurationUtil.getAnalyzer(), null, text);  
注意,这里返回的结果是存放在lucene的Document对象里边的到此就能把出现的关键字高亮起来。如果我们把这结果在浏览器显示,浏览器会帮我们解析这些html标签。但是现在结果是要显示在android上的,android如何解析?我们可以通过android提供的一个Html类来解析(这里我只提供一种解决方案,或许还有更好的解决方案,但限于能力不足,未能给出,若有,望指教)

首先我们需要将Document对象里边的数据转换成我们自定义的对象,先看一段代码

[java] view plaincopy
  1. public static Book DocumentToBook(Document doc) {  
  2.         Book book = new Book();  
  3.         book.setId(Integer.parseInt(doc.get("id")));  
  4.         book.setName(doc.get("name"));  
  5.         book.setFirstTitle(doc.get("firstTitle"));  
  6.         book.setSecondTitle(doc.get("secondTitle"));  
  7.         book.setContent(doc.get("content"));  
  8.         book.setUrl(doc.get("url"));  
  9.         return book;  
  10.     }  
这个方法就是把Document对象转换成我们自定义的Book对象,有了这个Book对象后,我们就可以取出book里边的属性值,用Html类的fromHtml()方法来解析html标签,先看段代码
[java] view plaincopy
  1. this.nameTv.setText(Html.fromHtml(name));  
  2. this.firstTitleTv.setText(Html.fromHtml(firstTitle));  
  3. this.secondTitleTv.setText(Html.fromHtml(secondTitle));  
  4. this.contentTv.setText(Html.fromHtml(content));  

这样进过解析的文本信息就可以直接放到Textview中,并在Activity中显示

这是运行的效果图:




安静我要说的还没有完呢,从上边的显示结果可以看出,搜索出来的结果集是放在ListView中的。如果我们用简单的SimpleAdapter来装载ListView是不能实现高亮的。这时候我们需要自定义一个适配器,先看一下代码

[java] view plaincopy
  1. public class ListViewAdapter extends BaseAdapter {  
  2.   
  3.     private Context context = null;  
  4.     private ArrayList<HashMap<String, Object>> listItem = null;  
  5.     private TextView nameTv = null;  
  6.     private TextView firstTitleTv = null;  
  7.     private TextView secondTitleTv = null;  
  8.     private TextView contentTv = null;  
  9.   
  10.     public ListViewAdapter(Context context,  
  11.             ArrayList<HashMap<String, Object>> listItem) {  
  12.         super();  
  13.         this.context = context;  
  14.         this.listItem = listItem;  
  15.     }  
  16.   
  17.     @Override  
  18.     public int getCount() {  
  19.         return listItem.size();  
  20.   
  21.     }  
  22.   
  23.     @Override  
  24.     public Object getItem(int arg0) {  
  25.         return listItem.get(arg0);  
  26.   
  27.     }  
  28.   
  29.     @Override  
  30.     public long getItemId(int position) {  
  31.         return position;  
  32.     }  
  33.   
  34.     @Override  
  35.     public View getView(int position, View convertView, ViewGroup parent) {  
  36.         // 取出数据  
  37.         String name = listItem.get(position).get("name").toString();  
  38.         String firstTitle = listItem.get(position).get("firstTitle").toString();  
  39.         String secondTitle = listItem.get(position).get("secondTitle")  
  40.                 .toString();  
  41.         String content = listItem.get(position).get("content").toString();  
  42.         View view;  
  43.   
  44.         // 获取四个Textview控件  
  45.         if (convertView == null) {  
  46.             RelativeLayout relativeLayout = (RelativeLayout) View.inflate(  
  47.                     context, R.layout.law_item, null);  
  48.             this.nameTv = (TextView) relativeLayout.findViewById(R.id.name);  
  49.             this.firstTitleTv = (TextView) relativeLayout  
  50.                     .findViewById(R.id.firstTitle);  
  51.             this.secondTitleTv = (TextView) relativeLayout  
  52.                     .findViewById(R.id.secondTitle);  
  53.             this.contentTv = (TextView) relativeLayout  
  54.                     .findViewById(R.id.content);  
  55.   
  56.             view = relativeLayout;  
  57.         } else {  
  58.             view = convertView;  
  59.   
  60.             this.nameTv = (TextView) view.findViewById(R.id.name);  
  61.             this.firstTitleTv = (TextView) view.findViewById(R.id.firstTitle);  
  62.             this.secondTitleTv = (TextView) view.findViewById(R.id.secondTitle);  
  63.             this.contentTv = (TextView) view.findViewById(R.id.content);  
  64.         }  
  65.   
  66.         // 解析在LuceneConfigurationUtil设置的html格式代码  
  67.         this.nameTv.setText(Html.fromHtml(name));  
  68.         this.firstTitleTv.setText(Html.fromHtml(firstTitle));  
  69.         this.secondTitleTv.setText(Html.fromHtml(secondTitle));  
  70.         this.contentTv.setText(Html.fromHtml(content));  
  71.           
  72.         return view;  
  73.     }  
  74.   
  75. }  

自定义适配器继承了BaseAdapter抽象类。我们这么做目的是通过重写getView()方法来获取当前的view,,进而获取到view下边的各个控件,最后才能执行那段解析html格式的代码大笑

好啦,说到这里就差不多了,具体的就看我上传的源码吧。

多说几句,这里侧重的是功能的实现,对于lucene的索引库我没有去做怎样的优化。还有,分词器用的是中国人自己开发的IKAnalyzer。老外的太蛋疼了,用过lucene的人,你们懂的。。。。

给些下载连接   

lucene-3.0.0

IKAnalyzer3.2.8


0 0
原创粉丝点击