content: package org.apache.lucene.search;
  
  /**
   * 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.io.IOException;
  
  import org.apache.lucene.index.IndexReader;
  import org.apache.lucene.search.BooleanQuery;
  import org.apache.lucene.search.DefaultSimilarity;
  import org.apache.lucene.search.Query;
  import org.apache.lucene.search.Searcher;
  import org.apache.lucene.search.Similarity;
  /**
   * The BoostingQuery class can be used to effectively demote results that match a given query. 
   * Unlike the "NOT" clause, this still selects documents that contain undesirable terms, 
   * but reduces their overall score:
   *
   *     Query balancedQuery = new BoostingQuery(positiveQuery, negativeQuery, 0.01f);
   * In this scenario the positiveQuery contains the mandatory, desirable criteria which is used to 
   * select all matching documents, and the negativeQuery contains the undesirable elements which 
   * are simply used to lessen the scores. Documents that match the negativeQuery have their score 
   * multiplied by the supplied "boost" parameter, so this should be less than 1 to achieve a 
   * demoting effect
   * 
   * This code was originally made available here: [WWW] http://marc.theaimsgroup.com/?l=lucene-user&m=108058407130459&w=2
   * and is documented here: http://wiki.apache.org/lucene-java/CommunityContributions
   */
  public class BoostingQuery extends Query {
      private float boost;                            // the amount to boost by
      private Query match;                            // query to match
      private Query context;                          // boost when matches too
  
      public BoostingQuery(Query match, Query context, float boost) {
        this.match = match;
        this.context = (Query)context.clone();        // clone before boost
        this.boost = boost;
  
        this.context.setBoost(0.0f);                      // ignore context-only matches
      }
  
      @Override
      public Query rewrite(IndexReader reader) throws IOException {
        BooleanQuery result = new BooleanQuery() {
  
          @Override
          public Similarity getSimilarity(Searcher searcher) {
            return new DefaultSimilarity() {
  
              @Override
              public float coord(int overlap, int max) {
                switch (overlap) {
  
                case 1:                               // matched only one clause
                  return 1.0f;                        // use the score as-is
  
                case 2:                               // matched both clauses
                  return boost;                       // multiply by boost
  
                default:
                  return 0.0f;
                  
                }
              }
            };
          }
        };
  
        result.add(match, BooleanClause.Occur.MUST);
        result.add(context, BooleanClause.Occur.SHOULD);
  
        return result;
      }
  
      @Override
      public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + Float.floatToIntBits(boost);
        result = prime * result + ((context == null) ? 0 : context.hashCode());
        result = prime * result + ((match == null) ? 0 : match.hashCode());
        return result;
      }
  
      @Override
      public boolean equals(Object obj) {
        if (this == obj)
          return true;
        if (obj == null)
          return false;
        if (getClass() != obj.getClass())
          return false;
        BoostingQuery other = (BoostingQuery) obj;
        if (Float.floatToIntBits(boost) != Float.floatToIntBits(other.boost))
          return false;
        if (context == null) {
          if (other.context != null)
            return false;
        } else if (!context.equals(other.context))
          return false;
        if (match == null) {
          if (other.match != null)
            return false;
        } else if (!match.equals(other.match))
          return false;
        return true;
      }
  
      @Override
      public String toString(String field) {
        return match.toString(field) + "/" + context.toString(field);
      }
    }
  