solr源码分析--query

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)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值