(三)solrj使用

1、查询

(1)获取cloud solr server

 Collapse source

/**
 * 获取cloud solr server
 * @author caibosi
 * @created 2013-12-04
 */
public enum SolrServerManager {
    CONTRACT_LIST("collection1"),
    REQUEST_AUDIT_LIST("collection2");
     String serverName;
     Logger logger = LoggerFactory.getLogger(SolrServerManager.class);
     final int zkClientTimeout = 20000; // 心跳20秒
     final int zkConnectTimeout = 10000; // 连接时间10秒
    //如果采用的cloud server, 这个地址为zookeeper的地址,192.168.4.129:9983
     final String zkHost = "ct.solrcloud.host";
     CloudSolrServer cloudSolrServer = null;
    private SolrServerManager(String serverName){
        this.serverName = serverName;
        try {
            cloudSolrServer = new CloudSolrServer(ConfigUtil.getValueByKey(this.zkHost));
            logger.info("### get solr server");
        } catch (MalformedURLException e) {
            logger.error("connect solr server error",e);
        }
        cloudSolrServer.setDefaultCollection(this.serverName);
        cloudSolrServer.setZkClientTimeout(this.zkClientTimeout);
        cloudSolrServer.setZkConnectTimeout(this.zkConnectTimeout);
    }
    public CloudSolrServer getSolrServer(){
        return cloudSolrServer;
    }
}

 

(2)查询实例

 Collapse source

/**
     * 封装solr查询方法
     * @author caibosi
     * @created 2013-12-05
     * @param query
     * @return
     * @throws SolrServerException
     */
    public SolrDocumentList getSolrDocumentList(SolrQuery query) throws SolrServerException {
        CloudSolrServer server = SolrServerManager.CONTRACT_LIST.getSolrServer();
        QueryResponse response = server.query(query);
        SolrDocumentList docs = response.getResults();
        logger.info("### query:"+ decodeByUTF8(query.toString()));
        logger.info("### solr response:"+ToStringBuilder.reflectionToString(response));
        return docs;
    }
    // 将字符串 UTF-8 解码
    public String decodeByUTF8(String str) {
        String target;
        try {
            target = URLDecoder.decode(str, "UTF-8");
        } catch (Exception e) {
            logger.error("解码出错!", e);
            return str;
        }
        return target;
    }

    /**
     * contract/list
     * 根据合同编号 或 合同名称查询
     *
     * 抛出RuntimeException的话
     * 会导致事务的回滚
     * 影响到页面报错
     *
     * 因而抛出Exception
     * http://xdy2008.iteye.com/blog/1973725
     *
     * @author caibosi
     * @created 2013-12-05
     * @param keyword
     * @param page
     * @return
     */
    public List<Contract> getContractListByKeyword(String keyword,Page page) throws Exception {
        boolean solrEnabled = ConfigUtil.getValue2BooleanByKey("solr.enabled");
        if(solrEnabled == false)
            throw new Exception("solr service disabled");
        long start = System.currentTimeMillis();
        logger.info("### query contract list using solr, keyword :"+keyword);
        SolrQuery query = new SolrQuery();
        query.setQuery("contractName:"+keyword+" OR contractNum:"+keyword);
        SolrDocumentList docs = getSolrDocumentList(query);
        List<String> contractIds = new ArrayList<String>();
        if(CollectionUtils.isEmpty(docs) == false){
            for(SolrDocument doc : docs){
                String contractId = MapUtils.getString(doc,"id");
                if(contractId!=null)
                    contractIds.add(contractId);
            }
        }
        List<Contract> contractList = new ArrayList<Contract>();
        if(CollectionUtils.isEmpty(contractIds) == false){
            contractList = contractDao.findByIds(contractIds);
        }
        long end = System.currentTimeMillis();
        logger.info("### get by solr,cost:"+(end-start));
        return contractList;
    }

 

2、植入业务代码

     植入方案:

(1)在原有的代码里头增加solr查询逻辑

