Lucene.Net  3.0.3
Lucene.Net is a port of the Lucene search engine library, written in C# and targeted at .NET runtime users.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
ConjunctionScorer.cs
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 using System;
19 using System.Linq;
20 
21 namespace Lucene.Net.Search
22 {
23 
24  /// <summary>Scorer for conjunctions, sets of queries, all of which are required. </summary>
26  {
27  private Scorer[] scorers;
28  private float coord;
29  private int lastDoc = - 1;
30 
31  public ConjunctionScorer(Similarity similarity, System.Collections.Generic.ICollection<Scorer> scorers)
32  : this(similarity, scorers.ToArray())
33  {
34  }
35 
36  public ConjunctionScorer(Similarity similarity, params Scorer[] scorers):base(similarity)
37  {
38  this.scorers = scorers;
39  coord = similarity.Coord(scorers.Length, scorers.Length);
40 
41  for (int i = 0; i < scorers.Length; i++)
42  {
43  if (scorers[i].NextDoc() == NO_MORE_DOCS)
44  {
45  // If even one of the sub-scorers does not have any documents, this
46  // scorer should not attempt to do any more work.
47  lastDoc = NO_MORE_DOCS;
48  return ;
49  }
50  }
51 
52  // Sort the array the first time...
53  // We don't need to sort the array in any future calls because we know
54  // it will already start off sorted (all scorers on same doc).
55 
56  // note that this comparator is not consistent with equals!
57  System.Array.Sort(scorers, (a, b) => a.DocID() - b.DocID());
58 
59  // NOTE: doNext() must be called before the re-sorting of the array later on.
60  // The reason is this: assume there are 5 scorers, whose first docs are 1,
61  // 2, 3, 5, 5 respectively. Sorting (above) leaves the array as is. Calling
62  // doNext() here advances all the first scorers to 5 (or a larger doc ID
63  // they all agree on).
64  // However, if we re-sort before doNext() is called, the order will be 5, 3,
65  // 2, 1, 5 and then doNext() will stop immediately, since the first scorer's
66  // docs equals the last one. So the invariant that after calling doNext()
67  // all scorers are on the same doc ID is broken.);
68  if (DoNext() == NO_MORE_DOCS)
69  {
70  // The scorers did not agree on any document.
71  lastDoc = NO_MORE_DOCS;
72  return ;
73  }
74 
75  // If first-time skip distance is any predictor of
76  // scorer sparseness, then we should always try to skip first on
77  // those scorers.
78  // Keep last scorer in it's last place (it will be the first
79  // to be skipped on), but reverse all of the others so that
80  // they will be skipped on in order of original high skip.
81  int end = scorers.Length - 1;
82  int max = end >> 1;
83  for (int i = 0; i < max; i++)
84  {
85  Scorer tmp = scorers[i];
86  int idx = end - i - 1;
87  scorers[i] = scorers[idx];
88  scorers[idx] = tmp;
89  }
90  }
91 
92  private int DoNext()
93  {
94  int first = 0;
95  int doc = scorers[scorers.Length - 1].DocID();
96  Scorer firstScorer;
97  while ((firstScorer = scorers[first]).DocID() < doc)
98  {
99  doc = firstScorer.Advance(doc);
100  first = first == scorers.Length - 1?0:first + 1;
101  }
102  return doc;
103  }
104 
105  public override int Advance(int target)
106  {
107  if (lastDoc == NO_MORE_DOCS)
108  {
109  return lastDoc;
110  }
111  else if (scorers[(scorers.Length - 1)].DocID() < target)
112  {
113  scorers[(scorers.Length - 1)].Advance(target);
114  }
115  return lastDoc = DoNext();
116  }
117 
118  public override int DocID()
119  {
120  return lastDoc;
121  }
122 
123  public override int NextDoc()
124  {
125  if (lastDoc == NO_MORE_DOCS)
126  {
127  return lastDoc;
128  }
129  else if (lastDoc == - 1)
130  {
131  return lastDoc = scorers[scorers.Length - 1].DocID();
132  }
133  scorers[(scorers.Length - 1)].NextDoc();
134  return lastDoc = DoNext();
135  }
136 
137  public override float Score()
138  {
139  float sum = 0.0f;
140  for (int i = 0; i < scorers.Length; i++)
141  {
142  sum += scorers[i].Score();
143  }
144  return sum * coord;
145  }
146  }
147 }