封装solrj之二次开发

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

    比如如下一个类:

Java代码   收藏代码
  1. package org.uppower.tnt.biz.core.manager.blog.dataobject;  
  2.   
  3. /** 
  4.  * @author yingmu 
  5.  * @version 2010-7-20 下午01:00:55 
  6.  */  
  7. public class SolrPropertyDO {  
  8.     private String auction_id;  
  9.     private String opt_tag;  
  10.     private String exp_tag;  
  11.     private String title;  
  12.     private String desc;  
  13.     private String brand;  
  14.     private String category;  
  15.     private String price;  
  16.     private String add_prov;  
  17.     private String add_city;  
  18.     private String quality;  
  19.     private String flag;  
  20.     private String sales;  
  21.     private String sellerrate;  
  22.     private String selleruid;  
  23.     private String ipv15;  
  24.   
  25.     public String getAuction_id() {  
  26.         return auction_id;  
  27.     }  
  28.   
  29.     public void setAuction_id(String auctionId) {  
  30.         auction_id = auctionId;  
  31.     }  
  32.   
  33.     ……  
  34.   
  35.     public String getExp_tag() {  
  36.         return exp_tag;  
  37.     }  
  38.   
  39.     public void setExp_tag(String expTag) {  
  40.         exp_tag = expTag;  
  41.     }  
  42. }  

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

Java代码   收藏代码
  1. SolrPropertyDO propertyDO = new SolrPropertyDO();  
  2.         propertyDO.setAdd_city("(杭州AND成都)OR北京");  
  3.         propertyDO.setTitle("丝绸OR剪刀");  
  4.          ……  

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

Java代码   收藏代码
  1. SolrPropertyDO compositorDO = new SolrPropertyDO();  
  2.         compositorDO.setPrice ("desc");  
  3.         compositorDO.setQuality ("asc");  
  4.          ……  

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

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

Java代码   收藏代码
  1. package org.uppower.tnt.biz.core.manager.blog;  
  2.   
  3. import java.util.List;  
  4.   
  5. import org.uppower.tnt.biz.core.manager.isearch.dataobject.SolrPropertyDO;  
  6.   
  7. /** 
  8.  * @author yingmu 
  9.  * @version 2010-7-20 下午03:51:15 
  10.  */  
  11. public interface SolrjOperator {  
  12.   
  13.     /** 
  14.      * 获得搜索结果 
  15.      *  
  16.      * @param propertyDO 
  17.      * @param compositorDO 
  18.      * @param startIndex 
  19.      * @param pageSize 
  20.      * @return 
  21.      * @throws Exception 
  22.      */  
  23.     public List<Object> querySolrResult(Object propertyDO,  
  24.             Object compositorDO, Long startIndex, Long pageSize)  
  25.             throws Exception;  
  26.   
  27.     /** 
  28.      * 获得搜索结果条数 
  29.      *  
  30.      * @param propertyDO 
  31.      * @param compositorDO 
  32.      * @return 
  33.      * @throws Exception 
  34.      */  
  35.     public Long querySolrResultCount(SolrPropertyDO propertyDO,  
  36.             Object compositorDO) throws Exception;  
  37.   
  38. }  

 

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

