pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / contrib / highlighter / src / java / org / apache / lucene / search / highlight / QueryTermExtractor.java
1 package org.apache.lucene.search.highlight;
2 /**
3  * Licensed to the Apache Software Foundation (ASF) under one or more
4  * contributor license agreements.  See the NOTICE file distributed with
5  * this work for additional information regarding copyright ownership.
6  * The ASF licenses this file to You under the Apache License, Version 2.0
7  * (the "License"); you may not use this file except in compliance with
8  * the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 import java.io.IOException;
20 import java.util.HashSet;
21 import java.util.Iterator;
22
23 import org.apache.lucene.index.IndexReader;
24 import org.apache.lucene.index.Term;
25 import org.apache.lucene.search.BooleanClause;
26 import org.apache.lucene.search.BooleanQuery;
27 import org.apache.lucene.search.FilteredQuery;
28 import org.apache.lucene.search.Query;
29 import org.apache.lucene.util.StringHelper;
30
31 /**
32  * Utility class used to extract the terms used in a query, plus any weights.
33  * This class will not find terms for MultiTermQuery, TermRangeQuery and PrefixQuery classes
34  * so the caller must pass a rewritten query (see Query.rewrite) to obtain a list of 
35  * expanded terms. 
36  * 
37  */
38 public final class QueryTermExtractor
39 {
40
41         /**
42          * Extracts all terms texts of a given Query into an array of WeightedTerms
43          *
44          * @param query      Query to extract term texts from
45          * @return an array of the terms used in a query, plus their weights.
46          */
47         public static final WeightedTerm[] getTerms(Query query) 
48         {
49                 return getTerms(query,false);
50         }
51
52         /**
53          * Extracts all terms texts of a given Query into an array of WeightedTerms
54          *
55          * @param query      Query to extract term texts from
56          * @param reader used to compute IDF which can be used to a) score selected fragments better 
57          * b) use graded highlights eg changing intensity of font color
58          * @param fieldName the field on which Inverse Document Frequency (IDF) calculations are based
59          * @return an array of the terms used in a query, plus their weights.
60          */
61         public static final WeightedTerm[] getIdfWeightedTerms(Query query, IndexReader reader, String fieldName) 
62         {
63             WeightedTerm[] terms=getTerms(query,false, fieldName);
64             int totalNumDocs=reader.numDocs();
65             for (int i = 0; i < terms.length; i++)
66         {
67                 try
68             {
69                 int docFreq=reader.docFreq(new Term(fieldName,terms[i].term));
70                 // docFreq counts deletes
71                 if(totalNumDocs < docFreq) {
72                   docFreq = totalNumDocs;
73                 }
74                 //IDF algorithm taken from DefaultSimilarity class
75                 float idf=(float)(Math.log((float)totalNumDocs/(double)(docFreq+1)) + 1.0);
76                 terms[i].weight*=idf;
77             } 
78                 catch (IOException e)
79             {
80                     //ignore 
81             }
82         }
83                 return terms;
84         }
85
86         /**
87          * Extracts all terms texts of a given Query into an array of WeightedTerms
88          *
89          * @param query      Query to extract term texts from
90          * @param prohibited <code>true</code> to extract "prohibited" terms, too
91          * @param fieldName  The fieldName used to filter query terms
92    * @return an array of the terms used in a query, plus their weights.
93    */
94         public static final WeightedTerm[] getTerms(Query query, boolean prohibited, String fieldName) 
95         {
96                 HashSet<WeightedTerm> terms=new HashSet<WeightedTerm>();
97                 if(fieldName!=null)
98                 {
99                     fieldName= StringHelper.intern(fieldName);
100                 }
101                 getTerms(query,terms,prohibited,fieldName);
102                 return terms.toArray(new WeightedTerm[0]);
103         }
104         
105         /**
106          * Extracts all terms texts of a given Query into an array of WeightedTerms
107          *
108          * @param query      Query to extract term texts from
109          * @param prohibited <code>true</code> to extract "prohibited" terms, too
110    * @return an array of the terms used in a query, plus their weights.
111    */
112         public static final WeightedTerm[] getTerms(Query query, boolean prohibited) 
113         {
114             return getTerms(query,prohibited,null);
115         }       
116
117         //fieldname MUST be interned prior to this call
118         private static final void getTerms(Query query, HashSet<WeightedTerm> terms,boolean prohibited, String fieldName) 
119         {
120         try
121         {
122                 if (query instanceof BooleanQuery)
123                         getTermsFromBooleanQuery((BooleanQuery) query, terms, prohibited, fieldName);
124                 else
125                         if(query instanceof FilteredQuery)
126                                 getTermsFromFilteredQuery((FilteredQuery)query, terms,prohibited, fieldName);
127                         else
128                 {
129                         HashSet<Term> nonWeightedTerms=new HashSet<Term>();
130                         query.extractTerms(nonWeightedTerms);
131                         for (Iterator<Term> iter = nonWeightedTerms.iterator(); iter.hasNext();)
132                                 {
133                                         Term term = iter.next();
134                                     if((fieldName==null)||(term.field()==fieldName))
135                                         {
136                                                 terms.add(new WeightedTerm(query.getBoost(),term.text()));
137                                         }
138                                 }
139                 }
140               }
141               catch(UnsupportedOperationException ignore)
142               {
143                   //this is non-fatal for our purposes
144           }                                                             
145         }
146
147         /**
148          * extractTerms is currently the only query-independent means of introspecting queries but it only reveals
149          * a list of terms for that query - not the boosts each individual term in that query may or may not have.
150          * "Container" queries such as BooleanQuery should be unwrapped to get at the boost info held
151          * in each child element. 
152          * Some discussion around this topic here:
153          * http://www.gossamer-threads.com/lists/lucene/java-dev/34208?search_string=introspection;#34208
154          * Unfortunately there seemed to be limited interest in requiring all Query objects to implement
155          * something common which would allow access to child queries so what follows here are query-specific
156          * implementations for accessing embedded query elements. 
157          */
158         private static final void getTermsFromBooleanQuery(BooleanQuery query, HashSet<WeightedTerm> terms, boolean prohibited, String fieldName)
159         {
160                 BooleanClause[] queryClauses = query.getClauses();
161                 for (int i = 0; i < queryClauses.length; i++)
162                 {
163                         if (prohibited || queryClauses[i].getOccur()!=BooleanClause.Occur.MUST_NOT)
164                                 getTerms(queryClauses[i].getQuery(), terms, prohibited, fieldName);
165                 }
166         }       
167         private static void getTermsFromFilteredQuery(FilteredQuery query, HashSet<WeightedTerm> terms, boolean prohibited, String fieldName)
168         {
169                 getTerms(query.getQuery(),terms,prohibited,fieldName);          
170         }
171         
172 }