/**
	 * @param contractListBean
	 * @param page
	 * @return
	 */
    @SolrCached
	public List<Contract> findContractListByContractListBean(ContractListBean contractListBean,
	                                                          Page page) {
		if (StringUtil.isNotBlank(contractListBean.getKeyword())) {
			// 有关键字,先等值匹配,再like
            long start = System.currentTimeMillis();
            /**
             * spring aop 不支持拦截方法内部再调同一类的其他方法
             * 先写在这里测试下solr功能
             */
            try {
                List<Contract> list = solrService.getContractListByKeyword(contractListBean.getKeyword(),page);
                return list;
            } catch (Exception e) {
                logger.error("get from solr by keyword error,get from db instead",e);
            }
            logger.info("### query key word from db :"+contractListBean.getKeyword());
			List<Contract> list = findContractListByContractListBeanInternal(contractListBean, page,
					true);
            long end = System.currentTimeMillis();
            logger.info("### cost:"+(end-start));
//            if (list.size() == 0) {
//                return findContractListByContractListBeanInternal(contractListBean, page, true);
//            } else {
//                return list;
//            }
			return list;
		} else {
			// 没关键字,只查一次
			return findContractListByContractListBeanInternal(contractListBean, page, true);
		}
	}

 Collapse source

         优点:明了,直接,程序员看着直白,知道这里有经过solr的缓存

         缺点:在编程的时候植入,业务逻辑与缓存逻辑混杂在一起

 

(2)利用aop,动态植入

原有的方法仅仅加一个注解

 Collapse source

/**
     * @param contractListBean
     * @param page
     * @return
     */
    @SolrCached(SolrCachedMethod.CONTRACT_LIST_KEYWORD)
    public List<Contract> findContractListByContractListBean(ContractListBean contractListBean,
                                                             Page page) {
        if (StringUtil.isNotBlank(contractListBean.getKeyword())) {
            // 有关键字,先等值匹配,再like
            long start = System.currentTimeMillis();
            List<Contract> list = contractService.findContractListByContractListBeanInternal(contractListBean, page,
                    true);
            long end = System.currentTimeMillis();
            logger.info("### cost:"+(end-start));
//            if (list.size() == 0) {
//                return findContractListByContractListBeanInternal(contractListBean, page, true);
//            } else {
//                return list;
//            }
            return list;
        } else {
            // 没关键字,只查一次
            return contractService.findContractListByContractListBeanInternal(contractListBean, page, true);
        }
    }

 

在拦截器里头处理

/**
 * 拦截service相关方法
 * 使用solr进行查询
 * @author caibosi
 * @created 2013-12-05
 */
@Aspect
@Component
public class SolrInterceptor {
    private final Logger logger = LoggerFactory.getLogger(SolrInterceptor.class);
    @Resource
    private SolrService solrService;