Java代码   收藏代码
  1. package org.uppower.tnt.biz.core.manager.blog;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.HashMap;  
  5. import java.util.List;  
  6. import java.util.Map;  
  7. import java.util.TreeMap;  
  8.   
  9. import org.apache.solr.common.SolrDocumentList;  
  10.   
  11. import org.uppower.tnt.biz.core.manager.isearch.common.SolrjCommonUtil;  
  12. import org.uppower.tnt.biz.core.manager.isearch.dataobject.SolrPropertyDO;  
  13. import org.uppower.tnt.biz.core.manager.isearch.solrj.SolrjQuery;  
  14.   
  15. /** 
  16.  * @author yingmu 
  17.  * @version 2010-7-20 下午03:51:15 
  18.  */  
  19. public class DefaultSolrOperator implements SolrjOperator {  
  20.       
  21.     private Logger logger = LoggerFactory.getLogger(this.getClass());  
  22.     private SolrjQuery solrjQuery;  
  23.   
  24.     public void setSolrjQuery(SolrjQuery solrjQuery) {  
  25.         this.solrjQuery = solrjQuery;  
  26.     }  
  27.   
  28.     @Override  
  29.     public List<Object> querySolrResult(Object propertyDO,  
  30.             Object compositorDO, Long startIndex, Long pageSize)  
  31.             throws Exception {  
  32.         Map<String, String> propertyMap = new TreeMap<String, String>();  
  33.         //排序有顺序,使用TreeMap  
  34.         Map<String, String> compositorMap = new TreeMap<String, String>();  
  35.         try {  
  36.             propertyMap = SolrjCommonUtil.getSearchProperty(propertyDO);  
  37.             compositorMap = SolrjCommonUtil.getSearchProperty(compositorDO);  
  38.         } catch (Exception e) {  
  39.             logger.error("SolrjCommonUtil.getSearchProperty() is error !"+ e);  
  40.         }  
  41.         SolrDocumentList solrDocumentList = solrjQuery.query(propertyMap, compositorMap,  
  42.                 startIndex, pageSize);  
  43.         List<Object> resultList = new ArrayList<Object>();  
  44.         for (int i = 0; i < solrDocumentList.size(); i++) {  
  45.             resultList.add(solrDocumentList.get(i));  
  46.         }  
  47.         return resultList;  
  48.     }  
  49.   
  50.     @Override  
  51.     public Long querySolrResultCount(SolrPropertyDO propertyDO,  
  52.             Object compositorDO) throws Exception {  
  53.         Map<String, String> propertyMap = new TreeMap<String, String>();  
  54.         Map<String, String> compositorMap = new TreeMap<String, String>();  
  55.         try {  
  56.             propertyMap = SolrjCommonUtil.getSearchProperty(propertyDO);  
  57.             compositorMap = SolrjCommonUtil.getSearchProperty(compositorDO);  
  58.         } catch (Exception e) {  
  59.             logger.error("SolrjCommonUtil.getSearchProperty() is error !" + e);  
  60.         }  
  61.         SolrDocumentList solrDocument = solrjQuery.query(propertyMap, compositorMap,  
  62.                 nullnull);  
  63.         return solrDocument.getNumFound();  
  64.     }  
  65.   
  66. }  

 

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

Java代码   收藏代码
  1. package org.uppower.tnt.biz.core.manager.blog.common;  
  2.   
  3. import java.lang.reflect.Field;  
  4. import java.lang.reflect.InvocationTargetException;  
  5. import java.lang.reflect.Method;  
  6. import java.util.HashMap;  
  7. import java.util.Map;  
  8.   
  9. /** 
  10.  * @author yingmu 
  11.  * @version 2010-7-20 下午01:07:15 
  12.  */  
  13. public class SolrjCommonUtil {  
  14.   
  15.     public static Map<String, String> getSearchProperty(Object model)  
  16.             throws NoSuchMethodException, IllegalAccessException,  
  17.             IllegalArgumentException, InvocationTargetException {  
  18.         Map<String, String> resultMap = new TreeMap<String, String>();  
  19.         // 获取实体类的所有属性,返回Field数组  
  20.         Field[] field = model.getClass().getDeclaredFields();  
  21.         for (int i = 0; i < field.length; i++) { // 遍历所有属性  
  22.             String name = field[i].getName(); // 获取属性的名字  
  23.             // 获取属性的类型  
  24.             String type = field[i].getGenericType().toString();  
  25.             if (type.equals("class java.lang.String")) { // 如果type是类类型,则前面包含"class ",后面跟类名  
  26.                 Method m = model.getClass().getMethod(  
  27.                         "get" + UpperCaseField(name));  
  28.                 String value = (String) m.invoke(model); // 调用getter方法获取属性值  
  29.                 if (value != null) {  
  30.                     resultMap.put(name, value);  
  31.                 }  
  32.             }  
  33.         }  
  34.         return resultMap;  
  35.     }  
  36.   
  37.     // 转化字段首字母为大写  
  38.     private static String UpperCaseField(String fieldName) {  
  39.         fieldName = fieldName.replaceFirst(fieldName.substring(01), fieldName  
  40.                 .substring(01).toUpperCase());  
  41.         return fieldName;  
  42.     }  
  43.   
  44. }  

 

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

