/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.solr.handler.component; import org.apache.solr.handler.RequestHandlerBase; import org.apache.solr.handler.component.ResponseBuilder.ScheduleInfo; import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.StrUtils; import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.FacetParams; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.params.ShardParams; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.SolrException; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.mdrill.FacetComponent; import org.apache.solr.request.mdrill.MdrillGroupBy; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.client.solrj.SolrServer; import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrResponse; import org.apache.solr.client.solrj.request.QueryRequest; import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer; import org.apache.solr.util.plugin.SolrCoreAware; import org.apache.solr.core.SolrCore; import org.apache.lucene.queryParser.ParseException; import org.apache.commons.httpclient.HttpClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.*; import java.util.concurrent.*; public class SearchHandler extends RequestHandlerBase implements SolrCoreAware { protected static Logger log = LoggerFactory.getLogger(SearchHandler.class); protected List<SearchComponent> components = null; protected List<String> getDefaultComponents() { ArrayList<String> names = new ArrayList<String>(6); names.add( QueryComponent.COMPONENT_NAME ); names.add( FacetComponent.COMPONENT_NAME ); return names; } public void inform(SolrCore core) { if(components!=null) { return ; } List<String> list = getDefaultComponents(); components = new ArrayList<SearchComponent>( list.size() ); for(String c : list){ SearchComponent comp = core.getSearchComponent( c ); components.add(comp); // log.info("Adding component:"+comp); } } public List<SearchComponent> getComponents() { return components; } @Override public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception, ParseException, InstantiationException, IllegalAccessException { ResponseBuilder rb = new ResponseBuilder(); rb.req = req; rb.rsp = rsp; rb.components = components; rb.setDebug(false);//清理用不到的debug for( SearchComponent c : components ) { c.prepare(rb); } SolrParams paramsr=req.getParams(); String shards = paramsr.get(ShardParams.SHARDS); if (shards == null) { for( SearchComponent c : components ) { c.process(rb); } return ; } String mergeServers=paramsr.get(FacetParams.MERGER_SERVERS); List<String> lst = StrUtils.splitSmart(shards, ",", true); List<String> mslist = StrUtils.splitSmart(mergeServers, ",", true); String[] partions=paramsr.getParams(ShardParams.PARTIONS); ScheduleInfo scheduleInfo=MergerSchedule.schedule(paramsr, lst, mslist,partions); int depth=req.getParams().getInt("__higo_ms_depth__", 0); HttpCommComponent comm = new HttpCommComponent(depth); ShardRequest sreq = new ShardRequest(); sreq.params = new ModifiableSolrParams(rb.req.getParams()); for (SearchComponent c : components) { c.modifyRequest(rb, c, sreq); c.distributedProcess(rb); } sreq.responses = new ArrayList<ShardResponse>(); for (int i=0;i<scheduleInfo.shards.length;i++) { ModifiableSolrParams params = new ModifiableSolrParams(sreq.params); params.remove(ShardParams.SHARDS); // not a top-level request params.remove("indent"); params.remove(ShardParams.PARTIONS); params.remove(CommonParams.HEADER_ECHO_PARAMS); params.set(ShardParams.IS_SHARD, true); // a sub (shard) request if(scheduleInfo.partions!=null) { params.set(ShardParams.PARTIONS, scheduleInfo.partions); } if(scheduleInfo.hasSubShards) { params.set(ShardParams.SHARDS,scheduleInfo.subShards[i]); } // params.set(FacetParams.IS_SUB_SHARDS, true); params.set(FacetParams.FACET_CROSS_OFFSET, 0); params.set(FacetParams.FACET_CROSS_LIMIT, MdrillGroupBy.MAX_CROSS_ROWS); params.remove(CommonParams.QT); comm.submit( scheduleInfo,sreq, scheduleInfo.shards[i], params,depth); } while (true) { ShardResponse srsp = comm.takeCompletedOrError(); if (srsp == null) { break; // no more requests to wait for } if (srsp.getException() != null) { comm.cancelAll(); if (srsp.getException() instanceof SolrException) { throw (SolrException) srsp.getException(); } else { throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, srsp.getException()); } } for (SearchComponent c : components) { c.handleResponses(rb, srsp.getShardRequest()); } } for(SearchComponent c : components) { c.finishStage(rb); } } @Override public String getDescription() { StringBuilder sb = new StringBuilder(); sb.append("Search using components: "); if( components != null ) { for(SearchComponent c : components){ sb.append(c.getName()); sb.append(","); } } return sb.toString(); } @Override public String getVersion() { return "$Revision: 1052938 $"; } @Override public String getSourceId() { return "$Id: SearchHandler.java 1052938 2010-12-26 20:21:48Z rmuir $"; } @Override public String getSource() { return "$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java $"; } } class HttpCommComponent { CompletionService<ShardResponse> completionService =null; Set<Future<ShardResponse>> pending = new HashSet<Future<ShardResponse>>(); HttpCommComponent(int depth) { this.completionService= MergerServerThreads.create(depth); } public static class SimpleSolrResponse extends SolrResponse { private static final long serialVersionUID = 1L; long elapsedTime; NamedList<Object> nl; @Override public long getElapsedTime() { return elapsedTime; } @Override public NamedList<Object> getResponse() { return nl; } @Override public void setResponse(NamedList<Object> rsp) { nl = rsp; } } private static void setupParams(final ModifiableSolrParams params, String[] shardparams) { if (shardparams.length > 1) { params.set(CommonParams.PARTION, shardparams[1]); } params.remove(CommonParams.WT); // use default (currently javabin) params.remove(CommonParams.VERSION); } private static HttpClient makeHttpClient() { HttpClient cli = new HttpClient(); cli.getHttpConnectionManager().getParams().setConnectionTimeout(1000*60*100); cli.getHttpConnectionManager().getParams().setSoTimeout(1000*60*100); cli.getParams().setConnectionManagerTimeout(1000*60*100); return cli; } void submit(final ScheduleInfo scheduleInfo,final ShardRequest sreq, final String shard, final ModifiableSolrParams params,final int depth) { final long begintime=System.currentTimeMillis(); Callable<ShardResponse> task = new Callable<ShardResponse>() { public ShardResponse call() throws Exception { ShardResponse srsp = new ShardResponse(); srsp.setScheduleInfo(scheduleInfo); srsp.setShardRequest(sreq); srsp.setShard(shard); SimpleSolrResponse ssr = new SimpleSolrResponse(); srsp.setSolrResponse(ssr); long startTime = System.currentTimeMillis(); String[] shardparams=shard.split("@"); String url = "http://" + shardparams[0]; try { params.set("__higo_ms_depth__", (depth+1)); HttpCommComponent.setupParams(params, shardparams); HttpClient cli =HttpCommComponent.makeHttpClient(); SolrServer server = new CommonsHttpSolrServer(url, cli); QueryRequest req = new QueryRequest(params); req.setMethod(SolrRequest.METHOD.POST); ssr.nl = server.request(req); cli.getHttpConnectionManager().closeIdleConnections(0); Map<String,String> timetaken=(Map<String,String>) ssr.nl.get("mdrill_shard_time"); if(timetaken==null) { timetaken=new LinkedHashMap<String,String>(); ssr.nl.add("mdrill_shard_time", timetaken); } long t2=System.currentTimeMillis(); long timetake=t2-startTime; long waittime=startTime-begintime; timetaken.put(String.valueOf(depth)+"@"+shard, String.valueOf(timetake)+"@"+waittime); SearchHandler.log.info("##HttpClient## timetaken="+(timetake)+"@"+waittime+",shard:"+shard); }catch (RuntimeException th) { SearchHandler.log.error(shard+"@"+params.toString(),th); srsp.setException(new Exception(shard, th)); srsp.setResponseCode(-1); } catch (Throwable th) { SearchHandler.log.error(shard+"@"+params.toString(),th); srsp.setException(new Exception(shard, th)); if (th instanceof SolrException) { srsp.setResponseCode(((SolrException)th).code()); } else { srsp.setResponseCode(-1); } } ssr.elapsedTime = System.currentTimeMillis() - startTime; return srsp; } }; pending.add( completionService.submit(task) ); } ShardResponse takeCompletedOrError() { while (pending.size() > 0) { try { Future<ShardResponse> future = completionService.take(); pending.remove(future); ShardResponse rsp = future.get(); if (rsp.getException() != null) { return rsp; // if exception, return immediately } rsp.getShardRequest().responses.add(rsp); if(rsp.getShardRequest().responses.size()==rsp.getScheduleInfo().shards.length) { return rsp; } } catch (InterruptedException e) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e); } catch (ExecutionException e) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Impossible Exception",e); } } return null; } void cancelAll() { for (Future<ShardResponse> future : pending) { future.cancel(true); } } }