`
ilovejavaforever
  • 浏览: 164239 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

封装solrj之二次开发

阅读更多

    Solrj已经是很强大的solr客户端了。它本身就包装了httpCliet,以完全对象的方式对solr进行交互。很小很好很强大。
    不过在实际使用中,设置SolrQuery 的过程中,为了设置多个搜索条件和排序规则等等参数,我们往往会陷入并接字符串的地步,实在是很丑陋,不符合面向对象的思想。扩展性几乎为0,。基于这点,开发了一个小东西,我们只需要设置搜索对象,将对象扔给后台就可以了。
    比如,我们搭建的solr服务支持某10个字段的搜索,我们要搜索其中的一些,那么我们只需要传入要搜索的对象POJO,将要搜索的字段内容,set到POJO对象对应额字段即可。

    比如如下一个类:

package org.uppower.tnt.biz.core.manager.blog.dataobject;

/**
 * @author yingmu
 * @version 2010-7-20 下午01:00:55
 */
public class SolrPropertyDO {
	private String auction_id;
	private String opt_tag;
	private String exp_tag;
	private String title;
	private String desc;
	private String brand;
	private String category;
	private String price;
	private String add_prov;
	private String add_city;
	private String quality;
	private String flag;
	private String sales;
	private String sellerrate;
	private String selleruid;
	private String ipv15;

	public String getAuction_id() {
		return auction_id;
	}

	public void setAuction_id(String auctionId) {
		auction_id = auctionId;
	}

    ……

	public String getExp_tag() {
		return exp_tag;
	}

	public void setExp_tag(String expTag) {
		exp_tag = expTag;
	}
}

     那么我们在定义搜索对象时候,就按照如下设置:

SolrPropertyDO propertyDO = new SolrPropertyDO();
		propertyDO.setAdd_city("(杭州AND成都)OR北京");
		propertyDO.setTitle("丝绸OR剪刀");
         ……

     设置排序条件,也是类似的做法:

SolrPropertyDO compositorDO = new SolrPropertyDO();
		compositorDO.setPrice ("desc");
		compositorDO.setQuality ("asc");
         ……

     将定义好的两个对象扔给后面的接口就可以了。

     接口函数querySolrResult传入四个参数,其中包含搜索字段对象,排序条件对象。为了提供类似limit的操作,用于分页查询,提供了startIndex和pageSize。
     函数querySolrResultCount是单纯为了获得搜索条数,配合分页使用。
    以下是定义的接口:

package org.uppower.tnt.biz.core.manager.blog;

import java.util.List;

import org.uppower.tnt.biz.core.manager.isearch.dataobject.SolrPropertyDO;

/**
 * @author yingmu
 * @version 2010-7-20 下午03:51:15
 */
public interface SolrjOperator {

	/**
	 * 获得搜索结果
	 * 
	 * @param propertyDO
	 * @param compositorDO
	 * @param startIndex
	 * @param pageSize
	 * @return
	 * @throws Exception
	 */
	public List<Object> querySolrResult(Object propertyDO,
			Object compositorDO, Long startIndex, Long pageSize)
			throws Exception;

	/**
	 * 获得搜索结果条数
	 * 
	 * @param propertyDO
	 * @param compositorDO
	 * @return
	 * @throws Exception
	 */
	public Long querySolrResultCount(SolrPropertyDO propertyDO,
			Object compositorDO) throws Exception;

}

 

    实现逻辑为,首先将传入的两个实体对象,解析为<K,V>结构的Map当中,将解析完成的Map放入solrj实际的搜索对象当中。返回的对象为solrj的API提供的SolrDocument,其中结果数量为直接返回SolrDocumentList对象的getNumFound()
    具体实现类:

package org.uppower.tnt.biz.core.manager.blog;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.solr.common.SolrDocumentList;

import org.uppower.tnt.biz.core.manager.isearch.common.SolrjCommonUtil;
import org.uppower.tnt.biz.core.manager.isearch.dataobject.SolrPropertyDO;
import org.uppower.tnt.biz.core.manager.isearch.solrj.SolrjQuery;

/**
 * @author yingmu
 * @version 2010-7-20 下午03:51:15
 */
public class DefaultSolrOperator implements SolrjOperator {
	
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	private SolrjQuery solrjQuery;

	public void setSolrjQuery(SolrjQuery solrjQuery) {
		this.solrjQuery = solrjQuery;
	}

	@Override
	public List<Object> querySolrResult(Object propertyDO,
			Object compositorDO, Long startIndex, Long pageSize)
			throws Exception {
		Map<String, String> propertyMap = new TreeMap<String, String>();
		//排序有顺序,使用TreeMap
		Map<String, String> compositorMap = new TreeMap<String, String>();
		try {
			propertyMap = SolrjCommonUtil.getSearchProperty(propertyDO);
			compositorMap = SolrjCommonUtil.getSearchProperty(compositorDO);
		} catch (Exception e) {
			logger.error("SolrjCommonUtil.getSearchProperty() is error !"+ e);
		}
		SolrDocumentList solrDocumentList = solrjQuery.query(propertyMap, compositorMap,
				startIndex, pageSize);
		List<Object> resultList = new ArrayList<Object>();
		for (int i = 0; i < solrDocumentList.size(); i++) {
			resultList.add(solrDocumentList.get(i));
		}
		return resultList;
	}

	@Override
	public Long querySolrResultCount(SolrPropertyDO propertyDO,
			Object compositorDO) throws Exception {
		Map<String, String> propertyMap = new TreeMap<String, String>();
		Map<String, String> compositorMap = new TreeMap<String, String>();
		try {
			propertyMap = SolrjCommonUtil.getSearchProperty(propertyDO);
			compositorMap = SolrjCommonUtil.getSearchProperty(compositorDO);
		} catch (Exception e) {
			logger.error("SolrjCommonUtil.getSearchProperty() is error !" + e);
		}
		SolrDocumentList solrDocument = solrjQuery.query(propertyMap, compositorMap,
				null, null);
		return solrDocument.getNumFound();
	}

}

 

    其中,对象的解析式利用反射原理,将实体对象中不为空的值,以映射的方式,转化为一个Map,其中排序对象在转化的过程中,使用TreeMap,保证其顺序性。
    解析公共类实现如下:

package org.uppower.tnt.biz.core.manager.blog.common;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author yingmu
 * @version 2010-7-20 下午01:07:15
 */
public class SolrjCommonUtil {

	public static Map<String, String> getSearchProperty(Object model)
			throws NoSuchMethodException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException {
		Map<String, String> resultMap = new TreeMap<String, String>();
		// 获取实体类的所有属性,返回Field数组
		Field[] field = model.getClass().getDeclaredFields();
		for (int i = 0; i < field.length; i++) { // 遍历所有属性
			String name = field[i].getName(); // 获取属性的名字
			// 获取属性的类型
			String type = field[i].getGenericType().toString();
			if (type.equals("class java.lang.String")) { // 如果type是类类型,则前面包含"class ",后面跟类名
				Method m = model.getClass().getMethod(
						"get" + UpperCaseField(name));
				String value = (String) m.invoke(model); // 调用getter方法获取属性值
				if (value != null) {
					resultMap.put(name, value);
				}
			}
		}
		return resultMap;
	}

	// 转化字段首字母为大写
	private static String UpperCaseField(String fieldName) {
		fieldName = fieldName.replaceFirst(fieldName.substring(0, 1), fieldName
				.substring(0, 1).toUpperCase());
		return fieldName;
	}

}

 

    搜索直接调用solr客户端solrj,基本逻辑为循环两个解析之后的TreeMap,设置到SolrQuery当中,最后直接调用solrj的API,获得搜索结果。最终将搜索结构以List<Object>的形式返回。
    具体实现:

package org.uppower.tnt.biz.core.manager.blog.solrj;

import java.net.MalformedURLException;
import java.util.Map;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocumentList;

/**
 * @author yingmu
 * @version 2010-7-20 下午02:57:04
 */
public class SolrjQuery {
	private String url;
	private Integer soTimeOut;
	private Integer connectionTimeOut;
	private Integer maxConnectionsPerHost;
	private Integer maxTotalConnections;
	private Integer maxRetries;
	private CommonsHttpSolrServer solrServer = null;
	private final static String ASC = "asc";

	public void init() throws MalformedURLException {
		solrServer = new CommonsHttpSolrServer(url);
		solrServer.setSoTimeout(soTimeOut);
		solrServer.setConnectionTimeout(connectionTimeOut);
		solrServer.setDefaultMaxConnectionsPerHost(maxConnectionsPerHost);
		solrServer.setMaxTotalConnections(maxTotalConnections);
		solrServer.setFollowRedirects(false);
		solrServer.setAllowCompression(true);
		solrServer.setMaxRetries(maxRetries);
	}

	public SolrDocumentList query(Map<String, String> propertyMap,
			Map<String, String> compositorMap, Long startIndex, Long pageSize)
			throws Exception {
		SolrQuery query = new SolrQuery();
		// 设置搜索字段
		if (null == propertyMap) {
			throw new Exception("搜索字段不可为空!");
		} else {
			for (Object o : propertyMap.keySet()) {
				StringBuffer sb = new StringBuffer();
				sb.append(o.toString()).append(":");
				sb.append(propertyMap.get(o));
				String queryString = addBlank2Expression(sb.toString());
				query.setQuery(queryString);
			}
		}
		// 设置排序条件
		if (null != compositorMap) {
			for (Object co : compositorMap.keySet()) {
				if (ASC == compositorMap.get(co)
						|| ASC.equals(compositorMap.get(co))) {
					query.addSortField(co.toString(), SolrQuery.ORDER.asc);
				} else {
					query.addSortField(co.toString(), SolrQuery.ORDER.desc);
				}
			}
		}
		
		if (null != startIndex) {
			query.setStart(Integer.parseInt(String.valueOf(startIndex)));
		}
		if (null != pageSize && 0L != pageSize.longValue()) {
			query.setRows(Integer.parseInt(String.valueOf(pageSize)));
		}
		try {
			QueryResponse qrsp = solrServer.query(query);
			SolrDocumentList docs = qrsp.getResults();
			return docs;
		} catch (Exception e) {
			throw new Exception(e);
		}
	}

	private String addBlank2Expression(String oldExpression) {
		String lastExpression;
		lastExpression = oldExpression.replace("AND", " AND ").replace("NOT",
				" NOT ").replace("OR", " OR ");
		return lastExpression;
	}

	public Integer getMaxRetries() {
		return maxRetries;
	}

	……
      
        public void setMaxTotalConnections(Integer maxTotalConnections) {
		this.maxTotalConnections = maxTotalConnections;
	}
}

 

    整个实现是在Spring的基础上完成的,其中SolrjQuery的init()方法在Spring容器启动是初始化。Init()方法内的属性,也是直接注入的。上层与下层之间也完全用注入的方式解决。具体配置就不贴不出来了,大家都会。
整个代码很简陋,但是几乎支持了你想要搜索的条件设置,而且不会暴露任何与solr相关的内容给上层调用,使整个搜索几乎以sql语言的思想在设置条件。

 

分享到:
评论

相关推荐

    solrj工具类封装

    solrj工具类封装,包括条件批量查询,批量增删改,分段修改。

    solr-solrj-6.1.0

    Solr是一款强大的全文检索服务器,而Solrj则是与之交互的Java API,使得开发人员能够轻松地在Java应用程序中集成Solr的功能。 标题"solr-solrj-6.1.0"表明我们关注的是Solrj的一个特定版本,即6.1.0。这个版本可能...

    solr-solrj-4.10.3.jar和solr-solrj-5.0.0.jar

    在实际开发中,SolrJ通过提供简单的Java接口,使得开发者可以方便地执行以下操作: 1. 创建和管理Solr核心(Collection)。 2. 向Solr服务器发送索引文档,支持单个和批量操作。 3. 执行各种查询,包括基本查询、...

    solr-solrj 5.0.0 demo

    同时,这个版本可能也对错误处理和异常报告进行了优化,以提供更好的开发体验。 在与自建的Solr服务交互时,首先需要在项目中添加Solr-Solrj的依赖。这通常通过Maven或Gradle等构建工具完成。接着,创建`SolrServer...

    SolrJ6.3.0

    在使用 SolrJ 时,开发人员需要将这些库添加到项目的类路径中,以便能够调用 SolrJ 提供的各种类和方法。例如,可以通过 `SolrClient` 接口连接到 Solr 服务器,使用 `SolrInputDocument` 类来构建要索引的文档,...

    快速上手数据挖掘之solr搜索引擎高级教程(Solr集群、KI分词)第07讲 solrj之SolrBean 共6页.pptx

    【课程大纲】第01讲 solr5简介第02讲 solr5之Schema第03讲 solr5之Solrconfig第04讲 solr5单机安装与配置第05讲 solrj基础(一)第06讲 solrj基础(二)第07讲 solrj之SolrBean第08讲 solrj语法详解第09讲 Solrj之...

    快速上手数据挖掘之solr搜索引擎高级教程(Solr集群、KI分词)第09讲 Solrj之Multicore查询共7页.pptx

    【课程大纲】第01讲 solr5简介第02讲 solr5之Schema第03讲 solr5之Solrconfig第04讲 solr5单机安装与配置第05讲 solrj基础(一)第06讲 solrj基础(二)第07讲 solrj之SolrBean第08讲 solrj语法详解第09讲 Solrj之...

    solrJ 需要的jar文件 (全)

    - 在SolrJ的开发或集成过程中,JUnit是必不可少的,因为它可以帮助开发者确保代码的正确性和稳定性。通过编写针对SolrJ功能的测试用例,开发者可以验证SolrJ的各种操作,如建立索引、查询、更新等是否按预期工作。 ...

    solrj的使用

    SolrJ是Apache Solr官方提供的Java客户端库,它...总之,SolrJ是Java开发人员与Solr进行交互的强大工具,它简化了Solr操作并提供了丰富的功能。通过熟练掌握SolrJ,你可以更高效地构建和管理基于Solr的搜索解决方案。

    SolrJ需要的jar包

    SolrJ是Apache Solr官方提供的Java客户端库,它使得Java开发者能够轻松地与Solr搜索引擎进行通信,执行查询、索引文档等操作。SolrJ的使用是大数据环境中实现高效全文检索和数据分析的关键组件。在Java项目中,正确...

    solr配置和solrJ的使用

    #### 二、Solr服务器复制配置 **1. 配置多台Tomcat服务器** - **步骤说明**: 在同一台机器上配置多个Tomcat实例作为Solr服务器。 - **操作详情**: 本例中配置了三台Tomcat服务器,端口分别为80、9888和9008。每...

    快速上手数据挖掘之solr搜索引擎高级教程(Solr集群、KI分词)第06讲 solrj基础(二) 共6页.pptx

    【课程大纲】第01讲 solr5简介第02讲 solr5之Schema第03讲 solr5之Solrconfig第04讲 solr5单机安装与配置第05讲 solrj基础(一)第06讲 solrj基础(二)第07讲 solrj之SolrBean第08讲 solrj语法详解第09讲 Solrj之...

    solr-solrj-4.9.0.jar

    solr-solrj-4.9.0.jar

    solr-solrj-4.10.3.jar

    solr-solrj-4.10.3.jar。

    solrj使用教程

    SolrJ是Apache Solr官方提供的Java客户端库,它使得在Java应用程序中与Solr进行交互变得简单。这个“solrj使用教程”很可能是为了帮助开发者了解如何使用SolrJ来连接、查询和管理Solr索引。下面将详细介绍SolrJ的...

    solr-core-4.6.0.jar solr-solrj-4.6.0.jar

    下载后会获得名为:solr_core.4.6.0 的zip包,解压后会获得solr-core-4.6.0.jar和 solr-solrj-4.6.0.jar两个文件,搭建solr全文检索环境必须要添加的包

    solrJ所需要的核心包

    java大数据开发中solrJ所需要的核心包.................

    solr-solrj-4.4.0.jar

    solr-solrj-4.4.0.jar

    solr-solrj-6.6.0.jar

    solr-solrj-6.6.0.jar

    solrj创建连接工厂

    solr部署在tomcat势必要设置用户权限,所以客户端solrj在创建连接的时候也需要用户名加密码

Global site tag (gtag.js) - Google Analytics