    /**
     * 拦截带有SolrCached的方法
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("@annotation(solrCached)")
    public Object getResultBySolr(ProceedingJoinPoint pjp,SolrCached solrCached) throws Throwable {
        try{
            if(solrCached.value() == SolrCachedMethod.CONTRACT_LIST_KEYWORD){
                Object[] args = pjp.getArgs();
                ContractListBean queryBean = (ContractListBean) args[0];
                Page page = (Page) args[1];
                if(queryBean!=null && queryBean.getKeyword()!=null){
                    return  solrService.getContractListByKeyword(queryBean.getKeyword(),page);
                }
                logger.info("### into findContractListByContractListBean");
            }
        }catch (Exception e){
            logger.error("query solr error,query db instead",e);
        }
        return pjp.proceed(pjp.getArgs());
    }
}

 Collapse source

         优点:与业务逻辑分离开

         缺点:程序员可能不知道此处会被拦截,进行solr查询

                   因而,采用注解的形式告知,但spring aop不支持同一类A方法内部调B方法中B方法的拦截,因而找到最细粒度的方法进行拦截可能优点困难,因而这个方法可能没办法拦截到。

         解决方法:1、改造原来方法(移动其他类,但是改动大) 2、采用兼容模式,无法被拦截的,直接在代码里头写,可以被拦截的就在interceptor里头写、

 

3、同步索引

     索引的同步与业务逻辑关联比较大,每个solr缓存的数据的触发条件都不大一样。

   (1)增加

          根据contract的add_time,对solr进行增量同步

          方案1:采用delta import, 在配置文件里配置,同时使用crontab 定时执行该命令的url

          方案2:在java里头增量同步,可以在数据库里记录同步,把失败的再重来

public SolrImortResult importContractListByPage(Date start,Date end,Page page){
        List<Contract> contractList = contractDao.findByAddTime(start,end,page);
        if(CollectionUtils.isEmpty(contractList)){
            return new SolrImortResult(new Date(),new Date(),0);
        }else{
            logger.info("#### begin to update count:"+contractList.size());
        }
        List<SolrInputDocument> inputDocs = new ArrayList<SolrInputDocument>();
        SolrImortResult result = new SolrImortResult();
        int updateCount = -1;
        for(Contract ct : contractList){
            SolrInputDocument doc = new SolrInputDocument();
            doc.addField("contractId",ct.getContractId());
            doc.addField("contractNum",ct.getContractNum());
            doc.addField("contractName",ct.getContractName());
            inputDocs.add(doc);
        }
        CloudSolrServer server = SolrServerManager.CONTRACT_LIST.getSolrServer();
        try {
            server.connect();
            server.add(inputDocs);
            UpdateResponse response = server.commit();
            if(response!=null){
               logger.info("### update to solr for page:"+page.getPageNo()+";response:"+ToStringBuilder.reflectionToString(response));
                   updateCount = page.getPageSize();
            }
        } catch (Exception e) {
            logger.error("update contract list to solr error",e);
            updateCount = -1;
        }
        Date startTime = contractList.get(0).getAddTime();
        Date endTime = contractList.get(contractList.size()-1).getAddTime();
        result.setStartTime(startTime);
        result.setEndTime(endTime);
        result.setUpdateCount(updateCount);
        return result;
    }

 Collapse source

   (2)更新

         add方法添加字段,set方法更新

package com.persia.solrj;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrServer;
import org.apache.solr.common.SolrInputDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.*;
/**
 * solr服务
 * 获取solr server
 * @author caibosi
 * @created 2013-12-04
 */
@Service
public class SolrTestService {
    private static final Logger logger = LoggerFactory.getLogger(SolrTestService.class);

