solrj使用

1、查询

(1)获取cloud solr server

 Collapse source

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
  * 获取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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/**
      * 封装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查询逻辑

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
      * @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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
      * @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 );
         }
     }

 

在拦截器里头处理

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
  * 拦截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里头增量同步,可以在数据库里记录同步,把失败的再重来

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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方法更新

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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}" );
     }
     /**

你可能感兴趣的:(java,Solr)