View Javadoc
1   /*
2    * Copyright [2017] Wikimedia Foundation
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.wikimedia.search.extra.simswitcher;
18  
19  import static java.util.Objects.requireNonNull;
20  
21  import java.io.IOException;
22  import java.util.Objects;
23  
24  import org.apache.lucene.search.IndexSearcher;
25  import org.apache.lucene.search.Query;
26  import org.apache.lucene.search.ScoreMode;
27  import org.apache.lucene.search.Weight;
28  import org.apache.lucene.search.similarities.Similarity;
29  
30  import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
31  
32  /**
33   * Query wrapper that overrides the similarity provided
34   * by the IndexSearcher by a custom one.
35   * Useful to quickly test the impact of given similarity
36   * without reindexing the whole index.
37   */
38  public class SimSwitcherQuery extends Query {
39      private final Similarity similarity;
40      private final Query subQuery;
41  
42      /**
43       * Builds a new SimSwitcherQuery.
44       */
45      public SimSwitcherQuery(Similarity similarity, Query subQuery) {
46          this.similarity = requireNonNull(similarity);
47          this.subQuery = requireNonNull(subQuery);
48      }
49  
50  
51      @Override
52      public String toString(String field) {
53          return "simswitch:" + field;
54      }
55  
56      @Override
57      @SuppressFBWarnings(value = "BC_EQUALS_METHOD_SHOULD_WORK_FOR_ALL_OBJECTS", justification = "handled by sameClassAs")
58      public boolean equals(Object obj) {
59          return sameClassAs(obj) &&
60                  // Use toString as most similarity don't implement hashCode/equals but provide
61                  // all their settings in toString()
62                  Objects.equals(similarity.toString(), ((SimSwitcherQuery)obj).similarity.toString()) &&
63                  Objects.equals(subQuery, ((SimSwitcherQuery)obj).subQuery);
64      }
65  
66      @Override
67      public int hashCode() {
68          return classHash() + Objects.hash(similarity, subQuery);
69      }
70  
71      @Override
72      public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException {
73          if (!scoreMode.needsScores()) {
74              return searcher.createWeight(subQuery, scoreMode, boost);
75          }
76          final Similarity oldSim = searcher.getSimilarity();
77          try {
78              // XXX: hackish, this only works because a searcher
79              // is created per SearchContext (multiple queries does not share the
80              // same ContextIndexSearcher)
81              // and that setSimilarity is delegated to super not the real IndexSearcher
82              searcher.setSimilarity(similarity);
83              return searcher.createWeight(subQuery, scoreMode, boost);
84          } finally {
85              searcher.setSimilarity(oldSim);
86          }
87      }
88  
89      /**
90       * The similarity.
91       */
92      public Similarity getSimilarity() {
93          return similarity;
94      }
95  
96      /**
97       * The sub query.
98       */
99      public Query getSubQuery() {
100         return subQuery;
101     }
102 }