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