Java代码   收藏代码
  1. package org.uppower.tnt.biz.core.manager.blog.solrj;  
  2.   
  3. import java.net.MalformedURLException;  
  4. import java.util.Map;  
  5.   
  6. import org.apache.solr.client.solrj.SolrQuery;  
  7. import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;  
  8. import org.apache.solr.client.solrj.response.QueryResponse;  
  9. import org.apache.solr.common.SolrDocumentList;  
  10.   
  11. /** 
  12.  * @author yingmu 
  13.  * @version 2010-7-20 下午02:57:04 
  14.  */  
  15. public class SolrjQuery {  
  16.     private String url;  
  17.     private Integer soTimeOut;  
  18.     private Integer connectionTimeOut;  
  19.     private Integer maxConnectionsPerHost;  
  20.     private Integer maxTotalConnections;  
  21.     private Integer maxRetries;  
  22.     private CommonsHttpSolrServer solrServer = null;  
  23.     private final static String ASC = "asc";  
  24.   
  25.     public void init() throws MalformedURLException {  
  26.         solrServer = new CommonsHttpSolrServer(url);  
  27.         solrServer.setSoTimeout(soTimeOut);  
  28.         solrServer.setConnectionTimeout(connectionTimeOut);  
  29.         solrServer.setDefaultMaxConnectionsPerHost(maxConnectionsPerHost);  
  30.         solrServer.setMaxTotalConnections(maxTotalConnections);  
  31.         solrServer.setFollowRedirects(false);  
  32.         solrServer.setAllowCompression(true);  
  33.         solrServer.setMaxRetries(maxRetries);  
  34.     }  
  35.   
  36.     public SolrDocumentList query(Map<String, String> propertyMap,  
  37.             Map<String, String> compositorMap, Long startIndex, Long pageSize)  
  38.             throws Exception {  
  39.         SolrQuery query = new SolrQuery();  
  40.         // 设置搜索字段  
  41.         if (null == propertyMap) {  
  42.             throw new Exception("搜索字段不可为空!");  
  43.         } else {  
  44.             for (Object o : propertyMap.keySet()) {  
  45.                 StringBuffer sb = new StringBuffer();  
  46.                 sb.append(o.toString()).append(":");  
  47.                 sb.append(propertyMap.get(o));  
  48.                 String queryString = addBlank2Expression(sb.toString());  
  49.                 query.setQuery(queryString);  
  50.             }  
  51.         }  
  52.         // 设置排序条件  
  53.         if (null != compositorMap) {  
  54.             for (Object co : compositorMap.keySet()) {  
  55.                 if (ASC == compositorMap.get(co)  
  56.                         || ASC.equals(compositorMap.get(co))) {  
  57.                     query.addSortField(co.toString(), SolrQuery.ORDER.asc);  
  58.                 } else {  
  59.                     query.addSortField(co.toString(), SolrQuery.ORDER.desc);  
  60.                 }  
  61.             }  
  62.         }  
  63.           
  64.         if (null != startIndex) {  
  65.             query.setStart(Integer.parseInt(String.valueOf(startIndex)));  
  66.         }  
  67.         if (null != pageSize && 0L != pageSize.longValue()) {  
  68.             query.setRows(Integer.parseInt(String.valueOf(pageSize)));  
  69.         }  
  70.         try {  
  71.             QueryResponse qrsp = solrServer.query(query);  
  72.             SolrDocumentList docs = qrsp.getResults();  
  73.             return docs;  
  74.         } catch (Exception e) {  
  75.             throw new Exception(e);  
  76.         }  
  77.     }  
  78.   
  79.     private String addBlank2Expression(String oldExpression) {  
  80.         String lastExpression;  
  81.         lastExpression = oldExpression.replace("AND"" AND ").replace("NOT",  
  82.                 " NOT ").replace("OR"" OR ");  
  83.         return lastExpression;  
  84.     }  
  85.   
  86.     public Integer getMaxRetries() {  
  87.         return maxRetries;  
  88.     }  
  89.   
  90.     ……  
  91.         
  92.         public void setMaxTotalConnections(Integer maxTotalConnections) {  
  93.         this.maxTotalConnections = maxTotalConnections;  
  94.     }  
  95. }  

 

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值