使用装饰器模式构建Lucene的搜索

本文介绍装饰器模式在Java IO中的应用,并展示如何利用该模式动态扩展查询功能,实现多种搜索方式,包括前缀、准确、范围及模糊搜索。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

  一、Java IO中的装饰器模式:

     良好的设计模式可以更好的扩充,“开闭原则”是指对新功能开放,对原有代码封闭。我理解为纵向扩展,在尽量不改变原代码的前提下进行扩展新功能,典型的装饰器例子有java IO包中的大家耳熟能详的代码:

     

BufferedReader bufReader=new BufferedReader(new InputStreamReader(new FileInputStream(new File("test.txt")))); 

    我们看上面的一句代码,

    FileInputStream对new File("text.txt")进行了装饰!

    InputStreamReader对FileInputStream进行了装饰!

    BufferedReader对InputStreamReader进行了装饰! 

    我们假设现在对一个文件全部转换成 小写 字母,那么我们需要构购一个,那么上述的代码可 

    以改成:

BufferedReader bufReader=new BufferedReader(new InputStreamReader(new FileInputStream(new FileLowCaseStream(new File("test.txt"))))); 

 

   

二、我们的应用:

     大家都用过51Job找过工作吧,假设现在找工作的Server业务层里有这几个搜索

      1)前缀搜索:如有公司名为“腾迅网络”,那么,应该支持用户输入“腾迅”。(PrefixQuery)

      2)准确搜索:搜索关键字为“java”(TermQuery)

      3)范围搜索:搜索“某天到某到”,(RangeQuery)

     4)模糊搜索:通过公司地址,“深圳”,也能搜索到“腾迅网络”(FuzzyQuery)

 

三、代码如下:

      1)构建一个BaseQuery,主要提供类型一致,它是一个抽象类。

      

public abstract class BaseQuery {
	public abstract BooleanQuery getQuery();
}

   

     2)构建SearchQuery,它是我们上面提到的四种搜索的父类。

     

public abstract class SearchQuery extends BaseQuery {
	
	protected BaseQuery baseQuery;

	public abstract Query setQuery();

	@Override
	public BooleanQuery getQuery() {
		BooleanQuery booleanQuery;
		if (null == baseQuery)
			booleanQuery = new BooleanQuery();
		else
			booleanQuery = baseQuery.getQuery() == null ? new BooleanQuery()
					: baseQuery.getQuery();
		Query query = setQuery();
		booleanQuery.add(query, Occur.MUST);
		return booleanQuery;
	}
}

 

   3)分别构建上面四种搜索:

 

public class FuzzyTemplateQuery extends SearchQuery {

	protected String queryValue;

	protected String attribute;
	@Override
	

 public Query setQuery() {
		return new FuzzyQuery(new Term(attribute,queryValue));
	}

}

   

   上面代码,attribute是存进索引的键,queryValue是客户端输入的搜索的值。

 同样的,构建其它三另的搜索只需重载一下setQuery即可,下面一并给出代码:

 

//前缀搜索,PrefixQuery
	@Override
	public Query setQuery() {
		return new PrefixQuery(new Term(attribute,queryValue));
	}

//准确搜索 TermQuery
	@Override
	public TermQuery setQuery() {
		return new TermQuery(new Term(attribute,queryValue));
	}

//范围搜索,RangeQuery,注意范围搜索有起始值和结束值
	@Override
	public Query setQuery() {
		Term start = new Term(attribute,startValue);
		Term end = new Term(attribute,endValue);
		Query rangeQuery = new RangeQuery(start,end,bound);
		return rangeQuery;
	}

//针对RangeQuery我们还可以加上边界的设定
public BaseQuery setBound(boolean bound) {
		this.bound = bound;
		return this;
	}

 

四、通过四种类型构造查询,如查找公司名称,它继承自PrefixTemplateQuery

 

	public class CorporationQuery extends  prefixQuery {
                           public CompanyQuery(String queryValue, BaseQuery baseQuery) {
		this.attribute = "companyField";//设置索引中的key
		this.queryValue = queryValue;
		this.baseQuery = baseQuery;
	}

               }

  其实做到这一步,就已经很容易了,只需要一个构造函数完成值的设置就行了。其它的就不举例了。分别继承再设值就好了。

 

五、写客户端的代码。

    

BaseQuery base = new CorporationQuery("腾讯",null);

  

    那如果同时要查询腾讯公司的java职位呢?

 

   

BaseQuery base = new CorporationQuery("腾讯",null);
base  = new JobQuery("java",base);

    我们注意到,先构建一个query,搜索“腾讯”公司的,然后再构建JobQuery来装饰CorporationQuery。

    至此我们完成了装饰器来动态增加搜索,尊循了开闭原则。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值