solr查询的逻辑比较复杂,下面按场景简单做一个梳理。
概述
只考虑一般的查询流程。单节点和分布式搜索流程上还是有很大的差别。简单的先看一下solrServer是如何接受到查询请求的,以及response的构造。
整体流程
大体的流程在这篇博客中已经写明。solr6.2源码分析
请求入口
首先,solr是部署在tomcat上的一个web项目,看一下过滤器的逻辑。
web.xml,SolrDispatchFilter是请求的入口。
<filter>
<filter-name>SolrRequestFilter</filter-name>
<filter-class>org.apache.solr.servlet.SolrDispatchFilter</filter-class>
<!--
Exclude patterns is a list of directories that would be short circuited by the
SolrDispatchFilter. It includes all Admin UI related static content.
NOTE: It is NOT a pattern but only matches the start of the HTTP ServletPath.
-->
<init-param>
<param-name>excludePatterns</param-name>
<param-value>/css/.+,/js/.+,/img/.+,/tpl/.+</param-value>
</init-param>
</filter>
SolrDispatchFilter 请求的分类
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain, boolean retry) throws IOException, ServletException {
if (!(request instanceof HttpServletRequest)) return;
try {
if (cores == null || cores.isShutDown()) {
log.error("Error processing the request. CoreContainer is either not initialized or shutting down.");
throw new SolrException(ErrorCode.SERVICE_UNAVAILABLE,
"Error processing the request. CoreContainer is either not initialized or shutting down.");
}
AtomicReference<ServletRequest> wrappedRequest = new AtomicReference<>();
if (!authenticateRequest(request, response, wrappedRequest)) { // the response and status code have already been
// sent
return;
}
if (wrappedRequest.get() != null) {
request = wrappedRequest.get();
}
request = closeShield(request, retry);
response = closeShield(response, retry);
if (cores.getAuthenticationPlugin() != null) {
log.debug("User principal: {}", ((HttpServletRequest) request).getUserPrincipal());
}
// No need to even create the HttpSolrCall object if this path is excluded.
if (excludePatterns != null) {
String requestPath = ((HttpServletRequest) request).getServletPath();
String extraPath = ((HttpServletRequest) request).getPathInfo();
if (extraPath != null) { // In embedded mode, servlet path is empty - include all post-context path here for
// testing
requestPath += extraPath;
}
for (Pattern p : excludePatterns) {
Matcher matcher = p.matcher(requestPath);
if (matcher.lookingAt()) {
chain.doFilter(request, response);
return;
}
}
}
// 这块没有太多的逻辑
HttpSolrCall call = getHttpSolrCall((HttpServletRequest) request, (HttpServletResponse) response, retry); // HttpSolrCall总要的关注点。
ExecutorUtil.setServerThreadFlag(Boolean.TRUE);
try {
Action result = call.call();
switch (result) {
case PASSTHROUGH:
chain.doFilter(request, response);
break;
case RETRY:
doFilter(request, response, chain, true);
break;
case FORWARD:
request.getRequestDispatcher(call.getPath()).forward(request, response);
break;
}
} finally {
call.destroy();
ExecutorUtil.setServerThreadFlag(null);
}
} finally {
consumeInputFully((HttpServletRequest) request);
}
}
HttpSolrCall.call() 构造查询处理方式,以及response类型。这个response也是个重点,不是简单的构造一个response,返回的数据到这里只有一个id和score,会在此处进行一次查询,获取整个doc的所有数据。
switch (action) {
case ADMIN:
handleAdminRequest(); // 主要的执行逻辑,根据不同的请求调用不同的handler
return RETURN;
case REMOTEQUERY:
remoteQuery(coreUrl + path, resp);
return RETURN;
case PROCESS: // 查询逻辑
final Method reqMethod = Method.getMethod(req.getMethod());
HttpCacheHeaderUtil.setCacheControlHeader(config, resp, reqMethod);
// unless we have been explicitly told not to, do cache validation
// if we fail cache validation, execute the query
if (config.getHttpCachingConfig().isNever304() ||
!HttpCacheHeaderUtil.doCacheHeaderValidation(solrReq, req, reqMethod, resp)) {
SolrQueryResponse solrRsp = new SolrQueryResponse();
SolrRequestInfo.setRequestInfo(new SolrRequestInfo(solrReq, solrRsp));
execute(solrRsp);
HttpCacheHeaderUtil.checkHttpCachingVeto(solrRsp, resp, reqMethod);
Iterator<Map.Entry<String, String>> headers = solrRsp.httpHeaders();
while (headers.hasNext()) {
Map.Entry<String, String> entry = headers.next();
resp.addHeader(entry.getKey(), entry.getValue());
}
QueryResponseWriter responseWriter = core.getQueryResponseWriter(solrReq);
if (invalidStates != null) solrReq.getContext().put(CloudSolrClient.STATE_VERSION, invalidStates);
writeResponse(solrRsp, responseWriter, reqMethod); // response处理逻辑
}
return RETURN;
default: return action;
response构造
QueryResponseWriterUtil.writeQueryResponse()
public static void writeQueryResponse(OutputStream outputStream,
QueryResponseWriter responseWriter, SolrQueryRequest solrRequest,
SolrQueryResponse solrResponse, String contentType)