pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / src / test / org / apache / lucene / search / TestScorerPerf.java
1 package org.apache.lucene.search;
2
3 import org.apache.lucene.util.DocIdBitSet;
4 import org.apache.lucene.util.LuceneTestCase;
5
6 import java.util.BitSet;
7 import java.io.IOException;
8
9 import org.apache.lucene.index.IndexReader;
10 import org.apache.lucene.index.IndexWriter;
11 import org.apache.lucene.index.Term;
12 import org.apache.lucene.index.IndexWriterConfig.OpenMode;
13 import org.apache.lucene.store.Directory;
14 import org.apache.lucene.analysis.MockAnalyzer;
15 import org.apache.lucene.document.Document;
16 import org.apache.lucene.document.Field;
17
18 /**
19  * Licensed to the Apache Software Foundation (ASF) under one or more
20  * contributor license agreements.  See the NOTICE file distributed with
21  * this work for additional information regarding copyright ownership.
22  * The ASF licenses this file to You under the Apache License, Version 2.0
23  * (the "License"); you may not use this file except in compliance with
24  * the License.  You may obtain a copy of the License at
25  *
26  *     http://www.apache.org/licenses/LICENSE-2.0
27  *
28  * Unless required by applicable law or agreed to in writing, software
29  * distributed under the License is distributed on an "AS IS" BASIS,
30  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31  * See the License for the specific language governing permissions and
32  * limitations under the License.
33  */
34
35 public class TestScorerPerf extends LuceneTestCase {
36   boolean validate = true;  // set to false when doing performance testing
37
38   BitSet[] sets;
39   Term[] terms;
40   IndexSearcher s;
41   IndexReader r;
42   Directory d;
43
44   // TODO: this should be setUp()....
45   public void createDummySearcher() throws Exception {
46       // Create a dummy index with nothing in it.
47     // This could possibly fail if Lucene starts checking for docid ranges...
48     d = newDirectory();
49     IndexWriter iw = new IndexWriter(d, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
50     iw.addDocument(new Document());
51     iw.close();
52     r = IndexReader.open(d);
53     s = new IndexSearcher(r);
54   }
55
56   public void createRandomTerms(int nDocs, int nTerms, double power, Directory dir) throws Exception {
57     int[] freq = new int[nTerms];
58     terms = new Term[nTerms];
59     for (int i=0; i<nTerms; i++) {
60       int f = (nTerms+1)-i;  // make first terms less frequent
61       freq[i] = (int)Math.ceil(Math.pow(f,power));
62       terms[i] = new Term("f",Character.toString((char)('A'+i)));
63     }
64
65     IndexWriter iw = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).setOpenMode(OpenMode.CREATE));
66     for (int i=0; i<nDocs; i++) {
67       Document d = new Document();
68       for (int j=0; j<nTerms; j++) {
69         if (random.nextInt(freq[j]) == 0) {
70           d.add(newField("f", terms[j].text(), Field.Store.NO, Field.Index.NOT_ANALYZED));
71           //System.out.println(d);
72         }
73       }
74       iw.addDocument(d);
75     }
76     iw.forceMerge(1);
77     iw.close();
78   }
79
80
81   public BitSet randBitSet(int sz, int numBitsToSet) {
82     BitSet set = new BitSet(sz);
83     for (int i=0; i<numBitsToSet; i++) {
84       set.set(random.nextInt(sz));
85     }
86     return set;
87   }
88
89   public BitSet[] randBitSets(int numSets, int setSize) {
90     BitSet[] sets = new BitSet[numSets];
91     for (int i=0; i<sets.length; i++) {
92       sets[i] = randBitSet(setSize, random.nextInt(setSize));
93     }
94     return sets;
95   }
96
97   public static class CountingHitCollector extends Collector {
98     int count=0;
99     int sum=0;
100     protected int docBase = 0;
101
102     @Override
103     public void setScorer(Scorer scorer) throws IOException {}
104     
105     @Override
106     public void collect(int doc) {
107       count++;
108       sum += docBase + doc;  // use it to avoid any possibility of being eliminated by hotspot
109     }
110
111     public int getCount() { return count; }
112     public int getSum() { return sum; }
113
114     @Override
115     public void setNextReader(IndexReader reader, int base) {
116       docBase = base;
117     }
118     @Override
119     public boolean acceptsDocsOutOfOrder() {
120       return true;
121     }
122   }
123
124
125   public static class MatchingHitCollector extends CountingHitCollector {
126     BitSet answer;
127     int pos=-1;
128     public MatchingHitCollector(BitSet answer) {
129       this.answer = answer;
130     }
131
132     public void collect(int doc, float score) {
133       
134       pos = answer.nextSetBit(pos+1);
135       if (pos != doc + docBase) {
136         throw new RuntimeException("Expected doc " + pos + " but got " + doc + docBase);
137       }
138       super.collect(doc);
139     }
140   }
141
142
143   BitSet addClause(BooleanQuery bq, BitSet result) {
144     final BitSet rnd = sets[random.nextInt(sets.length)];
145     Query q = new ConstantScoreQuery(new Filter() {
146       @Override
147       public DocIdSet getDocIdSet(IndexReader reader) {
148         return new DocIdBitSet(rnd);
149       }
150     });
151     bq.add(q, BooleanClause.Occur.MUST);
152     if (validate) {
153       if (result==null) result = (BitSet)rnd.clone();
154       else result.and(rnd);
155     }
156     return result;
157   }
158
159
160   public int doConjunctions(int iter, int maxClauses) throws IOException {
161     int ret=0;
162
163     for (int i=0; i<iter; i++) {
164       int nClauses = random.nextInt(maxClauses-1)+2; // min 2 clauses
165       BooleanQuery bq = new BooleanQuery();
166       BitSet result=null;
167       for (int j=0; j<nClauses; j++) {
168         result = addClause(bq,result);
169       }
170
171       CountingHitCollector hc = validate ? new MatchingHitCollector(result)
172                                          : new CountingHitCollector();
173       s.search(bq, hc);
174       ret += hc.getSum();
175
176       if (validate) assertEquals(result.cardinality(), hc.getCount());
177       // System.out.println(hc.getCount());
178     }
179     
180     return ret;
181   }
182
183   public int doNestedConjunctions(int iter, int maxOuterClauses, int maxClauses) throws IOException {
184     int ret=0;
185     long nMatches=0;
186
187     for (int i=0; i<iter; i++) {
188       int oClauses = random.nextInt(maxOuterClauses-1)+2;
189       BooleanQuery oq = new BooleanQuery();
190       BitSet result=null;
191
192       for (int o=0; o<oClauses; o++) {
193
194       int nClauses = random.nextInt(maxClauses-1)+2; // min 2 clauses
195       BooleanQuery bq = new BooleanQuery();
196       for (int j=0; j<nClauses; j++) {
197         result = addClause(bq,result);
198       }
199
200       oq.add(bq, BooleanClause.Occur.MUST);
201       } // outer
202
203       CountingHitCollector hc = validate ? new MatchingHitCollector(result)
204                                          : new CountingHitCollector();
205       s.search(oq, hc);
206       nMatches += hc.getCount();
207       ret += hc.getSum();
208       if (validate) assertEquals(result.cardinality(), hc.getCount());
209       // System.out.println(hc.getCount());
210     }
211     if (VERBOSE) System.out.println("Average number of matches="+(nMatches/iter));
212     return ret;
213   }
214
215   
216   public int doTermConjunctions(IndexSearcher s,
217                                 int termsInIndex,
218                                 int maxClauses,
219                                 int iter
220   ) throws IOException {
221     int ret=0;
222
223     long nMatches=0;
224     for (int i=0; i<iter; i++) {
225       int nClauses = random.nextInt(maxClauses-1)+2; // min 2 clauses
226       BooleanQuery bq = new BooleanQuery();
227       BitSet termflag = new BitSet(termsInIndex);
228       for (int j=0; j<nClauses; j++) {
229         int tnum;
230         // don't pick same clause twice
231         tnum = random.nextInt(termsInIndex);
232         if (termflag.get(tnum)) tnum=termflag.nextClearBit(tnum);
233         if (tnum<0 || tnum>=termsInIndex) tnum=termflag.nextClearBit(0);
234         termflag.set(tnum);
235         Query tq = new TermQuery(terms[tnum]);
236         bq.add(tq, BooleanClause.Occur.MUST);
237       }
238
239       CountingHitCollector hc = new CountingHitCollector();
240       s.search(bq, hc);
241       nMatches += hc.getCount();
242       ret += hc.getSum();
243     }
244     if (VERBOSE) System.out.println("Average number of matches="+(nMatches/iter));
245
246     return ret;
247   }
248
249
250   public int doNestedTermConjunctions(IndexSearcher s,
251                                 int termsInIndex,
252                                 int maxOuterClauses,
253                                 int maxClauses,
254                                 int iter
255   ) throws IOException {
256     int ret=0;
257     long nMatches=0;
258     for (int i=0; i<iter; i++) {
259       int oClauses = random.nextInt(maxOuterClauses-1)+2;
260       BooleanQuery oq = new BooleanQuery();
261       for (int o=0; o<oClauses; o++) {
262
263       int nClauses = random.nextInt(maxClauses-1)+2; // min 2 clauses
264       BooleanQuery bq = new BooleanQuery();
265       BitSet termflag = new BitSet(termsInIndex);
266       for (int j=0; j<nClauses; j++) {
267         int tnum;
268         // don't pick same clause twice
269         tnum = random.nextInt(termsInIndex);
270         if (termflag.get(tnum)) tnum=termflag.nextClearBit(tnum);
271         if (tnum<0 || tnum>=25) tnum=termflag.nextClearBit(0);
272         termflag.set(tnum);
273         Query tq = new TermQuery(terms[tnum]);
274         bq.add(tq, BooleanClause.Occur.MUST);
275       } // inner
276
277       oq.add(bq, BooleanClause.Occur.MUST);
278       } // outer
279
280
281       CountingHitCollector hc = new CountingHitCollector();
282       s.search(oq, hc);
283       nMatches += hc.getCount();     
284       ret += hc.getSum();
285     }
286     if (VERBOSE) System.out.println("Average number of matches="+(nMatches/iter));
287     return ret;
288   }
289
290
291     public int doSloppyPhrase(IndexSearcher s,
292                                 int termsInIndex,
293                                 int maxClauses,
294                                 int iter
295   ) throws IOException {
296     int ret=0;
297
298     for (int i=0; i<iter; i++) {
299       int nClauses = random.nextInt(maxClauses-1)+2; // min 2 clauses
300       PhraseQuery q = new PhraseQuery();
301       for (int j=0; j<nClauses; j++) {
302         int tnum = random.nextInt(termsInIndex);
303         q.add(new Term("f",Character.toString((char)(tnum+'A'))), j);
304       }
305       q.setSlop(termsInIndex);  // this could be random too
306
307       CountingHitCollector hc = new CountingHitCollector();
308       s.search(q, hc);
309       ret += hc.getSum();
310     }
311
312     return ret;
313   }
314
315
316   public void testConjunctions() throws Exception {
317     // test many small sets... the bugs will be found on boundary conditions
318     createDummySearcher();
319     validate=true;
320     sets=randBitSets(atLeast(1000), atLeast(10));
321     doConjunctions(atLeast(10000), atLeast(5));
322     doNestedConjunctions(atLeast(10000), atLeast(3), atLeast(3));
323     s.close();
324     r.close();
325     d.close();
326   }
327
328   /***
329   int bigIter=10;
330
331   public void testConjunctionPerf() throws Exception {
332     r = newRandom();
333     createDummySearcher();
334     validate=false;
335     sets=randBitSets(32,1000000);
336     for (int i=0; i<bigIter; i++) {
337       long start = System.currentTimeMillis();
338       doConjunctions(500,6);
339       long end = System.currentTimeMillis();
340       if (VERBOSE) System.out.println("milliseconds="+(end-start));
341     }
342     s.close();
343   }
344
345   public void testNestedConjunctionPerf() throws Exception {
346     r = newRandom();
347     createDummySearcher();
348     validate=false;
349     sets=randBitSets(32,1000000);
350     for (int i=0; i<bigIter; i++) {
351       long start = System.currentTimeMillis();
352       doNestedConjunctions(500,3,3);
353       long end = System.currentTimeMillis();
354       if (VERBOSE) System.out.println("milliseconds="+(end-start));
355     }
356     s.close();
357   }
358
359
360   public void testConjunctionTerms() throws Exception {
361     r = newRandom();
362     validate=false;
363     RAMDirectory dir = new RAMDirectory();
364     if (VERBOSE) System.out.println("Creating index");
365     createRandomTerms(100000,25,.5, dir);
366     s = new IndexSearcher(dir, true);
367     if (VERBOSE) System.out.println("Starting performance test");
368     for (int i=0; i<bigIter; i++) {
369       long start = System.currentTimeMillis();
370       doTermConjunctions(s,25,5,1000);
371       long end = System.currentTimeMillis();
372       if (VERBOSE) System.out.println("milliseconds="+(end-start));
373     }
374     s.close();
375   }
376
377   public void testNestedConjunctionTerms() throws Exception {
378     r = newRandom();
379     validate=false;    
380     RAMDirectory dir = new RAMDirectory();
381     if (VERBOSE) System.out.println("Creating index");
382     createRandomTerms(100000,25,.2, dir);
383     s = new IndexSearcher(dir, true);
384     if (VERBOSE) System.out.println("Starting performance test");
385     for (int i=0; i<bigIter; i++) {
386       long start = System.currentTimeMillis();
387       doNestedTermConjunctions(s,25,3,3,200);
388       long end = System.currentTimeMillis();
389       if (VERBOSE) System.out.println("milliseconds="+(end-start));
390     }
391     s.close();
392   }
393
394
395   public void testSloppyPhrasePerf() throws Exception {
396     r = newRandom();
397     validate=false;    
398     RAMDirectory dir = new RAMDirectory();
399     if (VERBOSE) System.out.println("Creating index");
400     createRandomTerms(100000,25,2,dir);
401     s = new IndexSearcher(dir, true);
402     if (VERBOSE) System.out.println("Starting performance test");
403     for (int i=0; i<bigIter; i++) {
404       long start = System.currentTimeMillis();
405       doSloppyPhrase(s,25,2,1000);
406       long end = System.currentTimeMillis();
407       if (VERBOSE) System.out.println("milliseconds="+(end-start));
408     }
409     s.close();
410   }
411    ***/
412
413
414 }