content: package org.apache.solr.spelling;
  /**
   * 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.
   */
  
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.List;
  
  import org.apache.lucene.analysis.Token;
  import org.apache.solr.common.params.CommonParams;
  import org.apache.solr.common.params.ModifiableSolrParams;
  import org.apache.solr.common.util.NamedList;
  import org.apache.solr.handler.component.QueryComponent;
  import org.apache.solr.handler.component.ResponseBuilder;
  import org.apache.solr.handler.component.SearchComponent;
  import org.apache.solr.request.LocalSolrQueryRequest;
  import org.apache.solr.response.SolrQueryResponse;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  public class SpellCheckCollator {
    private static final Logger LOG = LoggerFactory.getLogger(SpellCheckCollator.class);
  
    public List<SpellCheckCollation> collate(SpellingResult result, String originalQuery, ResponseBuilder ultimateResponse,
                                             int maxCollations, int maxTries, int maxEvaluations) {
      List<SpellCheckCollation> collations = new ArrayList<SpellCheckCollation>();
  
      QueryComponent queryComponent = null;
      if (ultimateResponse.components != null) {
        for (SearchComponent sc : ultimateResponse.components) {
          if (sc instanceof QueryComponent) {
            queryComponent = (QueryComponent) sc;
            break;
          }
        }
      }
  
      boolean verifyCandidateWithQuery = true;
      if (maxTries < 1) {
        maxTries = 1;
        verifyCandidateWithQuery = false;
      }
      if (queryComponent == null && verifyCandidateWithQuery) {
        LOG.info("Could not find an instance of QueryComponent.  Disabling collation verification against the index.");
        maxTries = 1;
        verifyCandidateWithQuery = false;
      }
  
      int tryNo = 0;
      int collNo = 0;
      PossibilityIterator possibilityIter = new PossibilityIterator(result.getSuggestions(), maxTries, maxEvaluations);
      while (tryNo < maxTries && collNo < maxCollations && possibilityIter.hasNext()) {
  
        RankedSpellPossibility possibility = possibilityIter.next();
        String collationQueryStr = getCollation(originalQuery, possibility.getCorrections());
        int hits = 0;
  
        if (verifyCandidateWithQuery) {
          tryNo++;
  
          ResponseBuilder checkResponse = new ResponseBuilder();
          checkResponse.setQparser(ultimateResponse.getQparser());
          checkResponse.setFilters(ultimateResponse.getFilters());
          checkResponse.setQueryString(collationQueryStr);
          checkResponse.components = Arrays.asList(new SearchComponent[] { queryComponent });
  
          ModifiableSolrParams params = new ModifiableSolrParams(ultimateResponse.req.getParams());
          params.set(CommonParams.Q, collationQueryStr);
          params.remove(CommonParams.START);
          params.set(CommonParams.FL, "id");
          params.set(CommonParams.ROWS, "0");
          // creating a request here... make sure to close it!
          checkResponse.req = new LocalSolrQueryRequest(ultimateResponse.req.getCore(), params);
          checkResponse.rsp = new SolrQueryResponse();
  
          try {
            queryComponent.prepare(checkResponse);
            queryComponent.process(checkResponse);
            hits = (Integer) checkResponse.rsp.getToLog().get("hits");
          } catch (Exception e) {
            LOG.warn("Exception trying to re-query to check if a spell check possibility would return any hits.", e);
          } finally {
            checkResponse.req.close();  
          }
        }
        if (hits > 0 || !verifyCandidateWithQuery) {
          collNo++;
          SpellCheckCollation collation = new SpellCheckCollation();
          collation.setCollationQuery(collationQueryStr);
          collation.setHits(hits);
          collation.setInternalRank(possibility.getRank());
  
          NamedList<String> misspellingsAndCorrections = new NamedList<String>();
          for (SpellCheckCorrection corr : possibility.getCorrections()) {
            misspellingsAndCorrections.add(corr.getOriginal().toString(), corr.getCorrection());
          }
          collation.setMisspellingsAndCorrections(misspellingsAndCorrections);
          collations.add(collation);
        }
        if (LOG.isDebugEnabled()) {
          LOG.debug("Collation: " + collationQueryStr + (verifyCandidateWithQuery ? (" will return " + hits + " hits.") : ""));
        }
      }
      return collations;
    }
  
    private String getCollation(String origQuery,
                                List<SpellCheckCorrection> corrections) {
      StringBuilder collation = new StringBuilder(origQuery);
      int offset = 0;
      for (SpellCheckCorrection correction : corrections) {
        Token tok = correction.getOriginal();
        // we are replacing the query in order, but injected terms might cause
        // illegal offsets due to previous replacements.
        if (tok.getPositionIncrement() == 0)
          continue;
        collation.replace(tok.startOffset() + offset, tok.endOffset() + offset,
            correction.getCorrection());
        offset += correction.getCorrection().length()
            - (tok.endOffset() - tok.startOffset());
      }
      return collation.toString();
    }
  
  }
  