    /**
     * 这种有效果,删除再添加
     * 但不知道与map方式的区别
     * 如果是add全部字段,其实是没有区别滴
     * 如果add部分字段,没有add的字段会丢失掉
     * @throws java.io.IOException
     * @throws org.apache.solr.client.solrj.SolrServerException
     */
    public void updateByAdd() throws IOException, SolrServerException {
        CloudSolrServer server = SolrServerManager.CONTRACT_SEARCH.getSolrServer();
        server.connect();
        SolrInputDocument doc = new SolrInputDocument();
        doc.addField("contractId","74acd736-f84e-11e2-8dea-00222822153f");
        doc.addField("contractName","测试update操作23");
        doc.addField("contractNum","测试update操作33");
        server.add(doc);
        server.commit();
        logger.info("### update success,contractId:{283a8436-481c-11e3-8dea-00222822153f}");
    }
    /**
     * 下面这种纯属字面上的误会
     * 实际上会更新整个文档
     * 假设文档原来十几个字段
     * 这种方式会替换为3个字段(如下)
     * http://osdir.com/ml/solr-user.lucene.apache.org/2012-07/msg01065.html
     *
     * not setting internal flags for the
       indexer to treat the SolrInputDocument differently based on if set or
       add was called
     *
     * @throws java.io.IOException
     * @throws org.apache.solr.client.solrj.SolrServerException
     */
    public void updateBySet() throws IOException, SolrServerException {
        CloudSolrServer server = SolrServerManager.CONTRACT_SEARCH.getSolrServer();
        server.connect();
        SolrInputDocument doc = new SolrInputDocument();
        //如果id也用setfield的话,当文档不存在的时候,也会创建
        doc.addField("contractId", "74acd736-f84e-11e2-8dea-00222822153f");
        doc.setField("contractNum","234254646664c1set");
        doc.setField("contractName", "测试update操作3set");
        server.add(doc);
        server.commit();
        logger.info("### update success,contractId:{283a8436-481c-11e3-8dea-00222822153f}");
    }
    /**
     * 下面这种才是正确的update方式
     * {
     *"add" : {
     *"doc" : {
     *"id":"12345",
     *"foo":{"set":null},
     *"bar":{"set":"baz"}
     *}
     *}
     *}
     * @throws java.io.IOException
     * @throws org.apache.solr.client.solrj.SolrServerException
     */
    public void updateByMap() throws IOException, SolrServerException {
        CloudSolrServer server = SolrServerManager.CONTRACT_SEARCH.getSolrServer();
        server.connect();
        SolrInputDocument doc = new SolrInputDocument();
        doc.addField("contractId","8b0e8874-5640-11e3-8dea-00222822153f");
        Map<String,Object> value = new HashMap<String,Object>();
        value.put("set","ww测试partial");
        doc.addField("contractName",value);
        Map<String,Object> value1 = new HashMap<String,Object>();
        value1.put("set","wwc987654321");
        doc.addField("contractNum",value1);
        server.add(doc);
        server.commit();
        logger.info("### update success,contractId:{283a8436-481c-11e3-8dea-00222822153f}");
    }
   public void test() throws IOException, SolrServerException {
       CloudSolrServer server = SolrServerManager.CONTRACT_SEARCH.getSolrServer();
       server.connect();
//       ZkStateReader zkStateReader = server.getZkStateReader();
//       ClusterState state = zkStateReader.getClusterState();
//       System.out.println("### "+state);
//
//       SolrQuery query = new SolrQuery();
//       query.setQuery("contractName:测试选择商户改进");
//       try {
//           QueryResponse response = server.query(query);
//           SolrDocumentList docs = response.getResults();
//           System.out.println("### count:"+docs.getNumFound());
//           System.out.println("### cost:"+response.getQTime());
//
//           for(SolrDocument doc:docs){
//               String name = (String) doc.getFieldValue("contractName");
//               String id = (String)doc.getFieldValue("contractId");
//               System.out.println("### id:"+id+";name:"+name);
//           }
//       } catch (SolrServerException e) {
//           e.printStackTrace();
//       }
       SolrInputDocument doc = new SolrInputDocument();
       doc.addField("contractId","g283a8436-481c-11e3-8dea-00222822153f");
       doc.addField("contractNum", "g234254646664c1");
       doc.addField("contractName", "g测试update操作3");
//       Map<String,Object> value = new HashMap<String,Object>();
//       value.put("set","测试partial");
//       doc.addField("contractName",value);
       server.add(doc);
       server.commit();
       logger.info("### update success,contractId:{283a8436-481c-11e3-8dea-00222822153f}");
//       server.shutdown();
//      CloudSolrServer server1 = SolrServerManager.CONTRACT_LIST.getSolrServer();
//       System.out.println("### server1:"+server1.toString());
//
//       CloudSolrServer server2 = SolrServerManager.CONTRACT_LIST.getSolrServer();
//       System.out.println("### server2:"+server2.toString());
   }
    public static void main(String[] args){
    }
}

   (3)删除

 Collapse source

public void clearContractSearch() throws IOException, SolrServerException {
        CloudSolrServer server = SolrServerManager.CONTRACT_SEARCH.getSolrServer();
        server.connect();
        server.deleteByQuery( "*:*" );// delete everything!
        server.commit();
}

 

 

你可能感兴趣的:((三)solrj使用)