add --shared
[pylucene.git] / lucene-java-3.4.0 / lucene / src / java / org / apache / lucene / search / TermQuery.java
1 package org.apache.lucene.search;
2
3 /**
4  * Licensed to the Apache Software Foundation (ASF) under one or more
5  * contributor license agreements.  See the NOTICE file distributed with
6  * this work for additional information regarding copyright ownership.
7  * The ASF licenses this file to You under the Apache License, Version 2.0
8  * (the "License"); you may not use this file except in compliance with
9  * the License.  You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 import java.io.IOException;
21 import java.util.HashSet;
22 import java.util.Set;
23
24 import org.apache.lucene.index.Term;
25 import org.apache.lucene.index.TermDocs;
26 import org.apache.lucene.index.IndexReader;
27 import org.apache.lucene.search.Explanation.IDFExplanation;
28 import org.apache.lucene.util.ReaderUtil;
29 import org.apache.lucene.util.ToStringUtils;
30
31 /** A Query that matches documents containing a term.
32   This may be combined with other terms with a {@link BooleanQuery}.
33   */
34 public class TermQuery extends Query {
35   private Term term;
36
37   private class TermWeight extends Weight {
38     private final Similarity similarity;
39     private float value;
40     private float idf;
41     private float queryNorm;
42     private float queryWeight;
43     private IDFExplanation idfExp;
44     private final Set<Integer> hash;
45
46     public TermWeight(Searcher searcher)
47       throws IOException {
48       this.similarity = getSimilarity(searcher);
49       if (searcher instanceof IndexSearcher) {
50         hash = new HashSet<Integer>();
51         IndexReader ir = ((IndexSearcher)searcher).getIndexReader();
52         final int dfSum[] = new int[1];
53         new ReaderUtil.Gather(ir) {
54           @Override
55           protected void add(int base, IndexReader r) throws IOException {
56             int df = r.docFreq(term);
57             dfSum[0] += df;
58             if (df > 0) {
59               hash.add(r.hashCode());
60             }
61           }
62         }.run();
63
64         idfExp = similarity.idfExplain(term, searcher, dfSum[0]);
65       } else {
66         idfExp = similarity.idfExplain(term, searcher);
67         hash = null;
68       }
69
70       idf = idfExp.getIdf();
71     }
72
73     @Override
74     public String toString() { return "weight(" + TermQuery.this + ")"; }
75
76     @Override
77     public Query getQuery() { return TermQuery.this; }
78
79     @Override
80     public float getValue() { return value; }
81
82     @Override
83     public float sumOfSquaredWeights() {
84       queryWeight = idf * getBoost();             // compute query weight
85       return queryWeight * queryWeight;           // square it
86     }
87
88     @Override
89     public void normalize(float queryNorm) {
90       this.queryNorm = queryNorm;
91       queryWeight *= queryNorm;                   // normalize query weight
92       value = queryWeight * idf;                  // idf for document
93     }
94
95     @Override
96     public Scorer scorer(IndexReader reader, boolean scoreDocsInOrder, boolean topScorer) throws IOException {
97       if (hash != null && !hash.contains(reader.hashCode())) {
98         return null;
99       }
100       
101       TermDocs termDocs = reader.termDocs(term);
102
103       if (termDocs == null)
104         return null;
105
106       return new TermScorer(this, termDocs, similarity, reader.norms(term.field()));
107     }
108
109     @Override
110     public Explanation explain(IndexReader reader, int doc)
111       throws IOException {
112
113       ComplexExplanation result = new ComplexExplanation();
114       result.setDescription("weight("+getQuery()+" in "+doc+"), product of:");
115
116       Explanation expl = new Explanation(idf, idfExp.explain());
117
118       // explain query weight
119       Explanation queryExpl = new Explanation();
120       queryExpl.setDescription("queryWeight(" + getQuery() + "), product of:");
121
122       Explanation boostExpl = new Explanation(getBoost(), "boost");
123       if (getBoost() != 1.0f)
124         queryExpl.addDetail(boostExpl);
125       queryExpl.addDetail(expl);
126
127       Explanation queryNormExpl = new Explanation(queryNorm,"queryNorm");
128       queryExpl.addDetail(queryNormExpl);
129
130       queryExpl.setValue(boostExpl.getValue() *
131                          expl.getValue() *
132                          queryNormExpl.getValue());
133
134       result.addDetail(queryExpl);
135
136       // explain field weight
137       String field = term.field();
138       ComplexExplanation fieldExpl = new ComplexExplanation();
139       fieldExpl.setDescription("fieldWeight("+term+" in "+doc+
140                                "), product of:");
141
142       Explanation tfExplanation = new Explanation();
143       int tf = 0;
144       TermDocs termDocs = reader.termDocs(term);
145       if (termDocs != null) {
146         try {
147           if (termDocs.skipTo(doc) && termDocs.doc() == doc) {
148             tf = termDocs.freq();
149           }
150         } finally {
151           termDocs.close();
152         }
153         tfExplanation.setValue(similarity.tf(tf));
154         tfExplanation.setDescription("tf(termFreq("+term+")="+tf+")");
155       } else {
156         tfExplanation.setValue(0.0f);
157         tfExplanation.setDescription("no matching term");
158       }
159       fieldExpl.addDetail(tfExplanation);
160       fieldExpl.addDetail(expl);
161
162       Explanation fieldNormExpl = new Explanation();
163       byte[] fieldNorms = reader.norms(field);
164       float fieldNorm =
165         fieldNorms!=null ? similarity.decodeNormValue(fieldNorms[doc]) : 1.0f;
166       fieldNormExpl.setValue(fieldNorm);
167       fieldNormExpl.setDescription("fieldNorm(field="+field+", doc="+doc+")");
168       fieldExpl.addDetail(fieldNormExpl);
169       
170       fieldExpl.setMatch(Boolean.valueOf(tfExplanation.isMatch()));
171       fieldExpl.setValue(tfExplanation.getValue() *
172                          expl.getValue() *
173                          fieldNormExpl.getValue());
174
175       result.addDetail(fieldExpl);
176       result.setMatch(fieldExpl.getMatch());
177       
178       // combine them
179       result.setValue(queryExpl.getValue() * fieldExpl.getValue());
180
181       if (queryExpl.getValue() == 1.0f)
182         return fieldExpl;
183
184       return result;
185     }
186   }
187
188   /** Constructs a query for the term <code>t</code>. */
189   public TermQuery(Term t) {
190     term = t;
191   }
192
193   /** Returns the term of this query. */
194   public Term getTerm() { return term; }
195
196   @Override
197   public Weight createWeight(Searcher searcher) throws IOException {
198     return new TermWeight(searcher);
199   }
200
201   @Override
202   public void extractTerms(Set<Term> terms) {
203     terms.add(getTerm());
204   }
205
206   /** Prints a user-readable version of this query. */
207   @Override
208   public String toString(String field) {
209     StringBuilder buffer = new StringBuilder();
210     if (!term.field().equals(field)) {
211       buffer.append(term.field());
212       buffer.append(":");
213     }
214     buffer.append(term.text());
215     buffer.append(ToStringUtils.boost(getBoost()));
216     return buffer.toString();
217   }
218
219   /** Returns true iff <code>o</code> is equal to this. */
220   @Override
221   public boolean equals(Object o) {
222     if (!(o instanceof TermQuery))
223       return false;
224     TermQuery other = (TermQuery)o;
225     return (this.getBoost() == other.getBoost())
226       && this.term.equals(other.term);
227   }
228
229   /** Returns a hash code value for this object.*/
230   @Override
231   public int hashCode() {
232     return Float.floatToIntBits(getBoost()) ^ term.hashCode();
233   }
234
235 }