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

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

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

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

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

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

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

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

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

private static final String STARTTAG = "";
private static final String ENDTAG = "";

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

Formatter formatter = new SimpleHTMLFormatter(STARTTAG, ENDTAG);

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

Scorer scorer = new QueryScorer(query);

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

Highlighter highlighter = new Highlighter(formatter, scorer);
// 设置高亮后的字符长度
highlighter.setTextFragmenter(new SimpleFragmenter(length));

5.通过Highlighter类的getBestFragment方法匹配关键字,并将关键字包裹在关键字上

String result = highlighter.getBestFragment(LuceneConfigurationUtil.getAnalyzer(), null, text);
注意,这里返回的结果是存放在lucene的Document对象里边的

到此就能把出现的关键字高亮起来。如果我们把这结果在浏览器显示,浏览器会帮我们解析这些html标签。但是现在结果是要显示在android上的,android如何解析?我们可以通过android提供的一个Html类来解析(这里我只提供一种解决方案,或许还有更好的解决方案,但限于能力不足,未能给出,若有,望指教)

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

public static Book DocumentToBook(Document doc) {
		Book book = new Book();
		book.setId(Integer.parseInt(doc.get("id")));
		book.setName(doc.get("name"));
		book.setFirstTitle(doc.get("firstTitle"));
		book.setSecondTitle(doc.get("secondTitle"));
		book.setContent(doc.get("content"));
		book.setUrl(doc.get("url"));
		return book;
	}
这个方法就是把Document对象转换成我们自定义的Book对象,有了这个Book对象后,我们就可以取出book里边的属性值,用Html类的fromHtml()方法来解析html标签,先看段代码

		this.nameTv.setText(Html.fromHtml(name));
		this.firstTitleTv.setText(Html.fromHtml(firstTitle));
		this.secondTitleTv.setText(Html.fromHtml(secondTitle));
		this.contentTv.setText(Html.fromHtml(content));

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

这是运行的效果图:

android+lucene实现全文检索并高亮关键字_第1张图片

android+lucene实现全文检索并高亮关键字_第2张图片

android+lucene实现全文检索并高亮关键字_第3张图片

android+lucene实现全文检索并高亮关键字_第4张图片


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

public class ListViewAdapter extends BaseAdapter {

	private Context context = null;
	private ArrayList> listItem = null;
	private TextView nameTv = null;
	private TextView firstTitleTv = null;
	private TextView secondTitleTv = null;
	private TextView contentTv = null;

	public ListViewAdapter(Context context,
			ArrayList> listItem) {
		super();
		this.context = context;
		this.listItem = listItem;
	}

	@Override
	public int getCount() {
		return listItem.size();

	}

	@Override
	public Object getItem(int arg0) {
		return listItem.get(arg0);

	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// 取出数据
		String name = listItem.get(position).get("name").toString();
		String firstTitle = listItem.get(position).get("firstTitle").toString();
		String secondTitle = listItem.get(position).get("secondTitle")
				.toString();
		String content = listItem.get(position).get("content").toString();
		View view;

		// 获取四个Textview控件
		if (convertView == null) {
			RelativeLayout relativeLayout = (RelativeLayout) View.inflate(
					context, R.layout.law_item, null);
			this.nameTv = (TextView) relativeLayout.findViewById(R.id.name);
			this.firstTitleTv = (TextView) relativeLayout
					.findViewById(R.id.firstTitle);
			this.secondTitleTv = (TextView) relativeLayout
					.findViewById(R.id.secondTitle);
			this.contentTv = (TextView) relativeLayout
					.findViewById(R.id.content);

			view = relativeLayout;
		} else {
			view = convertView;

			this.nameTv = (TextView) view.findViewById(R.id.name);
			this.firstTitleTv = (TextView) view.findViewById(R.id.firstTitle);
			this.secondTitleTv = (TextView) view.findViewById(R.id.secondTitle);
			this.contentTv = (TextView) view.findViewById(R.id.content);
		}

		// 解析在LuceneConfigurationUtil设置的html格式代码
		this.nameTv.setText(Html.fromHtml(name));
		this.firstTitleTv.setText(Html.fromHtml(firstTitle));
		this.secondTitleTv.setText(Html.fromHtml(secondTitle));
		this.contentTv.setText(Html.fromHtml(content));
		
		return view;
	}

}

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

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

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

给些下载连接   

lucene-3.0.0

IKAnalyzer3.2.8










你可能感兴趣的:(android,android,全文检索,高亮,字体,lucene)