• solr创建索引源码解析


    先说下创建索引源码流程

          源码类: 
              1.CommonHttpSolrServer (SolrServer的子类) 
              2.SolrServer(抽象类) 
              3.SolrRequest (基类) 
              4.AbstractUpdateRequest (抽象类、SolrRequest的子类) 
              5.UpdateRequest  (AbstractUpdateRequest的子类) 
              6.SolrInputDocument  (设置需要索引的名称和值、这个应该放在第一位) 

    创建索引代码:

      1.        查询数据库数据,或者其他文档数据进行索引
        [java] view plaincopy在CODE上查看代码片派生到我的代码片
         
        1.           private void updateBook(String sql, String url, String idColumn,  
        2.             String timeColumn,BufferedWriter dataFile) throws Exception {  
        3.         long start = System.currentTimeMillis();  
        4.                 <span></span> SolrUtil solrUtil = new SolrUtil(url);//初始化索引  
        5.         SolrDocument doc = SqlSh.getSolrMaxDoc(solrUtil, idColumn, timeColumn);  
        6.         if (doc == null) {  
        7.             CommonLogger.getLogger().error("solr no data.");  
        8.             return;  
        9.         }  
        10.         int maxId = Integer.parseInt(doc.get(idColumn).toString());  
        11.         long maxTime = Long.parseLong(doc.get(timeColumn).toString())*1000;  
        12.         Date maxDate = new Date(maxTime);  
        13.           
        14.         DateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
        15.                 //获取数据库需要索引的数据  
        16.         ResultSet rs = stmt_m.executeQuery(String.format(sql,  
        17.                 dateFormat2.format(maxDate)));  
        18.         //获取需要创建索引的key  
        19.                 initColumeMeta(rs.getMetaData());  
        20.   
        21.                 //解析数据并索引  
        22.         parseRs(rs, solrUtil);  
        23.   
        24.         rs.close();  
        25.                  
        26.                 //优化索引  
        27.         solrUtil.server.optimize();  
        28.   
        29.         CommonLogger.getLogger().info(  
        30.                 "update book time:" + (System.currentTimeMillis() - start)  
        31.                         / 1000 + "s");  
        32.     }  


      2. 咱们看下上面代码的parseRs方法
        [java] view plaincopy在CODE上查看代码片派生到我的代码片
         
        1. //下面是简单的解析数据方法并写索引         

        [java] view plaincopy在CODE上查看代码片派生到我的代码片
         
        1.  private void parseRs(ResultSet rs, SolrUtil solrUtil) throws <span></span> Exception {  
        2.         Collection<SolrInputDocument> docs=new ArrayList<SolrInputDocument>();  
        3.         SolrInputDocument doc = null;  
        4.         int locBk = 0;  
        5.         boolean flag=true;  
        6.         StringBuilder sb=null;  
        7.         String vl=null;  
        8.         try {  
        9.             while (rs.next()) {  
        10.                 doc = new SolrInputDocument();  
        11.                 for (int i = 0; i < ToolMain.columnNames.length; i++) {  
        12.                     doc.addField(  
        13.                         ToolMain.columnNames[i],  
        14.                         getColumnValue(  
        15.                             rs.getObject(ToolMain.columnNames[i]),  
        16.                             ToolMain.columnTypes[i]));//此方法为设置一个域,可以添加一个参数来设置权重  
        17.                 }  
        18.                 docs.add(doc);  
        19.                 locBk++;  
        20.                 if (docs.size() >= 1000) {  
        21.                     solrUtil.addDocList(docs);//创建索引和提交索引操作都在这里面  
        22.                     docs.clear();  
        23.                 }  
        24.             }  
        25.             if (docs.size() > 0) {  
        26.                 solrUtil.addDocList(docs);  
        27.                 docs.clear();  
        28.             }  
        29.         } catch (Exception e) {  
        30.             throw e;  
        31.         } finally {  
        32.             docs.clear();  
        33.             docs = null;  
        34.         }  
        35.     }  

        3.下面来说明下SolrUtil类,此类主要是封装了CommonHttpSolrServer
        [java] view plaincopy在CODE上查看代码片派生到我的代码片
         
        1. import java.util.Collection;  
        2.   
        3. import log.CommonLogger;  
        4.   
        5. import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;  
        6. import org.apache.solr.common.SolrInputDocument;  
        7.   
        8. public class SolrUtil {  
        9.     public CommonsHttpSolrServer server = null;  
        10.   
        11.     public String url = "";//url为solr服务的地址  
        12.     public  String shards = "";  
        13.   
        14.     public SolrUtil(String url) {  
        15.         this.url = url;  
        16.         initSolr();  
        17.     }  
        18.     public SolrUtil(String url,String shards) {  
        19.         this.url = url;  
        20.         this.shards=shards;  
        21.         initSolr();  
        22.     }  
        23.        //初始化Server  
        24.     private void initSolr() {  
        25.         try {  
        26.             server = new CommonsHttpSolrServer(url);  
        27.             server.setSoTimeout(60*1000);  
        28.             server.setConnectionTimeout(60*1000);  
        29.             server.setDefaultMaxConnectionsPerHost(1000);  
        30.             server.setMaxTotalConnections(1000);  
        31.             server.setFollowRedirects(false);  
        32.             server.setAllowCompression(true);  
        33.         } catch (Exception e) {  
        34.             e.printStackTrace();  
        35.             System.exit(-1);  
        36.         }  
        37.     }  
        38.     //封装了add、commit  
        39.     public void addDocList(Collection<SolrInputDocument> docs) {  
        40.         try {  
        41.             server.add(docs);  
        42.             server.commit();  
        43.             docs.clear();//释放  
        44.         } catch (Exception e) {  
        45.             CommonLogger.getLogger().error("addDocList error.", e);  
        46.         }  
        47.     }  
        48.       
        49.     public void deleteDocByQuery(String query) throws Exception {   
        50.         try {  
        51.             server.deleteByQuery(query);  
        52.             server.commit();  
        53.         } catch (Exception e) {  
        54.             CommonLogger.getLogger().error("deleteDocByQuery error.", e);  
        55.             throw e;  
        56.         }  
        57.     }  
        58. }  

        4.现在来看看solr创建索引的源码

            其实源码执行的操作无非是 生成请求request  返回response

            1.上面代码中的SolrInputDocument 类所做的操作

        [java] view plaincopy在CODE上查看代码片派生到我的代码片
         
        1.     public class SolrInputDocument implements Map<String,SolrInputField>, Iterable<SolrInputField>, Serializable   //实现了Map和Iterable的接口并且实现了接口中的方法,其主要的类为SolrInputFiled类  

        [java] view plaincopy在CODE上查看代码片派生到我的代码片
         
        1.     public class SolrInputField implements Iterable<Object>, Serializable //类中只有三个属性,String key,Object value,还包括评分  float boost = 1.0f; 默认是1.0f(如果做权重的话可以设置这个值)  

        再来看下执行的CommonHttpSolrServer类所做的操作(表现形式在SolrUtil中的addDocList)

            2.添加文档方法

        [java] view plaincopy在CODE上查看代码片派生到我的代码片
         
        1. public UpdateResponse add(Collection<SolrInputDocument> docs )                         throws SolrServerException, IOException {  

        [java] view plaincopy在CODE上查看代码片派生到我的代码片
         
        1.             UpdateRequest req = new UpdateRequest();//创建一个request  

        [java] view plaincopy在CODE上查看代码片派生到我的代码片
         
        1.           req.add(docs);//调用UpdateRequest的add方法,添加索引文档  
        2.           return req.process(this);//亲 重点是这个方法(返回的是response)  
        3.    }  

        [java] view plaincopy在CODE上查看代码片派生到我的代码片
         
        1.         //再看下UpdateRequest的add方法  
        2.         private List<SolrInputDocument> documents = null;  
        3.         public UpdateRequest add( final Collection<SolrInputDocument> docs )  
        4.         {  
        5.             if( documents == null ) {  
        6.                   documents = new ArrayList<SolrInputDocument>( docs.size()+1 );  
        7.             }  
        8.             documents.addAll( docs );  
        9.             return this;  
        10.         }  

         3.提交方法 commit,调用的是SolrServer类中的
        [java] view plaincopy在CODE上查看代码片派生到我的代码片
         
        1.  public UpdateResponse commit( boolean waitFlush, boolean waitSearcher ) throws Solr    ServerException, IOException {  
        2.         return new UpdateRequest().setAction( UpdateRequest.ACTION.COMMIT, waitFlush, waitSearcher ).process( this );//看到了吗?  
        3. <pre class="brush:java; toolbar: true; auto-links: false;"> setAction都是为了对对象ModifiableSolrParams(这个对象在最终CommonHttpSolrServerrequest的request方法中用的到)</pre>  
        4. <span></span> 在提交索引的时候也是调用的process方法  
        5.   }  

        4.优化索引
        [java] view plaincopy在CODE上查看代码片派生到我的代码片
         
        1. public UpdateResponse optimize(boolean waitFlush, boolean waitSearcher,                 int maxSegments ) throws SolrServerException, IOException {  
        2. sp;           return new UpdateRequest().setAction( UpdateRequest.ACTION.OPTIMIZE, waitFlush, waitSearcher, maxSegments ).process( this );//同样调用process,通过setAction参数,在CommonHttpSolrServer类方法request()中主要执行的是合并和压缩  setAction都是为了对对象ModifiableSolrParams(这个对象在最终CommonHttpSolrServer的request方法中用的到)进行赋值  
        3. }  

        5.既然上面都提到了process方法,那我们来看看
        [java] view plaincopy在CODE上查看代码片派生到我的代码片
         
        1. @Override  
        2.      public UpdateResponse process( SolrServer server ) throws SolrServerException,             IOException  
        3.      {  
        4.            long startTime = System.currentTimeMillis();  
        5.            UpdateResponse res = new UpdateResponse();  
        6.            res.setResponse( server.request( this ) );//这里面这个方法可是重点之重啊,这是调用了 CommonHttpSolrServer类中的request方法  
        7.            res.setElapsedTime( System.currentTimeMillis()-startTime );  
        8.            return res;  
        9.      }  

        6.最终的方法是SolrServer的子类CommonHttpSolrServer类的request方法,咋再来看看这个方法是怎么工作的
        [java] view plaincopy在CODE上查看代码片派生到我的代码片
         
        1. public NamedList<Object> request(final SolrRequest request, ResponseParser processor    ) throws SolrServerException, IOException {  
        2.       
        3.     HttpMethod method = null;  
        4.     InputStream is = null;  
        5.     SolrParams params = request.getParams();  
        6.     Collection<ContentStream> streams = requestWriter.getContentStreams(request);  
        7.     String path = requestWriter.getPath(request);  
        8.       
        9.     //创建索引进来的是/update  /select 为查询    
        10.     if( path == null || !path.startsWith( "/" ) ) {  
        11.       path = "/select";  
        12.     }  
        13.       
        14.     ResponseParser parser = request.getResponseParser();  
        15.     if( parser == null ) {  
        16.       parser = _parser;  
        17.     }  
        18.       
        19.     // The parser 'wt=' and 'version=' params are used instead of the original params  
        20.     ModifiableSolrParams wparams = new ModifiableSolrParams();  
        21.     wparams.set( CommonParams.WT, parser.getWriterType() );  
        22.     wparams.set( CommonParams.VERSION, parser.getVersion());  
        23.     if( params == null ) {  
        24.       params = wparams;  
        25.     }  
        26.     else {  
        27.       params = new DefaultSolrParams( wparams, params );  
        28.     }  
        29.       
        30.     if( _invariantParams != null ) {  
        31.       params = new DefaultSolrParams( _invariantParams, params );  
        32.     }  
        33.   
        34.     int tries = _maxRetries + 1;  
        35.     try {  
        36.       while( tries-- > 0 ) {  
        37.         // Note: since we aren't do intermittent time keeping  
        38.         // ourselves, the potential non-timeout latency could be as  
        39.         // much as tries-times (plus scheduling effects) the given  
        40.         // timeAllowed.  
        41.         try {//通过使用查看solr源码,在使用UpdateRequest对象时会自动设置为Post  
        42.           if( SolrRequest.METHOD.GET == request.getMethod() ) {  
        43.             if( streams != null ) {  
        44.                   <span></span>throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "GET can't send streams!" );  
        45.             }  
        46.             method = new GetMethod( _baseURL + path + ClientUtils.toQueryString( params, false ) );  
        47.           }  
        48.           else if( SolrRequest.METHOD.POST == request.getMethod() ) {//所以我们直接看  
        49.   
        50.             String url = _baseURL + path;  
        51.             boolean isMultipart = ( streams != null && streams.size() > 1 );  
        52.   
        53.             if (streams == null || isMultipart) {  
        54.               PostMethod post = new PostMethod(url);//设置post,包括request头部、内容、参数、等等一些操作  
        55.               post.getParams().setContentCharset("UTF-8");  
        56.               if (!this.useMultiPartPost && !isMultipart) {  
        57.                 post.addRequestHeader("Content-Type",  
        58.                     "application/x-www-form-urlencoded; charset=UTF-8");  
        59.               }  
        60.   
        61.               List<Part> parts = new LinkedList<Part>();  
        62.               Iterator<String> iter = params.getParameterNamesIterator();  
        63.               while (iter.hasNext()) {  
        64.                 String p = iter.next();  
        65.                 String[] vals = params.getParams(p);  
        66.                 if (vals != null) {  
        67.                   for (String v : vals) {  
        68.                     if (this.useMultiPartPost || isMultipart) {  
        69.                       parts.add(new StringPart(p, v, "UTF-8"));  
        70.                     } else {  
        71.                       post.addParameter(p, v);  
        72.                     }  
        73.                   }  
        74.                 }  
        75.               }  
        76.   
        77.               if (isMultipart) {  
        78.                 int i = 0;  
        79.                 for (ContentStream content : streams) {  
        80.                   final ContentStream c = content;  
        81.   
        82.                   String charSet = null;  
        83.                   PartSource source = new PartSource() {  
        84.                     public long getLength() {  
        85.                       return c.getSize();  
        86.                     }  
        87.                     public String getFileName() {  
        88.                       return c.getName();  
        89.                     }  
        90.                     public InputStream createInputStream() throws IOException {  
        91.                       return c.getStream();  
        92.                     }  
        93.                   };  
        94.                   
        95.                   parts.add(new FilePart(c.getName(), source,   
        96.                                          c.getContentType(), charSet));  
        97.                 }  
        98.               }  
        99.               if (parts.size() > 0) {  
        100.                 post.setRequestEntity(new MultipartRequestEntity(parts  
        101.                     .toArray(new Part[parts.size()]), post.getParams()));  
        102.               }  
        103.   
        104.               method = post;  
        105.             }  
        106.             // It is has one stream, it is the post body, put the params in the URL  
        107.             else {  
        108.               String pstr = ClientUtils.toQueryString(params, false);  
        109.               PostMethod post = new PostMethod(url + pstr);  
        110.   
        111.               // Single stream as body  
        112.               // Using a loop just to get the first one  
        113.               final ContentStream[] contentStream = new ContentStream[1];  
        114.               for (ContentStream content : streams) {  
        115.                 contentStream[0] = content;  
        116.                 break;  
        117.               }  
        118.               if (contentStream[0instanceof RequestWriter.LazyContentStream) {  
        119.                 post.setRequestEntity(new RequestEntity() {  
        120.                   public long getContentLength() {  
        121.                     return -1;  
        122.                   }  
        123.   
        124.                   public String getContentType() {  
        125.                     return contentStream[0].getContentType();  
        126.                   }  
        127.   
        128.                   public boolean isRepeatable() {  
        129.                     return false;  
        130.                   }  
        131.   
        132.                   public void writeRequest(OutputStream outputStream) throws IOException {  
        133.                     ((RequestWriter.LazyContentStream) contentStream[0]).writeTo(outputStream);  
        134.                   }  
        135.                 }  
        136.                 );  
        137.   
        138.               } else {  
        139.                 is = contentStream[0].getStream();  
        140.                 post.setRequestEntity(new InputStreamRequestEntity(is, contentStream[0].getContentType()));  
        141.               }  
        142.               method = post;  
        143.             }  
        144.           }  
        145.           else {  
        146.             throw new SolrServerException("Unsupported method: "+request.getMethod() );  
        147.           }  
        148.         }  
        149.         catch( NoHttpResponseException r ) {  
        150.           // This is generally safe to retry on  
        151.           method.releaseConnection();  
        152.           method = null;  
        153.           if(is != null) {  
        154.             is.close();  
        155.           }  
        156.           // If out of tries then just rethrow (as normal error).  
        157.           if( ( tries < 1 ) ) {  
        158.             throw r;  
        159.           }  
        160.           //log.warn( "Caught: " + r + ". Retrying..." );  
        161.         }  
        162.       }  
        163.     }  
        164.     catch( IOException ex ) {  
        165.       throw new SolrServerException("error reading streams", ex );  
        166.     }  
        167.   
        168.     method.setFollowRedirects( _followRedirects );  
        169.     method.addRequestHeader( "User-Agent", AGENT );  
        170.     if( _allowCompression ) {  
        171.       method.setRequestHeader( new Header( "Accept-Encoding""gzip,deflate" ) );  
        172.     }  
        173.   
        174.     try {  
        175.       // Execute the method.  
        176.       //System.out.println( "EXECUTE:"+method.getURI() );  
        177.       //执行请求,返回状态码,然后组装response 最后返回  
        178.       int statusCode = _httpClient.executeMethod(method);  
        179.       if (statusCode != HttpStatus.SC_OK) {  
        180.         StringBuilder msg = new StringBuilder();  
        181.         msg.append( method.getStatusLine().getReasonPhrase() );  
        182.         msg.append( " " );  
        183.         msg.append( method.getStatusText() );  
        184.         msg.append( " " );  
        185.         msg.append( "request: "+method.getURI() );  
        186.         throw new SolrException(statusCode, java.net.URLDecoder.decode(msg.toString(), "UTF-8") );  
        187.       }  
        188.   
        189.       // Read the contents  
        190.       String charset = "UTF-8";  
        191.       if( method instanceof HttpMethodBase ) {  
        192.         charset = ((HttpMethodBase)method).getResponseCharSet();  
        193.       }  
        194.       InputStream respBody = method.getResponseBodyAsStream();  
        195.       // Jakarta Commons HTTPClient doesn't handle any  
        196.       // compression natively.  Handle gzip or deflate  
        197.       // here if applicable.  
        198.       if( _allowCompression ) {  
        199.         Header contentEncodingHeader = method.getResponseHeader( "Content-Encoding" );  
        200.         if( contentEncodingHeader != null ) {  
        201.           String contentEncoding = contentEncodingHeader.getValue();  
        202.           if( contentEncoding.contains( "gzip" ) ) {  
        203.             //log.debug( "wrapping response in GZIPInputStream" );  
        204.             respBody = new GZIPInputStream( respBody );  
        205.           }  
        206.           else if( contentEncoding.contains( "deflate" ) ) {  
        207.             //log.debug( "wrapping response in InflaterInputStream" );  
        208.             respBody = new InflaterInputStream(respBody);  
        209.           }  
        210.         }  
        211.         else {  
        212.           Header contentTypeHeader = method.getResponseHeader( "Content-Type" );  
        213.           if( contentTypeHeader != null ) {  
        214.             String contentType = contentTypeHeader.getValue();  
        215.             if( contentType != null ) {  
        216.               if( contentType.startsWith( "application/x-gzip-compressed" ) ) {  
        217.                 //log.debug( "wrapping response in GZIPInputStream" );  
        218.                 respBody = new GZIPInputStream( respBody );  
        219.               }  
        220.               else if ( contentType.startsWith("application/x-deflate") ) {  
        221.                 //log.debug( "wrapping response in InflaterInputStream" );  
        222.                 respBody = new InflaterInputStream(respBody);  
        223.               }  
        224.             }  
        225.           }  
        226.         }  
        227.       }  
        228.       return processor.processResponse(respBody, charset);  
        229.     }  
        230.     catch (HttpException e) {  
        231.       throw new SolrServerException( e );  
        232.     }  
        233.     catch (IOException e) {  
        234.       throw new SolrServerException( e );  
        235.     }  
        236.     finally {  
        237.       method.releaseConnection();  
        238.       if(is != null) {  
        239.         is.close();  
        240.       }  
        241.     }  
        242.   }  
  • 相关阅读:
    POJ 1948 Triangular Pastures
    2018ACM/ICPC 青岛现场赛 E题 Plants vs. Zombies
    三大博弈
    ACM-ICPC 2018年北京网络赛 D-80 days
    hdu 2062 Subset sequence
    转-利用 Python 练习数据挖掘
    内联函数
    C++中冒号(:)和双冒号(::)的用法
    理性,感性和爱
    修改IE8搜索框为指定搜索引擎,如CSDN、百度知道等
  • 原文地址:https://www.cnblogs.com/bingbingJava/p/3625040.html
Copyright © 2020-2023  润新知