lucenenet-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aro...@apache.org
Subject svn commit: r411501 [17/30] - in /incubator/lucene.net/trunk/C#/src: ./ Demo/DeleteFiles/ Demo/DemoLib/ Demo/DemoLib/HTML/ Demo/IndexFiles/ Demo/IndexHtml/ Demo/SearchFiles/ Lucene.Net/ Lucene.Net/Analysis/ Lucene.Net/Analysis/Standard/ Lucene.Net/Docu...
Date Sun, 04 Jun 2006 02:41:25 GMT
Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/BooleanQuery.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Search/BooleanQuery.cs?rev=411501&r1=411500&r2=411501&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/BooleanQuery.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/BooleanQuery.cs Sat Jun  3 19:41:13 2006
@@ -13,28 +13,57 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 using System;
 using IndexReader = Lucene.Net.Index.IndexReader;
+using ToStringUtils = Lucene.Net.Util.ToStringUtils;
+
 namespace Lucene.Net.Search
 {
 	
 	/// <summary>A Query that matches documents matching boolean combinations of other
-	/// queries, typically {@link TermQuery}s or {@link PhraseQuery}s.
+	/// queries, e.g. {@link TermQuery}s, {@link PhraseQuery}s or other
+	/// BooleanQuerys.
 	/// </summary>
 	[Serializable]
-	public class BooleanQuery:Query, System.ICloneable
+	public class BooleanQuery : Query, System.ICloneable
 	{
+		private class AnonymousClassSimilarityDelegator : SimilarityDelegator
+		{
+			private void  InitBlock(BooleanQuery enclosingInstance)
+			{
+				this.enclosingInstance = enclosingInstance;
+			}
+			private BooleanQuery enclosingInstance;
+			public BooleanQuery Enclosing_Instance
+			{
+				get
+				{
+					return enclosingInstance;
+				}
+				
+			}
+			internal AnonymousClassSimilarityDelegator(BooleanQuery enclosingInstance, Lucene.Net.Search.Similarity Param1):base(Param1)
+			{
+				InitBlock(enclosingInstance);
+			}
+			public override float Coord(int overlap, int maxOverlap)
+			{
+				return 1.0f;
+			}
+		}
 		
-		/// <summary> Default value is 1024.  Use <code>Lucene.Net.maxClauseCount</code>
-		/// system property to override.
-		/// </summary>
-		public static int maxClauseCount = System.Int32.Parse(SupportClass.AppSettings.Get("Lucene.Net.maxClauseCount", "1024"));
+		/// <deprecated> use {@link #SetMaxClauseCount(int)} instead
+		/// </deprecated>
+		public static int maxClauseCount = 1024;
 		
 		/// <summary>Thrown when an attempt is made to add more than {@link
-		/// #GetMaxClauseCount()} clauses. 
+		/// #GetMaxClauseCount()} clauses. This typically happens if
+		/// a PrefixQuery, FuzzyQuery, WildcardQuery, or RangeQuery 
+		/// is expanded to many terms during search. 
 		/// </summary>
 		[Serializable]
-		public class TooManyClauses:System.SystemException
+		public class TooManyClauses : System.SystemException
 		{
 		}
 		
@@ -42,24 +71,116 @@
 		/// Attempts to add more than the permitted number of clauses cause {@link
 		/// TooManyClauses} to be thrown.
 		/// </summary>
+		/// <seealso cref="SetMaxClauseCount(int)">
+		/// </seealso>
 		public static int GetMaxClauseCount()
 		{
 			return maxClauseCount;
 		}
 		
-		/// <summary>Set the maximum number of clauses permitted. </summary>
+		/// <summary>Set the maximum number of clauses permitted per BooleanQuery.
+		/// Default value is 1024.
+		/// <p>TermQuery clauses are generated from for example prefix queries and
+		/// fuzzy queries. Each TermQuery needs some buffer space during search,
+		/// so this parameter indirectly controls the maximum buffer requirements for
+		/// query search.
+		/// <p>When this parameter becomes a bottleneck for a Query one can use a
+		/// Filter. For example instead of a {@link RangeQuery} one can use a
+		/// {@link RangeFilter}.
+		/// <p>Normally the buffers are allocated by the JVM. When using for example
+		/// {@link Lucene.Net.store.MMapDirectory} the buffering is left to
+		/// the operating system.
+		/// </summary>
 		public static void  SetMaxClauseCount(int maxClauseCount)
 		{
+			if (maxClauseCount < 1)
+				throw new System.ArgumentException("maxClauseCount must be >= 1");
 			BooleanQuery.maxClauseCount = maxClauseCount;
 		}
 		
 		private System.Collections.ArrayList clauses = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
+		private bool disableCoord;
 		
 		/// <summary>Constructs an empty boolean query. </summary>
 		public BooleanQuery()
 		{
 		}
 		
+		/// <summary>Constructs an empty boolean query.
+		/// 
+		/// {@link Similarity#Coord(int,int)} may be disabled in scoring, as
+		/// appropriate. For example, this score factor does not make sense for most
+		/// automatically generated queries, like {@link WildcardQuery} and {@link
+		/// FuzzyQuery}.
+		/// 
+		/// </summary>
+		/// <param name="disableCoord">disables {@link Similarity#Coord(int,int)} in scoring.
+		/// </param>
+		public BooleanQuery(bool disableCoord)
+		{
+			this.disableCoord = disableCoord;
+		}
+		
+		/// <summary>Returns true iff {@link Similarity#Coord(int,int)} is disabled in
+		/// scoring for this query instance.
+		/// </summary>
+		/// <seealso cref="BooleanQuery(boolean)">
+		/// </seealso>
+		public virtual bool IsCoordDisabled()
+		{
+			return disableCoord;
+		}
+		
+		// Implement coord disabling.
+		// Inherit javadoc.
+		public override Similarity GetSimilarity(Searcher searcher)
+		{
+			Similarity result = base.GetSimilarity(searcher);
+			if (disableCoord)
+			{
+				// disable coord as requested
+				result = new AnonymousClassSimilarityDelegator(this, result);
+			}
+			return result;
+		}
+		
+		/// <summary> Specifies a minimum number of the optional BooleanClauses
+		/// which must be satisifed.
+		/// 
+		/// <p>
+		/// By default no optional clauses are neccessary for a match
+		/// (unless there are no required clauses).  If this method is used,
+		/// then the specified numebr of clauses is required.
+		/// </p>
+		/// <p>
+		/// Use of this method is totally independant of specifying that
+		/// any specific clauses are required (or prohibited).  This number will
+		/// only be compared against the number of matching optional clauses.
+		/// </p>
+		/// <p>
+		/// EXPERT NOTE: Using this method will force the use of BooleanWeight2,
+		/// regardless of wether setUseScorer14(true) has been called.
+		/// </p>
+		/// 
+		/// </summary>
+		/// <param name="min">the number of optional clauses that must match
+		/// </param>
+		/// <seealso cref="setUseScorer14">
+		/// </seealso>
+		public virtual void  SetMinimumNumberShouldMatch(int min)
+		{
+			this.minNrShouldMatch = min;
+		}
+		protected internal int minNrShouldMatch = 0;
+		
+		/// <summary> Gets the minimum number of the optional BooleanClauses
+		/// which must be satisifed.
+		/// </summary>
+		public virtual int GetMinimumNumberShouldMatch()
+		{
+			return minNrShouldMatch;
+		}
+		
 		/// <summary>Adds a clause to a boolean query.  Clauses may be:
 		/// <ul>
 		/// <li><code>required</code> which means that documents which <i>do not</i>
@@ -74,15 +195,32 @@
 		/// <code>prohibited</code>.
 		/// 
 		/// </summary>
-		/// <seealso cref="#GetMaxClauseCount()">
-		/// </seealso>
+		/// <deprecated> use {@link #Add(Query, BooleanClause.Occur)} instead:
+		/// <ul>
+		/// <li>For add(query, true, false) use add(query, BooleanClause.Occur.MUST)
+		/// <li>For add(query, false, false) use add(query, BooleanClause.Occur.SHOULD)
+		/// <li>For add(query, false, true) use add(query, BooleanClause.Occur.MUST_NOT)
+		/// </ul>
+		/// </deprecated>
 		public virtual void  Add(Query query, bool required, bool prohibited)
 		{
 			Add(new BooleanClause(query, required, prohibited));
 		}
 		
+		/// <summary>Adds a clause to a boolean query.
+		/// 
+		/// </summary>
+		/// <throws>  TooManyClauses if the new number of clauses exceeds the maximum clause number </throws>
+		/// <seealso cref="GetMaxClauseCount()">
+		/// </seealso>
+		public virtual void  Add(Query query, BooleanClause.Occur occur)
+		{
+			Add(new BooleanClause(query, occur));
+		}
+		
 		/// <summary>Adds a clause to a boolean query.</summary>
-		/// <seealso cref="#GetMaxClauseCount()">
+		/// <throws>  TooManyClauses if the new number of clauses exceeds the maximum clause number </throws>
+		/// <seealso cref="GetMaxClauseCount()">
 		/// </seealso>
 		public virtual void  Add(BooleanClause clause)
 		{
@@ -95,7 +233,7 @@
 		/// <summary>Returns the set of clauses in this query. </summary>
 		public virtual BooleanClause[] GetClauses()
 		{
-            return (BooleanClause[]) clauses.ToArray(typeof(BooleanClause));
+			return (BooleanClause[]) clauses.ToArray(typeof(BooleanClause));
 		}
 		
 		[Serializable]
@@ -106,23 +244,7 @@
 				this.enclosingInstance = enclosingInstance;
 			}
 			private BooleanQuery enclosingInstance;
-            virtual public Query Query
-            {
-                get
-                {
-                    return Enclosing_Instance;
-                }
-				
-            }
-            virtual public float Value
-            {
-                get
-                {
-                    return Enclosing_Instance.GetBoost();
-                }
-				
-            }
-            public BooleanQuery Enclosing_Instance
+			public BooleanQuery Enclosing_Instance
 			{
 				get
 				{
@@ -130,20 +252,29 @@
 				}
 				
 			}
-			private Searcher searcher;
-			private System.Collections.ArrayList weights = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
+			protected internal Similarity similarity;
+			protected internal System.Collections.ArrayList weights = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
 			
 			public BooleanWeight(BooleanQuery enclosingInstance, Searcher searcher)
 			{
 				InitBlock(enclosingInstance);
-				this.searcher = searcher;
+				this.similarity = Enclosing_Instance.GetSimilarity(searcher);
 				for (int i = 0; i < Enclosing_Instance.clauses.Count; i++)
 				{
 					BooleanClause c = (BooleanClause) Enclosing_Instance.clauses[i];
-					weights.Add(c.query.CreateWeight(searcher));
+					weights.Add(c.GetQuery().CreateWeight(searcher));
 				}
 			}
 			
+			public virtual Query GetQuery()
+			{
+				return Enclosing_Instance;
+			}
+			public virtual float GetValue()
+			{
+				return Enclosing_Instance.GetBoost();
+			}
+			
 			public virtual float SumOfSquaredWeights()
 			{
 				float sum = 0.0f;
@@ -151,7 +282,7 @@
 				{
 					BooleanClause c = (BooleanClause) Enclosing_Instance.clauses[i];
 					Weight w = (Weight) weights[i];
-					if (!c.prohibited)
+					if (!c.IsProhibited())
 						sum += w.SumOfSquaredWeights(); // sum sub weights
 				}
 				
@@ -168,11 +299,13 @@
 				{
 					BooleanClause c = (BooleanClause) Enclosing_Instance.clauses[i];
 					Weight w = (Weight) weights[i];
-					if (!c.prohibited)
+					if (!c.IsProhibited())
 						w.Normalize(norm);
 				}
 			}
 			
+			/// <returns> A good old 1.4 Scorer 
+			/// </returns>
 			public virtual Scorer Scorer(IndexReader reader)
 			{
 				// First see if the (faster) ConjunctionScorer will work.  This can be
@@ -186,16 +319,16 @@
 				for (int i = 0; i < weights.Count; i++)
 				{
 					BooleanClause c = (BooleanClause) Enclosing_Instance.clauses[i];
-					if (!c.required)
+					if (!c.IsRequired())
 						allRequired = false;
-					if (c.query is BooleanQuery)
+					if (c.GetQuery() is BooleanQuery)
 						noneBoolean = false;
 				}
 				
 				if (allRequired && noneBoolean)
 				{
 					// ConjunctionScorer is okay
-					ConjunctionScorer result = new ConjunctionScorer(Enclosing_Instance.GetSimilarity(searcher));
+					ConjunctionScorer result = new ConjunctionScorer(similarity);
 					for (int i = 0; i < weights.Count; i++)
 					{
 						Weight w = (Weight) weights[i];
@@ -208,7 +341,7 @@
 				}
 				
 				// Use good-old BooleanScorer instead.
-				BooleanScorer result2 = new BooleanScorer(Enclosing_Instance.GetSimilarity(searcher));
+				BooleanScorer result2 = new BooleanScorer(similarity);
 				
 				for (int i = 0; i < weights.Count; i++)
 				{
@@ -216,8 +349,8 @@
 					Weight w = (Weight) weights[i];
 					Scorer subScorer = w.Scorer(reader);
 					if (subScorer != null)
-						result2.Add(subScorer, c.required, c.prohibited);
-					else if (c.required)
+						result2.Add(subScorer, c.IsRequired(), c.IsProhibited());
+					else if (c.IsRequired())
 						return null;
 				}
 				
@@ -236,11 +369,11 @@
 					BooleanClause c = (BooleanClause) Enclosing_Instance.clauses[i];
 					Weight w = (Weight) weights[i];
 					Explanation e = w.Explain(reader, doc);
-					if (!c.prohibited)
+					if (!c.IsProhibited())
 						maxCoord++;
 					if (e.GetValue() > 0)
 					{
-						if (!c.prohibited)
+						if (!c.IsProhibited())
 						{
 							sumExpl.AddDetail(e);
 							sum += e.GetValue();
@@ -251,7 +384,7 @@
 							return new Explanation(0.0f, "match prohibited");
 						}
 					}
-					else if (c.required)
+					else if (c.IsRequired())
 					{
 						return new Explanation(0.0f, "match required");
 					}
@@ -262,7 +395,7 @@
 				// only one clause matched
 					sumExpl = sumExpl.GetDetails()[0]; // eliminate wrapper
 				
-				float coordFactor = Enclosing_Instance.GetSimilarity(searcher).Coord(coord, maxCoord);
+				float coordFactor = similarity.Coord(coord, maxCoord);
 				if (coordFactor == 1.0f)
 				// coord is no-op
 					return sumExpl;
@@ -279,9 +412,73 @@
 			}
 		}
 		
+		[Serializable]
+		private class BooleanWeight2 : BooleanWeight
+		{
+			private void  InitBlock(BooleanQuery enclosingInstance)
+			{
+				this.enclosingInstance = enclosingInstance;
+			}
+			private BooleanQuery enclosingInstance;
+			public new BooleanQuery Enclosing_Instance
+			{
+				get
+				{
+					return enclosingInstance;
+				}
+				
+			}
+			/* Merge into BooleanWeight in case the 1.4 BooleanScorer is dropped */
+			public BooleanWeight2(BooleanQuery enclosingInstance, Searcher searcher):base(enclosingInstance, searcher)
+			{
+				InitBlock(enclosingInstance);
+			}
+			
+			/// <returns> An alternative Scorer that uses and provides skipTo(),
+			/// and scores documents in document number order.
+			/// </returns>
+			public override Scorer Scorer(IndexReader reader)
+			{
+				BooleanScorer2 result = new BooleanScorer2(similarity, Enclosing_Instance.minNrShouldMatch);
+				
+				for (int i = 0; i < weights.Count; i++)
+				{
+					BooleanClause c = (BooleanClause) Enclosing_Instance.clauses[i];
+					Weight w = (Weight) weights[i];
+					Scorer subScorer = w.Scorer(reader);
+					if (subScorer != null)
+						result.Add(subScorer, c.IsRequired(), c.IsProhibited());
+					else if (c.IsRequired())
+						return null;
+				}
+				
+				return result;
+			}
+		}
+		
+		/// <summary>Indicates whether to use good old 1.4 BooleanScorer. </summary>
+		private static bool useScorer14 = false;
+		
+		public static void  SetUseScorer14(bool use14)
+		{
+			useScorer14 = use14;
+		}
+		
+		public static bool GetUseScorer14()
+		{
+			return useScorer14;
+		}
+		
 		protected internal override Weight CreateWeight(Searcher searcher)
 		{
-			return new BooleanWeight(this, searcher);
+			
+			if (0 < minNrShouldMatch)
+			{
+				// :TODO: should we throw an exception if getUseScorer14 ?
+				return new BooleanWeight2(this, searcher);
+			}
+			
+			return GetUseScorer14() ? (Weight) new BooleanWeight(this, searcher) : (Weight) new BooleanWeight2(this, searcher);
 		}
 		
 		public override Query Rewrite(IndexReader reader)
@@ -290,16 +487,16 @@
 			{
 				// optimize 1-clause queries
 				BooleanClause c = (BooleanClause) clauses[0];
-				if (!c.prohibited)
+				if (!c.IsProhibited())
 				{
 					// just return clause
 					
-					Query query = c.query.Rewrite(reader); // rewrite first
+					Query query = c.GetQuery().Rewrite(reader); // rewrite first
 					
 					if (GetBoost() != 1.0f)
 					{
 						// incorporate boost
-						if (query == c.query)
+						if (query == c.GetQuery())
 						// if rewrite was no-op
 							query = (Query) query.Clone(); // then clone before boost
 						query.SetBoost(GetBoost() * query.GetBoost());
@@ -313,13 +510,13 @@
 			for (int i = 0; i < clauses.Count; i++)
 			{
 				BooleanClause c = (BooleanClause) clauses[i];
-				Query query = c.query.Rewrite(reader);
-				if (query != c.query)
+				Query query = c.GetQuery().Rewrite(reader);
+				if (query != c.GetQuery())
 				{
 					// clause rewrote: must clone
 					if (clone == null)
 						clone = (BooleanQuery) this.Clone();
-					clone.clauses[i] = new BooleanClause(query, c.required, c.prohibited);
+					clone.clauses[i] = new BooleanClause(query, c.GetOccur());
 				}
 			}
 			if (clone != null)
@@ -330,6 +527,15 @@
 				return this; // no clauses rewrote
 		}
 		
+		// inherit javadoc
+		public override void  ExtractTerms(System.Collections.Hashtable terms)
+		{
+			for (System.Collections.IEnumerator i = clauses.GetEnumerator(); i.MoveNext(); )
+			{
+				BooleanClause clause = (BooleanClause) i.Current;
+				clause.GetQuery().ExtractTerms(terms);
+			}
+		}
 		
 		public override System.Object Clone()
 		{
@@ -342,7 +548,8 @@
 		public override System.String ToString(System.String field)
 		{
 			System.Text.StringBuilder buffer = new System.Text.StringBuilder();
-			if (GetBoost() != 1.0)
+			bool needParens = (GetBoost() != 1.0) || (GetMinimumNumberShouldMatch() > 0);
+			if (needParens)
 			{
 				buffer.Append("(");
 			}
@@ -350,36 +557,40 @@
 			for (int i = 0; i < clauses.Count; i++)
 			{
 				BooleanClause c = (BooleanClause) clauses[i];
-				if (c.prohibited)
+				if (c.IsProhibited())
 					buffer.Append("-");
-				else if (c.required)
+				else if (c.IsRequired())
 					buffer.Append("+");
 				
-				Query subQuery = c.query;
+				Query subQuery = c.GetQuery();
 				if (subQuery is BooleanQuery)
 				{
 					// wrap sub-bools in parens
 					buffer.Append("(");
-					buffer.Append(c.query.ToString(field));
+					buffer.Append(c.GetQuery().ToString(field));
 					buffer.Append(")");
 				}
 				else
-					buffer.Append(c.query.ToString(field));
+					buffer.Append(c.GetQuery().ToString(field));
 				
 				if (i != clauses.Count - 1)
 					buffer.Append(" ");
 			}
 			
-			if (GetBoost() != 1.0)
+			if (needParens)
 			{
-                System.Globalization.NumberFormatInfo nfi = new System.Globalization.CultureInfo("en-US", false).NumberFormat;
-                nfi.NumberDecimalDigits = 1;
-
-                buffer.Append(")^");
-                buffer.Append(GetBoost().ToString("N", nfi));
-
-                //buffer.Append(")^");
-				//buffer.Append(GetBoost());
+				buffer.Append(")");
+			}
+			
+			if (GetMinimumNumberShouldMatch() > 0)
+			{
+				buffer.Append('~');
+				buffer.Append(GetMinimumNumberShouldMatch());
+			}
+			
+			if (GetBoost() != 1.0f)
+			{
+				buffer.Append(ToStringUtils.Boost(GetBoost()));
 			}
 			
 			return buffer.ToString();
@@ -391,14 +602,22 @@
 			if (!(o is BooleanQuery))
 				return false;
 			BooleanQuery other = (BooleanQuery) o;
-			return (this.GetBoost() == other.GetBoost()) && this.clauses.Equals(other.clauses);
+            if (this.GetBoost() != other.GetBoost())
+                return false;
+            if (this.clauses.Count != other.clauses.Count)
+                return false;
+            for (int i = 0; i < this.clauses.Count; i++)
+            {
+                if (this.clauses[i].Equals(other.clauses[i]) == false)
+                    return false;
+            }
+			return this.GetMinimumNumberShouldMatch() == other.GetMinimumNumberShouldMatch();
 		}
 		
 		/// <summary>Returns a hash code value for this object.</summary>
 		public override int GetHashCode()
 		{
-            int boostInt = BitConverter.ToInt32(BitConverter.GetBytes(GetBoost()), 0);
-            return boostInt ^ clauses.GetHashCode();
+			return BitConverter.ToInt32(BitConverter.GetBytes(GetBoost()), 0) ^ clauses.GetHashCode() + GetMinimumNumberShouldMatch();
 		}
 	}
 }

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/BooleanScorer.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Search/BooleanScorer.cs?rev=411501&r1=411500&r2=411501&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/BooleanScorer.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/BooleanScorer.cs Sat Jun  3 19:41:13 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright 2004 The Apache Software Foundation
+ * Copyright 2005 The Apache Software Foundation
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,7 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 using System;
+
 namespace Lucene.Net.Search
 {
 	
@@ -93,6 +95,73 @@
 		private int end;
 		private Bucket current;
 		
+		public override void  Score(HitCollector hc)
+		{
+			Next();
+			Score(hc, System.Int32.MaxValue);
+		}
+		
+		protected internal override bool Score(HitCollector hc, int max)
+		{
+			if (coordFactors == null)
+				ComputeCoordFactors();
+			
+			bool more;
+			Bucket tmp;
+			
+			do 
+			{
+				bucketTable.first = null;
+				
+				while (current != null)
+				{
+					// more queued 
+					
+					// check prohibited & required
+					if ((current.bits & prohibitedMask) == 0 && (current.bits & requiredMask) == requiredMask)
+					{
+						
+						if (current.doc >= max)
+						{
+							tmp = current;
+							current = current.next;
+							tmp.next = bucketTable.first;
+							bucketTable.first = tmp;
+							continue;
+						}
+						
+						hc.Collect(current.doc, current.score * coordFactors[current.coord]);
+					}
+					
+					current = current.next; // pop the queue
+				}
+				
+				if (bucketTable.first != null)
+				{
+					current = bucketTable.first;
+					bucketTable.first = current.next;
+					return true;
+				}
+				
+				// refill the queue
+				more = false;
+				end += BucketTable.SIZE;
+				for (SubScorer sub = scorers; sub != null; sub = sub.next)
+				{
+					if (!sub.done)
+					{
+						sub.done = !sub.scorer.Score(sub.collector, end);
+						if (!sub.done)
+							more = true;
+					}
+				}
+				current = bucketTable.first;
+			}
+			while (current != null || more);
+			
+			return false;
+		}
+		
 		public override int Doc()
 		{
 			return current.doc;
@@ -114,7 +183,7 @@
 					{
 						return true;
 					}
-                }
+				}
 				
 				// refill the queue
 				more = false;
@@ -133,7 +202,7 @@
 					}
 				}
 			}
-			while (bucketTable.first != null | more);
+			while (bucketTable.first != null || more);
 			
 			return false;
 		}
@@ -161,7 +230,7 @@
 			{
 				buckets = new Bucket[SIZE];
 			}
-			public const int SIZE = 1 << 10;
+			public const int SIZE = 1 << 11;
 			public static readonly int MASK;
 			
 			internal Bucket[] buckets;

Added: incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/BooleanScorer2.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Search/BooleanScorer2.cs?rev=411501&view=auto
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/BooleanScorer2.cs (added)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/BooleanScorer2.cs Sat Jun  3 19:41:13 2006
@@ -0,0 +1,487 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+
+namespace Lucene.Net.Search
+{
+	
+	/// <summary>An alternative to BooleanScorer.
+	/// <br>Uses ConjunctionScorer, DisjunctionScorer, ReqOptScorer and ReqExclScorer.
+	/// <br>Implements skipTo(), and has no limitations on the numbers of added scorers.
+	/// </summary>
+	class BooleanScorer2 : Scorer
+	{
+		private class AnonymousClassDisjunctionSumScorer : DisjunctionSumScorer
+		{
+			private void  InitBlock(BooleanScorer2 enclosingInstance)
+			{
+				this.enclosingInstance = enclosingInstance;
+			}
+			private BooleanScorer2 enclosingInstance;
+			public BooleanScorer2 Enclosing_Instance
+			{
+				get
+				{
+					return enclosingInstance;
+				}
+				
+			}
+			internal AnonymousClassDisjunctionSumScorer(BooleanScorer2 enclosingInstance, System.Collections.IList Param1, int Param2):base(Param1, Param2)
+			{
+				InitBlock(enclosingInstance);
+			}
+			private int lastScoredDoc = - 1;
+			public override float Score()
+			{
+				if (Doc() > lastScoredDoc)
+				{
+					lastScoredDoc = Doc();
+					Enclosing_Instance.coordinator.nrMatchers += base.nrMatchers;
+				}
+				return base.Score();
+			}
+		}
+
+        private class AnonymousClassConjunctionScorer : ConjunctionScorer
+		{
+			private void  InitBlock(int requiredNrMatchers, BooleanScorer2 enclosingInstance)
+			{
+				this.requiredNrMatchers = requiredNrMatchers;
+				this.enclosingInstance = enclosingInstance;
+			}
+			private int requiredNrMatchers;
+			private BooleanScorer2 enclosingInstance;
+
+			public BooleanScorer2 Enclosing_Instance
+			{
+				get
+				{
+					return enclosingInstance;
+				}
+				
+			}
+			internal AnonymousClassConjunctionScorer(int requiredNrMatchers, BooleanScorer2 enclosingInstance, Lucene.Net.Search.Similarity Param1):base(Param1)
+			{
+				InitBlock(requiredNrMatchers, enclosingInstance);
+			}
+			private int lastScoredDoc = - 1;
+			
+			public override float Score()
+			{
+				if (Doc() > lastScoredDoc)
+				{
+					lastScoredDoc = Doc();
+					Enclosing_Instance.coordinator.nrMatchers += requiredNrMatchers;
+				}
+				// All scorers match, so defaultSimilarity super.score() always has 1 as
+				// the coordination factor.
+				// Therefore the sum of the scores of the requiredScorers
+				// is used as score.
+				return base.Score();
+			}
+		}
+		private System.Collections.ArrayList requiredScorers = new System.Collections.ArrayList();
+		private System.Collections.ArrayList optionalScorers = new System.Collections.ArrayList();
+		private System.Collections.ArrayList prohibitedScorers = new System.Collections.ArrayList();
+		
+		
+		private class Coordinator
+		{
+			public Coordinator(BooleanScorer2 enclosingInstance)
+			{
+				InitBlock(enclosingInstance);
+			}
+			private void  InitBlock(BooleanScorer2 enclosingInstance)
+			{
+				this.enclosingInstance = enclosingInstance;
+			}
+			private BooleanScorer2 enclosingInstance;
+			public BooleanScorer2 Enclosing_Instance
+			{
+				get
+				{
+					return enclosingInstance;
+				}
+				
+			}
+			internal int maxCoord = 0; // to be increased for each non prohibited scorer
+			
+			private float[] coordFactors = null;
+			
+			internal virtual void  Init()
+			{
+				// use after all scorers have been added.
+				coordFactors = new float[maxCoord + 1];
+				Similarity sim = Enclosing_Instance.GetSimilarity();
+				for (int i = 0; i <= maxCoord; i++)
+				{
+					coordFactors[i] = sim.Coord(i, maxCoord);
+				}
+			}
+			
+			internal int nrMatchers; // to be increased by score() of match counting scorers.
+			
+			internal virtual void  InitDoc()
+			{
+				nrMatchers = 0;
+			}
+			
+			internal virtual float CoordFactor()
+			{
+				return coordFactors[nrMatchers];
+			}
+		}
+		
+		private Coordinator coordinator;
+		
+		/// <summary>The scorer to which all scoring will be delegated,
+		/// except for computing and using the coordination factor.
+		/// </summary>
+		private Scorer countingSumScorer = null;
+		
+		/// <summary>The number of optionalScorers that need to match (if there are any) </summary>
+		private int minNrShouldMatch;
+		
+		/// <summary>Create a BooleanScorer2.</summary>
+		/// <param name="similarity">The similarity to be used.
+		/// </param>
+		/// <param name="minNrShouldMatch">The minimum number of optional added scorers
+		/// that should match during the search.
+		/// In case no required scorers are added,
+		/// at least one of the optional scorers will have to
+		/// match during the search.
+		/// </param>
+		public BooleanScorer2(Similarity similarity, int minNrShouldMatch):base(similarity)
+		{
+			if (minNrShouldMatch < 0)
+			{
+				throw new System.ArgumentException("Minimum number of optional scorers should not be negative");
+			}
+			coordinator = new Coordinator(this);
+			this.minNrShouldMatch = minNrShouldMatch;
+		}
+		
+		/// <summary>Create a BooleanScorer2.
+		/// In no required scorers are added,
+		/// at least one of the optional scorers will have to match during the search.
+		/// </summary>
+		/// <param name="similarity">The similarity to be used.
+		/// </param>
+		public BooleanScorer2(Similarity similarity) : this(similarity, 0)
+		{
+		}
+		
+		public virtual void  Add(Scorer scorer, bool required, bool prohibited)
+		{
+			if (!prohibited)
+			{
+				coordinator.maxCoord++;
+			}
+			
+			if (required)
+			{
+				if (prohibited)
+				{
+					throw new System.ArgumentException("scorer cannot be required and prohibited");
+				}
+				requiredScorers.Add(scorer);
+			}
+			else if (prohibited)
+			{
+				prohibitedScorers.Add(scorer);
+			}
+			else
+			{
+				optionalScorers.Add(scorer);
+			}
+		}
+		
+		/// <summary>Initialize the match counting scorer that sums all the
+		/// scores. <p>
+		/// When "counting" is used in a name it means counting the number
+		/// of matching scorers.<br>
+		/// When "sum" is used in a name it means score value summing
+		/// over the matching scorers
+		/// </summary>
+		private void  InitCountingSumScorer()
+		{
+			coordinator.Init();
+			countingSumScorer = MakeCountingSumScorer();
+		}
+		
+		/// <summary>Count a scorer as a single match. </summary>
+		private class SingleMatchScorer : Scorer
+		{
+			private void  InitBlock(BooleanScorer2 enclosingInstance)
+			{
+				this.enclosingInstance = enclosingInstance;
+			}
+			private BooleanScorer2 enclosingInstance;
+			public BooleanScorer2 Enclosing_Instance
+			{
+				get
+				{
+					return enclosingInstance;
+				}
+				
+			}
+			private Scorer scorer;
+			private int lastScoredDoc = - 1;
+			
+			internal SingleMatchScorer(BooleanScorer2 enclosingInstance, Scorer scorer) : base(scorer.GetSimilarity())
+			{
+				InitBlock(enclosingInstance);
+				this.scorer = scorer;
+			}
+			public override float Score()
+			{
+				if (Doc() > lastScoredDoc)
+				{
+					lastScoredDoc = Doc();
+					Enclosing_Instance.coordinator.nrMatchers++;
+				}
+				return scorer.Score();
+			}
+			public override int Doc()
+			{
+				return scorer.Doc();
+			}
+			public override bool Next()
+			{
+				return scorer.Next();
+			}
+			public override bool SkipTo(int docNr)
+			{
+				return scorer.SkipTo(docNr);
+			}
+			public override Explanation Explain(int docNr)
+			{
+				return scorer.Explain(docNr);
+			}
+		}
+		
+		private Scorer CountingDisjunctionSumScorer(System.Collections.IList scorers, int minMrShouldMatch)
+		// each scorer from the list counted as a single matcher
+		{
+			return new AnonymousClassDisjunctionSumScorer(this, scorers, minMrShouldMatch);
+		}
+		
+		private static Similarity defaultSimilarity = new DefaultSimilarity();
+		
+		private Scorer CountingConjunctionSumScorer(System.Collections.IList requiredScorers)
+		{
+			// each scorer from the list counted as a single matcher
+			int requiredNrMatchers = requiredScorers.Count;
+			ConjunctionScorer cs = new AnonymousClassConjunctionScorer(requiredNrMatchers, this, defaultSimilarity);
+			System.Collections.IEnumerator rsi = requiredScorers.GetEnumerator();
+			while (rsi.MoveNext())
+			{
+				cs.Add((Scorer) rsi.Current);
+			}
+			return cs;
+		}
+		
+		private Scorer DualConjunctionSumScorer(Scorer req1, Scorer req2)
+		{
+			// non counting. 
+			//UPGRADE_NOTE: Final was removed from the declaration of 'requiredNrMatchers '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
+			int requiredNrMatchers = requiredScorers.Count;
+			ConjunctionScorer cs = new ConjunctionScorer(defaultSimilarity);
+			// All scorers match, so defaultSimilarity super.score() always has 1 as
+			// the coordination factor.
+			// Therefore the sum of the scores of two scorers
+			// is used as score.
+			cs.Add(req1);
+			cs.Add(req2);
+			return cs;
+		}
+		
+		/// <summary>Returns the scorer to be used for match counting and score summing.
+		/// Uses requiredScorers, optionalScorers and prohibitedScorers.
+		/// </summary>
+		private Scorer MakeCountingSumScorer()
+		{
+			// each scorer counted as a single matcher
+			return (requiredScorers.Count == 0)?MakeCountingSumScorerNoReq():MakeCountingSumScorerSomeReq();
+		}
+		
+		private Scorer MakeCountingSumScorerNoReq()
+		{
+			// No required scorers
+			if (optionalScorers.Count == 0)
+			{
+				return new NonMatchingScorer(); // no clauses or only prohibited clauses
+			}
+			else
+			{
+				// No required scorers. At least one optional scorer.
+				// minNrShouldMatch optional scorers are required, but at least 1
+				int nrOptRequired = (minNrShouldMatch < 1)?1:minNrShouldMatch;
+				if (optionalScorers.Count < nrOptRequired)
+				{
+					return new NonMatchingScorer(); // fewer optional clauses than minimum (at least 1) that should match
+				}
+				else
+				{
+					// optionalScorers.size() >= nrOptRequired, no required scorers
+					Scorer requiredCountingSumScorer = (optionalScorers.Count > nrOptRequired)?CountingDisjunctionSumScorer(optionalScorers, nrOptRequired):((optionalScorers.Count == 1)?new SingleMatchScorer(this, (Scorer) optionalScorers[0]):CountingConjunctionSumScorer(optionalScorers));
+					return AddProhibitedScorers(requiredCountingSumScorer);
+				}
+			}
+		}
+		
+		private Scorer MakeCountingSumScorerSomeReq()
+		{
+			// At least one required scorer.
+			if (optionalScorers.Count < minNrShouldMatch)
+			{
+				return new NonMatchingScorer(); // fewer optional clauses than minimum that should match
+			}
+			else if (optionalScorers.Count == minNrShouldMatch)
+			{
+				// all optional scorers also required.
+				System.Collections.ArrayList allReq = new System.Collections.ArrayList(requiredScorers);
+				allReq.AddRange(optionalScorers);
+				return AddProhibitedScorers(CountingConjunctionSumScorer(allReq));
+			}
+			else
+			{
+				// optionalScorers.size() > minNrShouldMatch, and at least one required scorer
+				Scorer requiredCountingSumScorer = (requiredScorers.Count == 1)?new SingleMatchScorer(this, (Scorer) requiredScorers[0]):CountingConjunctionSumScorer(requiredScorers);
+				if (minNrShouldMatch > 0)
+				{
+					// use a required disjunction scorer over the optional scorers
+					return AddProhibitedScorers(DualConjunctionSumScorer(requiredCountingSumScorer, CountingDisjunctionSumScorer(optionalScorers, minNrShouldMatch)));
+				}
+				else
+				{
+					// minNrShouldMatch == 0
+					return new ReqOptSumScorer(AddProhibitedScorers(requiredCountingSumScorer), ((optionalScorers.Count == 1)?new SingleMatchScorer(this, (Scorer) optionalScorers[0]):CountingDisjunctionSumScorer(optionalScorers, 1))); // require 1 in combined, optional scorer.
+				}
+			}
+		}
+		
+		/// <summary>Returns the scorer to be used for match counting and score summing.
+		/// Uses the given required scorer and the prohibitedScorers.
+		/// </summary>
+		/// <param name="requiredCountingSumScorer">A required scorer already built.
+		/// </param>
+		private Scorer AddProhibitedScorers(Scorer requiredCountingSumScorer)
+		{
+			return (prohibitedScorers.Count == 0)?requiredCountingSumScorer:new ReqExclScorer(requiredCountingSumScorer, ((prohibitedScorers.Count == 1)?(Scorer) prohibitedScorers[0]:new DisjunctionSumScorer(prohibitedScorers)));
+		}
+		
+		/// <summary>Scores and collects all matching documents.</summary>
+		/// <param name="hc">The collector to which all matching documents are passed through
+		/// {@link HitCollector#Collect(int, float)}.
+		/// <br>When this method is used the {@link #Explain(int)} method should not be used.
+		/// </param>
+		public override void  Score(HitCollector hc)
+		{
+			if (countingSumScorer == null)
+			{
+				InitCountingSumScorer();
+			}
+			while (countingSumScorer.Next())
+			{
+				hc.Collect(countingSumScorer.Doc(), Score());
+			}
+		}
+		
+		/// <summary>Expert: Collects matching documents in a range.
+		/// <br>Note that {@link #Next()} must be called once before this method is
+		/// called for the first time.
+		/// </summary>
+		/// <param name="hc">The collector to which all matching documents are passed through
+		/// {@link HitCollector#Collect(int, float)}.
+		/// </param>
+		/// <param name="max">Do not score documents past this.
+		/// </param>
+		/// <returns> true if more matching documents may remain.
+		/// </returns>
+		protected internal override bool Score(HitCollector hc, int max)
+		{
+			// null pointer exception when Next() was not called before:
+			int docNr = countingSumScorer.Doc();
+			while (docNr < max)
+			{
+				hc.Collect(docNr, Score());
+				if (!countingSumScorer.Next())
+				{
+					return false;
+				}
+				docNr = countingSumScorer.Doc();
+			}
+			return true;
+		}
+		
+		public override int Doc()
+		{
+			return countingSumScorer.Doc();
+		}
+		
+		public override bool Next()
+		{
+			if (countingSumScorer == null)
+			{
+				InitCountingSumScorer();
+			}
+			return countingSumScorer.Next();
+		}
+		
+		public override float Score()
+		{
+			coordinator.InitDoc();
+			float sum = countingSumScorer.Score();
+			return sum * coordinator.CoordFactor();
+		}
+		
+		/// <summary>Skips to the first match beyond the current whose document number is
+		/// greater than or equal to a given target.
+		/// 
+		/// <p>When this method is used the {@link #Explain(int)} method should not be used.
+		/// 
+		/// </summary>
+		/// <param name="target">The target document number.
+		/// </param>
+		/// <returns> true iff there is such a match.
+		/// </returns>
+		public override bool SkipTo(int target)
+		{
+			if (countingSumScorer == null)
+			{
+				InitCountingSumScorer();
+			}
+			return countingSumScorer.SkipTo(target);
+		}
+		
+		/// <summary>Throws an UnsupportedOperationException.
+		/// TODO: Implement an explanation of the coordination factor.
+		/// </summary>
+		/// <param name="doc">The document number for the explanation.
+		/// </param>
+		/// <throws>  UnsupportedOperationException </throws>
+		public override Explanation Explain(int doc)
+		{
+			throw new System.NotSupportedException();
+			/* How to explain the coordination factor?
+			initCountingSumScorer();
+			return countingSumScorer.explain(doc); // misses coord factor. 
+			*/
+		}
+	}
+}
\ No newline at end of file

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/CachingWrapperFilter.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Search/CachingWrapperFilter.cs?rev=411501&r1=411500&r2=411501&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/CachingWrapperFilter.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/CachingWrapperFilter.cs Sat Jun  3 19:41:13 2006
@@ -13,13 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 using System;
 using System.Runtime.InteropServices;
 using IndexReader = Lucene.Net.Index.IndexReader;
+
 namespace Lucene.Net.Search
 {
 	
-	/// <summary> Wraps another filters result and caches it.  The caching
+	/// <summary> Wraps another filter's result and caches it.  The caching
 	/// behavior is like {@link QueryFilter}.  The purpose is to allow
 	/// filters to simply filter, and then wrap with this class to add
 	/// caching, keeping the two concerns decoupled yet composable.
@@ -73,6 +75,18 @@
 		public override System.String ToString()
 		{
 			return "CachingWrapperFilter(" + filter + ")";
+		}
+		
+		public  override bool Equals(System.Object o)
+		{
+			if (!(o is CachingWrapperFilter))
+				return false;
+			return this.filter.Equals(((CachingWrapperFilter) o).filter);
+		}
+		
+		public override int GetHashCode()
+		{
+			return filter.GetHashCode() ^ 0x1117BF25;
 		}
 	}
 }

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/ConjunctionScorer.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Search/ConjunctionScorer.cs?rev=411501&r1=411500&r2=411501&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/ConjunctionScorer.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/ConjunctionScorer.cs Sat Jun  3 19:41:13 2006
@@ -13,12 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 using System;
+
 namespace Lucene.Net.Search
 {
 	
 	/// <summary>Scorer for conjunctions, sets of queries, all of which are required. </summary>
-	sealed class ConjunctionScorer:Scorer
+	class ConjunctionScorer : Scorer
 	{
 		private class AnonymousClassComparator : System.Collections.IComparer
 		{
@@ -40,14 +42,10 @@
 				
 			}
 			// sort the array
-			public int Compare(System.Object o1, System.Object o2)
+			public virtual int Compare(System.Object o1, System.Object o2)
 			{
 				return ((Scorer) o1).Doc() - ((Scorer) o2).Doc();
 			}
-			public bool equals(System.Object o1, System.Object o2)
-			{
-				return ((Scorer) o1).Doc() == ((Scorer) o2).Doc();
-			}
 		}
 		private System.Collections.ArrayList scorers = new System.Collections.ArrayList();
 		private bool firstTime = true;
@@ -81,7 +79,7 @@
 		{
 			if (firstTime)
 			{
-				Init();
+				Init(true);
 			}
 			else if (more)
 			{
@@ -106,13 +104,20 @@
 		
 		public override bool SkipTo(int target)
 		{
+			if (firstTime)
+			{
+				Init(false);
+			}
+			
 			System.Collections.IEnumerator i = scorers.GetEnumerator();
 			while (more && i.MoveNext())
 			{
 				more = ((Scorer) i.Current).SkipTo(target);
 			}
+			
 			if (more)
 				SortScorers(); // re-sort scorers
+			
 			return DoNext();
 		}
 		
@@ -128,21 +133,24 @@
 			return score;
 		}
 		
-		private void  Init()
+		private void  Init(bool initScorers)
 		{
-			more = scorers.Count > 0;
-			
-			// compute coord factor
+			//  compute coord factor
 			coord = GetSimilarity().Coord(scorers.Count, scorers.Count);
 			
-			// move each scorer to its first entry
-			System.Collections.IEnumerator i = scorers.GetEnumerator();
-			while (more && i.MoveNext())
+			more = scorers.Count > 0;
+			
+			if (initScorers)
 			{
-				more = ((Scorer) i.Current).Next();
+				// move each scorer to its first entry
+				System.Collections.IEnumerator i = scorers.GetEnumerator();
+				while (more && i.MoveNext())
+				{
+					more = ((Scorer) i.Current).Next();
+				}
+				if (more)
+					SortScorers(); // initial sort of list
 			}
-			if (more)
-				SortScorers(); // initial sort of list
 			
 			firstTime = false;
 		}
@@ -150,7 +158,7 @@
 		private void  SortScorers()
 		{
 			// move scorers to an array
-            Scorer[] array = (Scorer[]) scorers.ToArray(typeof(Scorer));
+			Scorer[] array = (Scorer[]) scorers.ToArray(typeof(Scorer));
 			scorers.Clear(); // empty the list
 			
 			// note that this comparator is not consistent with equals!

Added: incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/ConstantScoreQuery.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Search/ConstantScoreQuery.cs?rev=411501&view=auto
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/ConstantScoreQuery.cs (added)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/ConstantScoreQuery.cs Sat Jun  3 19:41:13 2006
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2004 The Apache Software Foundation
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using IndexReader = Lucene.Net.Index.IndexReader;
+
+namespace Lucene.Net.Search
+{
+	
+	/// <summary> A query that wraps a filter and simply returns a constant score equal to the
+	/// query boost for every document in the filter.
+	/// 
+	/// </summary>
+	/// <author>  yonik
+	/// </author>
+	/// <version>  $Id$
+	/// </version>
+	[Serializable]
+	public class ConstantScoreQuery : Query
+	{
+		protected internal Filter filter;
+		
+		public ConstantScoreQuery(Filter filter)
+		{
+			this.filter = filter;
+		}
+		
+		public override Query Rewrite(IndexReader reader)
+		{
+			return this;
+		}
+		
+		[Serializable]
+		protected internal class ConstantWeight : Weight
+		{
+			private void  InitBlock(ConstantScoreQuery enclosingInstance)
+			{
+				this.enclosingInstance = enclosingInstance;
+			}
+			private ConstantScoreQuery enclosingInstance;
+			public ConstantScoreQuery Enclosing_Instance
+			{
+				get
+				{
+					return enclosingInstance;
+				}
+				
+			}
+			private Searcher searcher;
+			private float queryNorm;
+			private float queryWeight;
+			
+			public ConstantWeight(ConstantScoreQuery enclosingInstance, Searcher searcher)
+			{
+				InitBlock(enclosingInstance);
+				this.searcher = searcher;
+			}
+			
+			public virtual Query GetQuery()
+			{
+				return Enclosing_Instance;
+			}
+			
+			public virtual float GetValue()
+			{
+				return queryWeight;
+			}
+			
+			public virtual float SumOfSquaredWeights()
+			{
+				queryWeight = Enclosing_Instance.GetBoost();
+				return queryWeight * queryWeight;
+			}
+			
+			public virtual void  Normalize(float norm)
+			{
+				this.queryNorm = norm;
+				queryWeight *= this.queryNorm;
+			}
+			
+			public virtual Scorer Scorer(IndexReader reader)
+			{
+				return new ConstantScorer(enclosingInstance, Enclosing_Instance.GetSimilarity(searcher), reader, this);
+			}
+			
+			public virtual Explanation Explain(IndexReader reader, int doc)
+			{
+				
+				ConstantScorer cs = (ConstantScorer) Scorer(reader);
+				bool exists = cs.bits.Get(doc);
+				
+				Explanation result = new Explanation();
+				
+				if (exists)
+				{
+					result.SetDescription("ConstantScoreQuery(" + Enclosing_Instance.filter + "), product of:");
+					result.SetValue(queryWeight);
+					result.AddDetail(new Explanation(Enclosing_Instance.GetBoost(), "boost"));
+					result.AddDetail(new Explanation(queryNorm, "queryNorm"));
+				}
+				else
+				{
+					result.SetDescription("ConstantScoreQuery(" + Enclosing_Instance.filter + ") doesn't match id " + doc);
+					result.SetValue(0);
+				}
+				return result;
+			}
+		}
+		
+		protected internal class ConstantScorer : Scorer
+		{
+			private void  InitBlock(ConstantScoreQuery enclosingInstance)
+			{
+				this.enclosingInstance = enclosingInstance;
+			}
+			private ConstantScoreQuery enclosingInstance;
+			public ConstantScoreQuery Enclosing_Instance
+			{
+				get
+				{
+					return enclosingInstance;
+				}
+				
+			}
+			internal System.Collections.BitArray bits;
+			internal float theScore;
+			internal int doc = - 1;
+			
+			public ConstantScorer(ConstantScoreQuery enclosingInstance, Similarity similarity, IndexReader reader, Weight w) : base(similarity)
+			{
+				InitBlock(enclosingInstance);
+				theScore = w.GetValue();
+				bits = Enclosing_Instance.filter.Bits(reader);
+			}
+			
+			public override bool Next()
+			{
+				doc = SupportClass.Number.NextSetBit(bits, doc + 1);
+				return doc >= 0;
+			}
+			
+			public override int Doc()
+			{
+				return doc;
+			}
+			
+			public override float Score()
+			{
+				return theScore;
+			}
+			
+			public override bool SkipTo(int target)
+			{
+				doc = SupportClass.Number.NextSetBit(bits, target); // requires JDK 1.4
+				return doc >= 0;
+			}
+			
+			public override Explanation Explain(int doc)
+			{
+				throw new System.NotSupportedException();
+			}
+		}
+		
+		
+		protected internal override Weight CreateWeight(Searcher searcher)
+		{
+			return new ConstantScoreQuery.ConstantWeight(this, searcher);
+		}
+		
+		
+		/// <summary>Prints a user-readable version of this query. </summary>
+		public override System.String ToString(System.String field)
+		{
+			return "ConstantScore(" + filter.ToString() + (GetBoost() == 1.0 ? ")" : "^" + GetBoost());
+		}
+		
+		/// <summary>Returns true if <code>o</code> is equal to this. </summary>
+		public  override bool Equals(System.Object o)
+		{
+			if (this == o)
+				return true;
+			if (!(o is ConstantScoreQuery))
+				return false;
+			ConstantScoreQuery other = (ConstantScoreQuery) o;
+			return this.GetBoost() == other.GetBoost() && filter.Equals(other.filter);
+		}
+		
+		/// <summary>Returns a hash code value for this object. </summary>
+		public override int GetHashCode()
+		{
+			// Simple add is OK since no existing filter hashcode has a float component.
+			return filter.GetHashCode() + BitConverter.ToInt32(BitConverter.GetBytes(GetBoost()), 0);
+		}
+
+        override public System.Object Clone()
+		{
+            // {{Aroush-1.9}} is this all that we need to clone?!
+            ConstantScoreQuery clone = (ConstantScoreQuery) base.Clone();
+            clone.filter = (Filter) this.filter;
+            return clone;
+        }
+	}
+}
\ No newline at end of file

Added: incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/ConstantScoreRangeQuery.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Search/ConstantScoreRangeQuery.cs?rev=411501&view=auto
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/ConstantScoreRangeQuery.cs (added)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/ConstantScoreRangeQuery.cs Sat Jun  3 19:41:13 2006
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2004 The Apache Software Foundation
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using IndexReader = Lucene.Net.Index.IndexReader;
+
+namespace Lucene.Net.Search
+{
+	
+	/// <summary> A range query that returns a constant score equal to it's boost for
+	/// all documents in the range.
+	/// <p>
+	/// It does not have an upper bound on the number of clauses covered in the range.
+	/// <p>
+	/// If an endpoint is null, it is said to be "open".
+	/// Either or both endpoints may be open.  Open endpoints may not be exclusive
+	/// (you can't select all but the first or last term without explicitly specifying the term to exclude.)
+	/// 
+	/// </summary>
+	/// <author>  yonik
+	/// </author>
+	/// <version>  $Id$
+	/// </version>
+	
+	[Serializable]
+	public class ConstantScoreRangeQuery : Query
+	{
+		private System.String fieldName;
+		private System.String lowerVal;
+		private System.String upperVal;
+		private bool includeLower;
+		private bool includeUpper;
+		
+		
+		public ConstantScoreRangeQuery(System.String fieldName, System.String lowerVal, System.String upperVal, bool includeLower, bool includeUpper)
+		{
+			// do a little bit of normalization...
+			// open ended range queries should always be inclusive.
+			if (lowerVal == null)
+			{
+				includeLower = true;
+			}
+			else if (includeLower && lowerVal.Equals(""))
+			{
+				lowerVal = null;
+			}
+			if (upperVal == null)
+			{
+				includeUpper = true;
+			}
+			
+			
+			this.fieldName = String.Intern(fieldName); // intern it, just like terms...
+			this.lowerVal = lowerVal;
+			this.upperVal = upperVal;
+			this.includeLower = includeLower;
+			this.includeUpper = includeUpper;
+		}
+		
+		/// <summary>Returns the field name for this query </summary>
+		public virtual System.String GetField()
+		{
+			return fieldName;
+		}
+		/// <summary>Returns the value of the lower endpoint of this range query, null if open ended </summary>
+		public virtual System.String GetLowerVal()
+		{
+			return lowerVal;
+		}
+		/// <summary>Returns the value of the upper endpoint of this range query, null if open ended </summary>
+		public virtual System.String GetUpperVal()
+		{
+			return upperVal;
+		}
+		/// <summary>Returns <code>true</code> if the lower endpoint is inclusive </summary>
+		public virtual bool IncludesLower()
+		{
+			return includeLower;
+		}
+		/// <summary>Returns <code>true</code> if the upper endpoint is inclusive </summary>
+		public virtual bool IncludesUpper()
+		{
+			return includeUpper;
+		}
+		
+		public override Query Rewrite(IndexReader reader)
+		{
+			// Map to RangeFilter semantics which are slightly different...
+			RangeFilter rangeFilt = new RangeFilter(fieldName, lowerVal != null ? lowerVal : "", upperVal, (System.Object) lowerVal == (System.Object) ""?false:includeLower, upperVal == null?false:includeUpper);
+			Query q = new ConstantScoreQuery(rangeFilt);
+			q.SetBoost(GetBoost());
+			return q;
+		}
+		
+		/// <summary>Prints a user-readable version of this query. </summary>
+		public override System.String ToString(System.String field)
+		{
+			System.Text.StringBuilder buffer = new System.Text.StringBuilder();
+			if (!GetField().Equals(field))
+			{
+				buffer.Append(GetField());
+				buffer.Append(":");
+			}
+			buffer.Append(includeLower ? '[' : '{');
+			buffer.Append(lowerVal != null ? lowerVal : "*");
+			buffer.Append(" TO ");
+			buffer.Append(upperVal != null ? upperVal : "*");
+			buffer.Append(includeUpper ? ']' : '}');
+			if (GetBoost() != 1.0f)
+			{
+				buffer.Append("^");
+				buffer.Append(GetBoost().ToString());
+			}
+			return buffer.ToString();
+		}
+		
+		/// <summary>Returns true if <code>o</code> is equal to this. </summary>
+		public  override bool Equals(System.Object o)
+		{
+			if (this == o)
+				return true;
+			if (!(o is ConstantScoreRangeQuery))
+				return false;
+			ConstantScoreRangeQuery other = (ConstantScoreRangeQuery) o;
+			
+			if ((System.Object) this.fieldName != (System.Object) other.fieldName || this.includeLower != other.includeLower || this.includeUpper != other.includeUpper)
+			{
+				return false;
+			}
+			if (this.lowerVal != null ? !this.lowerVal.Equals(other.lowerVal) : other.lowerVal != null)
+				return false;
+			if (this.upperVal != null ? !this.upperVal.Equals(other.upperVal) : other.upperVal != null)
+				return false;
+			return this.GetBoost() == other.GetBoost();
+		}
+		
+		/// <summary>Returns a hash code value for this object.</summary>
+		public override int GetHashCode()
+		{
+			int h = BitConverter.ToInt32(BitConverter.GetBytes(GetBoost()), 0) ^ fieldName.GetHashCode();
+			// hashCode of "" is 0, so don't use that for null...
+			h ^= (lowerVal != null ? lowerVal.GetHashCode() : unchecked((int) 0x965a965a));     // {{Aroush-1.9}} Is this OK?!
+			// don't just XOR upperVal with out mixing either it or h, as it will cancel
+			// out lowerVal if they are equal.
+			h ^= ((h << 17) | (SupportClass.Number.URShift(h, 16))); // a reversible (one to one) 32 bit mapping mix
+			h ^= (upperVal != null ? (upperVal.GetHashCode()) : 0x5a695a69);
+			h ^= (includeLower ? 0x665599aa : 0) ^ (includeUpper ? unchecked((int) 0x99aa5566) : 0);    // {{Aroush-1.9}} Is this OK?!
+			return h;
+		}
+
+        override public System.Object Clone()
+		{
+            // {{Aroush-1.9}} is this all that we need to clone?!
+			ConstantScoreRangeQuery clone = (ConstantScoreRangeQuery) base.Clone();
+			clone.fieldName = (System.String) this.fieldName.Clone();
+			clone.lowerVal = (System.String) this.lowerVal.Clone();
+			clone.upperVal = (System.String) this.upperVal.Clone();
+			clone.includeLower = this.includeLower;
+			clone.includeUpper = this.includeUpper;
+			return clone;
+        }
+	}
+}
\ No newline at end of file

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/DateFilter.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Search/DateFilter.cs?rev=411501&r1=411500&r2=411501&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/DateFilter.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/DateFilter.cs Sat Jun  3 19:41:13 2006
@@ -13,22 +13,28 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 using System;
 using DateField = Lucene.Net.Documents.DateField;
 using IndexReader = Lucene.Net.Index.IndexReader;
 using Term = Lucene.Net.Index.Term;
 using TermDocs = Lucene.Net.Index.TermDocs;
 using TermEnum = Lucene.Net.Index.TermEnum;
+
 namespace Lucene.Net.Search
 {
 	
 	/// <summary> A Filter that restricts search results to a range of time.
 	/// 
 	/// <p>For this to work, documents must have been indexed with a
-	/// {@link DateField}.
+	/// {@link DateField}.</p>
+	/// 
 	/// </summary>
+	/// <deprecated> Instead, use {@link RangeFilter} combined with 
+	/// {@link Lucene.Net.document.DateTools}.
+	/// </deprecated>
 	[Serializable]
-	public class DateFilter:Filter
+	public class DateFilter : Filter
 	{
 		private void  InitBlock()
 		{
@@ -46,7 +52,7 @@
 			field = f;
 		}
 		
-		/// <summary> Constructs a filter for Field <code>f</code> matching dates
+		/// <summary> Constructs a filter for field <code>f</code> matching dates
 		/// between <code>from</code> and <code>to</code> inclusively.
 		/// </summary>
 		public DateFilter(System.String f, System.DateTime from, System.DateTime to)
@@ -57,7 +63,7 @@
 			end = DateField.DateToString(to);
 		}
 		
-		/// <summary> Constructs a filter for Field <code>f</code> matching times
+		/// <summary> Constructs a filter for field <code>f</code> matching times
 		/// between <code>from</code> and <code>to</code> inclusively.
 		/// </summary>
 		public DateFilter(System.String f, long from, long to)
@@ -68,7 +74,7 @@
 			end = DateField.TimeToString(to);
 		}
 		
-		/// <summary> Constructs a filter for Field <code>f</code> matching
+		/// <summary> Constructs a filter for field <code>f</code> matching
 		/// dates on or before before <code>date</code>.
 		/// </summary>
 		public static DateFilter Before(System.String field, System.DateTime date)
@@ -78,7 +84,7 @@
 			return result;
 		}
 		
-		/// <summary> Constructs a filter for Field <code>f</code> matching times
+		/// <summary> Constructs a filter for field <code>f</code> matching times
 		/// on or before <code>time</code>.
 		/// </summary>
 		public static DateFilter Before(System.String field, long time)
@@ -88,7 +94,7 @@
 			return result;
 		}
 		
-		/// <summary> Constructs a filter for Field <code>f</code> matching
+		/// <summary> Constructs a filter for field <code>f</code> matching
 		/// dates on or after <code>date</code>.
 		/// </summary>
 		public static DateFilter After(System.String field, System.DateTime date)
@@ -98,7 +104,7 @@
 			return result;
 		}
 		
-		/// <summary> Constructs a filter for Field <code>f</code> matching
+		/// <summary> Constructs a filter for field <code>f</code> matching
 		/// times on or after <code>time</code>.
 		/// </summary>
 		public static DateFilter After(System.String field, long time)

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/DefaultSimilarity.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Search/DefaultSimilarity.cs?rev=411501&r1=411500&r2=411501&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/DefaultSimilarity.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/DefaultSimilarity.cs Sat Jun  3 19:41:13 2006
@@ -13,11 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 using System;
+
 namespace Lucene.Net.Search
 {
+	
 	/// <summary>Expert: Default scoring implementation. </summary>
-	public class DefaultSimilarity:Similarity
+	[Serializable]
+	public class DefaultSimilarity : Similarity
 	{
 		/// <summary>Implemented as <code>1/sqrt(numTerms)</code>. </summary>
 		public override float LengthNorm(System.String fieldName, int numTerms)
@@ -44,7 +48,7 @@
 		}
 		
 		/// <summary>Implemented as <code>log(numDocs/(docFreq+1)) + 1</code>. </summary>
-		public override float Idf(int docFreq, int numDocs)
+		public override float Ldf(int docFreq, int numDocs)
 		{
 			return (float) (System.Math.Log(numDocs / (double) (docFreq + 1)) + 1.0);
 		}

Added: incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/DisjunctionMaxQuery.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Search/DisjunctionMaxQuery.cs?rev=411501&view=auto
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/DisjunctionMaxQuery.cs (added)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/DisjunctionMaxQuery.cs Sat Jun  3 19:41:13 2006
@@ -0,0 +1,307 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using IndexReader = Lucene.Net.Index.IndexReader;
+
+namespace Lucene.Net.Search
+{
+	
+	/// <summary> A query that generates the union of the documents produced by its subqueries, and that scores each document as the maximum
+	/// score for that document produced by any subquery plus a tie breaking increment for any additional matching subqueries.
+	/// This is useful to search for a word in multiple fields with different boost factors (so that the fields cannot be
+	/// combined equivalently into a single search field).  We want the primary score to be the one associated with the highest boost,
+	/// not the sum of the field scores (as BooleanQuery would give).
+	/// If the query is "albino elephant" this ensures that "albino" matching one field and "elephant" matching
+	/// another gets a higher score than "albino" matching both fields.
+	/// To get this result, use both BooleanQuery and DisjunctionMaxQuery:  for each term a DisjunctionMaxQuery searches for it in
+	/// each field, while the set of these DisjunctionMaxQuery's is combined into a BooleanQuery.
+	/// The tie breaker capability allows results that include the same term in multiple fields to be judged better than results that
+	/// include this term in only the best of those multiple fields, without confusing this with the better case of two different terms
+	/// in the multiple fields.
+	/// </summary>
+	/// <author>  Chuck Williams
+	/// </author>
+	[Serializable]
+	public class DisjunctionMaxQuery : Query, System.ICloneable
+	{
+		
+		/* The subqueries */
+		private System.Collections.ArrayList disjuncts = new System.Collections.ArrayList();
+		
+		/* Multiple of the non-max disjunct scores added into our final score.  Non-zero values support tie-breaking. */
+		private float tieBreakerMultiplier = 0.0f;
+		
+		/// <summary>Creates a new empty DisjunctionMaxQuery.  Use add() to add the subqueries.</summary>
+		/// <param name="tieBreakerMultiplier">this score of each non-maximum disjunct for a document is multiplied by this weight
+		/// and added into the final score.  If non-zero, the value should be small, on the order of 0.1, which says that
+		/// 10 occurrences of word in a lower-scored field that is also in a higher scored field is just as good as a unique
+		/// word in the lower scored field (i.e., one that is not in any higher scored field.
+		/// </param>
+		public DisjunctionMaxQuery(float tieBreakerMultiplier)
+		{
+			this.tieBreakerMultiplier = tieBreakerMultiplier;
+		}
+		
+		/// <summary> Creates a new DisjunctionMaxQuery</summary>
+		/// <param name="disjuncts">a Collection<Query> of all the disjuncts to add
+		/// </param>
+		/// <param name="tieBreakerMultiplier">  the weight to give to each matching non-maximum disjunct
+		/// </param>
+		public DisjunctionMaxQuery(System.Collections.ICollection disjuncts, float tieBreakerMultiplier)
+		{
+			this.tieBreakerMultiplier = tieBreakerMultiplier;
+			Add(disjuncts);
+		}
+		
+		/// <summary>Add a subquery to this disjunction</summary>
+		/// <param name="query">the disjunct added
+		/// </param>
+		public virtual void  Add(Query query)
+		{
+			disjuncts.Add(query);
+		}
+		
+		/// <summary>Add a collection of disjuncts to this disjunction
+		/// via Iterable<Query>
+		/// </summary>
+		public virtual void  Add(System.Collections.ICollection disjuncts)
+		{
+			this.disjuncts.AddRange(disjuncts);
+		}
+		
+		/// <summary>An Iterator<Query> over the disjuncts </summary>
+		public virtual System.Collections.IEnumerator Iterator()
+		{
+			return disjuncts.GetEnumerator();
+		}
+		
+		/* The Weight for DisjunctionMaxQuery's, used to normalize, score and explain these queries */
+		[Serializable]
+		private class DisjunctionMaxWeight : Weight
+		{
+			private void  InitBlock(DisjunctionMaxQuery enclosingInstance)
+			{
+				this.enclosingInstance = enclosingInstance;
+			}
+			private DisjunctionMaxQuery enclosingInstance;
+			public DisjunctionMaxQuery Enclosing_Instance
+			{
+				get
+				{
+					return enclosingInstance;
+				}
+				
+			}
+			
+			private Searcher searcher; // The searcher with which we are associated.
+			private System.Collections.ArrayList weights = new System.Collections.ArrayList(); // The Weight's for our subqueries, in 1-1 correspondence with disjuncts
+			
+			/* Construct the Weight for this Query searched by searcher.  Recursively construct subquery weights. */
+			public DisjunctionMaxWeight(DisjunctionMaxQuery enclosingInstance, Searcher searcher)
+			{
+				InitBlock(enclosingInstance);
+				this.searcher = searcher;
+				for (int i = 0; i < Enclosing_Instance.disjuncts.Count; i++)
+					weights.Add(((Query) Enclosing_Instance.disjuncts[i]).CreateWeight(searcher));
+			}
+			
+			/* Return our associated DisjunctionMaxQuery */
+			public virtual Query GetQuery()
+			{
+				return Enclosing_Instance;
+			}
+			
+			/* Return our boost */
+			public virtual float GetValue()
+			{
+				return Enclosing_Instance.GetBoost();
+			}
+			
+			/* Compute the sub of squared weights of us applied to our subqueries.  Used for normalization. */
+			public virtual float SumOfSquaredWeights()
+			{
+				float max = 0.0f, sum = 0.0f;
+				for (int i = 0; i < weights.Count; i++)
+				{
+					float sub = ((Weight) weights[i]).SumOfSquaredWeights();
+					sum += sub;
+					max = System.Math.Max(max, sub);
+				}
+				return (((sum - max) * Enclosing_Instance.tieBreakerMultiplier * Enclosing_Instance.tieBreakerMultiplier) + max) * Enclosing_Instance.GetBoost() * Enclosing_Instance.GetBoost();
+			}
+			
+			/* Apply the computed normalization factor to our subqueries */
+			public virtual void  Normalize(float norm)
+			{
+				norm *= Enclosing_Instance.GetBoost(); // Incorporate our boost
+				for (int i = 0; i < weights.Count; i++)
+					((Weight) weights[i]).Normalize(norm);
+			}
+			
+			/* Create the scorer used to score our associated DisjunctionMaxQuery */
+			public virtual Scorer Scorer(IndexReader reader)
+			{
+				DisjunctionMaxScorer result = new DisjunctionMaxScorer(Enclosing_Instance.tieBreakerMultiplier, Enclosing_Instance.GetSimilarity(searcher));
+				for (int i = 0; i < weights.Count; i++)
+				{
+					Weight w = (Weight) weights[i];
+					Scorer subScorer = w.Scorer(reader);
+					if (subScorer == null)
+						return null;
+					result.Add(subScorer);
+				}
+				return result;
+			}
+			
+			/* Explain the score we computed for doc */
+			public virtual Explanation Explain(IndexReader reader, int doc)
+			{
+				if (Enclosing_Instance.disjuncts.Count == 1)
+					return ((Weight) weights[0]).Explain(reader, doc);
+				Explanation result = new Explanation();
+				float max = 0.0f, sum = 0.0f;
+				result.SetDescription(Enclosing_Instance.tieBreakerMultiplier == 0.0f ? "max of:" : "max plus " + Enclosing_Instance.tieBreakerMultiplier + " times others of:");
+				for (int i = 0; i < weights.Count; i++)
+				{
+					Explanation e = ((Weight) weights[i]).Explain(reader, doc);
+					if (e.GetValue() > 0)
+					{
+						result.AddDetail(e);
+						sum += e.GetValue();
+						max = System.Math.Max(max, e.GetValue());
+					}
+				}
+				result.SetValue(max + (sum - max) * Enclosing_Instance.tieBreakerMultiplier);
+				return result;
+			}
+		} // end of DisjunctionMaxWeight inner class
+		
+		/* Create the Weight used to score us */
+		protected internal override Weight CreateWeight(Searcher searcher)
+		{
+			return new DisjunctionMaxWeight(this, searcher);
+		}
+		
+		/// <summary>Optimize our representation and our subqueries representations</summary>
+		/// <param name="reader">the IndexReader we query
+		/// </param>
+		/// <returns> an optimized copy of us (which may not be a copy if there is nothing to optimize) 
+		/// </returns>
+		public override Query Rewrite(IndexReader reader)
+		{
+			if (disjuncts.Count == 1)
+			{
+				Query singleton = (Query) disjuncts[0];
+				Query result = singleton.Rewrite(reader);
+				if (GetBoost() != 1.0f)
+				{
+					if (result == singleton)
+						result = (Query) result.Clone();
+					result.SetBoost(GetBoost() * result.GetBoost());
+				}
+				return result;
+			}
+			DisjunctionMaxQuery clone = null;
+			for (int i = 0; i < disjuncts.Count; i++)
+			{
+				Query clause = (Query) disjuncts[i];
+				Query rewrite = clause.Rewrite(reader);
+				if (rewrite != clause)
+				{
+					if (clone == null)
+						clone = (DisjunctionMaxQuery) this.Clone();
+					clone.disjuncts[i] = rewrite;
+				}
+			}
+			if (clone != null)
+				return clone;
+			else
+				return this;
+		}
+		
+		/// <summary>Create a shallow copy of us -- used in rewriting if necessary</summary>
+		/// <returns> a copy of us (but reuse, don't copy, our subqueries) 
+		/// </returns>
+		public override System.Object Clone()
+		{
+			DisjunctionMaxQuery clone = (DisjunctionMaxQuery) base.Clone();
+			clone.disjuncts = (System.Collections.ArrayList) this.disjuncts.Clone();
+			return clone;
+		}
+		
+		/// <summary>Prettyprint us.</summary>
+		/// <param name="field">the field to which we are applied
+		/// </param>
+		/// <returns> a string that shows what we do, of the form "(disjunct1 | disjunct2 | ... | disjunctn)^boost"
+		/// </returns>
+		public override System.String ToString(System.String field)
+		{
+			System.Text.StringBuilder buffer = new System.Text.StringBuilder();
+			buffer.Append("(");
+			for (int i = 0; i < disjuncts.Count; i++)
+			{
+				Query subquery = (Query) disjuncts[i];
+				if (subquery is BooleanQuery)
+				{
+					// wrap sub-bools in parens
+					buffer.Append("(");
+					buffer.Append(subquery.ToString(field));
+					buffer.Append(")");
+				}
+				else
+					buffer.Append(subquery.ToString(field));
+				if (i != disjuncts.Count - 1)
+					buffer.Append(" | ");
+			}
+			buffer.Append(")");
+			if (tieBreakerMultiplier != 0.0f)
+			{
+				buffer.Append("~");
+				buffer.Append(tieBreakerMultiplier);
+			}
+			if (GetBoost() != 1.0)
+			{
+				buffer.Append("^");
+				buffer.Append(GetBoost());
+			}
+			return buffer.ToString();
+		}
+		
+		/// <summary>Return true iff we represent the same query as o</summary>
+		/// <param name="o">another object
+		/// </param>
+		/// <returns> true iff o is a DisjunctionMaxQuery with the same boost and the same subqueries, in the same order, as us
+		/// </returns>
+		public  override bool Equals(System.Object o)
+		{
+			if (!(o is DisjunctionMaxQuery))
+				return false;
+			DisjunctionMaxQuery other = (DisjunctionMaxQuery) o;
+			return this.GetBoost() == other.GetBoost() && 
+                this.tieBreakerMultiplier == other.tieBreakerMultiplier && 
+                this.disjuncts.Equals(other.disjuncts);
+		}
+		
+		/// <summary>Compute a hash code for hashing us</summary>
+		/// <returns> the hash code
+		/// </returns>
+		public override int GetHashCode()
+		{
+			return BitConverter.ToInt32(BitConverter.GetBytes(GetBoost()), 0) + BitConverter.ToInt32(BitConverter.GetBytes(tieBreakerMultiplier), 0) + disjuncts.GetHashCode();
+		}
+	}
+}
\ No newline at end of file

Added: incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/DisjunctionMaxScorer.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Search/DisjunctionMaxScorer.cs?rev=411501&view=auto
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/DisjunctionMaxScorer.cs (added)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Search/DisjunctionMaxScorer.cs Sat Jun  3 19:41:13 2006
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+
+namespace Lucene.Net.Search
+{
+	
+	/// <summary> The Scorer for DisjunctionMaxQuery's.  The union of all documents generated by the the subquery scorers
+	/// is generated in document number order.  The score for each document is the maximum of the scores computed
+	/// by the subquery scorers that generate that document, plus tieBreakerMultiplier times the sum of the scores
+	/// for the other subqueries that generate the document.
+	/// </summary>
+	/// <author>  Chuck Williams
+	/// </author>
+	class DisjunctionMaxScorer : Scorer
+	{
+		
+		/* The scorers for subqueries that have remaining docs, kept as a min heap by number of next doc. */
+		private System.Collections.ArrayList subScorers = new System.Collections.ArrayList();
+		
+		/* Multiplier applied to non-maximum-scoring subqueries for a document as they are summed into the result. */
+		private float tieBreakerMultiplier;
+		
+		private bool more = false; // True iff there is a next document
+		private bool firstTime = true; // True iff next() has not yet been called
+		
+		/// <summary>Creates a new instance of DisjunctionMaxScorer</summary>
+		/// <param name="tieBreakerMultiplier">Multiplier applied to non-maximum-scoring subqueries for a document as they are summed into the result.
+		/// </param>
+		/// <param name="similarity">-- not used since our definition involves neither coord nor terms directly 
+		/// </param>
+		public DisjunctionMaxScorer(float tieBreakerMultiplier, Similarity similarity) : base(similarity)
+		{
+			this.tieBreakerMultiplier = tieBreakerMultiplier;
+		}
+		
+		/// <summary>Add the scorer for a subquery</summary>
+		/// <param name="scorer">the scorer of a subquery of our associated DisjunctionMaxQuery
+		/// </param>
+		public virtual void  Add(Scorer scorer)
+		{
+			if (scorer.Next())
+			{
+				// Initialize and retain only if it produces docs
+				subScorers.Add(scorer);
+				more = true;
+			}
+		}
+		
+		/// <summary>Generate the next document matching our associated DisjunctionMaxQuery.</summary>
+		/// <returns> true iff there is a next document
+		/// </returns>
+		public override bool Next()
+		{
+			if (!more)
+				return false;
+			if (firstTime)
+			{
+				Heapify();
+				firstTime = false;
+				return true; // more would have been false if no subScorers had any docs
+			}
+			// Increment all generators that generated the last doc and adjust the heap.
+			int lastdoc = ((Scorer) subScorers[0]).Doc();
+			do 
+			{
+				if (((Scorer) subScorers[0]).Next())
+					HeapAdjust(0);
+				else
+				{
+					HeapRemoveRoot();
+					if ((subScorers.Count == 0))
+						return (more = false);
+				}
+			}
+			while (((Scorer) subScorers[0]).Doc() == lastdoc);
+			return true;
+		}
+		
+		/// <summary>Determine the current document number.  Initially invalid, until {@link #Next()} is called the first time.</summary>
+		/// <returns> the document number of the currently generated document
+		/// </returns>
+		public override int Doc()
+		{
+			return ((Scorer) subScorers[0]).Doc();
+		}
+		
+		/// <summary>Determine the current document score.  Initially invalid, until {@link #Next()} is called the first time.</summary>
+		/// <returns> the score of the current generated document
+		/// </returns>
+		public override float Score()
+		{
+			int doc = ((Scorer) subScorers[0]).Doc();
+			float[] sum = new float[]{((Scorer) subScorers[0]).Score()}, max = new float[]{sum[0]};
+			int size = subScorers.Count;
+			ScoreAll(1, size, doc, sum, max);
+			ScoreAll(2, size, doc, sum, max);
+			return max[0] + (sum[0] - max[0]) * tieBreakerMultiplier;
+		}
+		
+		// Recursively iterate all subScorers that generated last doc computing sum and max
+		private void  ScoreAll(int root, int size, int doc, float[] sum, float[] max)
+		{
+			if (root < size && ((Scorer) subScorers[root]).Doc() == doc)
+			{
+				float sub = ((Scorer) subScorers[root]).Score();
+				sum[0] += sub;
+				max[0] = System.Math.Max(max[0], sub);
+				ScoreAll((root << 1) + 1, size, doc, sum, max);
+				ScoreAll((root << 1) + 2, size, doc, sum, max);
+			}
+		}
+		
+		/// <summary>Advance to the first document beyond the current whose number is greater than or equal to target.</summary>
+		/// <param name="target">the minimum number of the next desired document
+		/// </param>
+		/// <returns> true iff there is a document to be generated whose number is at least target
+		/// </returns>
+		public override bool SkipTo(int target)
+		{
+			while (subScorers.Count > 0 && ((Scorer) subScorers[0]).Doc() < target)
+			{
+				if (((Scorer) subScorers[0]).SkipTo(target))
+					HeapAdjust(0);
+				else
+					HeapRemoveRoot();
+			}
+			if ((subScorers.Count == 0))
+				return (more = false);
+			return true;
+		}
+		
+		/// <summary>Explain a score that we computed.  UNSUPPORTED -- see explanation capability in DisjunctionMaxQuery.</summary>
+		/// <param name="doc">the number of a document we scored
+		/// </param>
+		/// <returns> the Explanation for our score
+		/// </returns>
+		public override Explanation Explain(int doc)
+		{
+			throw new System.NotSupportedException();
+		}
+		
+		// Organize subScorers into a min heap with scorers generating the earlest document on top.
+		private void  Heapify()
+		{
+			int size = subScorers.Count;
+			for (int i = (size >> 1) - 1; i >= 0; i--)
+				HeapAdjust(i);
+		}
+		
+		/* The subtree of subScorers at root is a min heap except possibly for its root element.
+		* Bubble the root down as required to make the subtree a heap.
+		*/
+		private void  HeapAdjust(int root)
+		{
+			Scorer scorer = (Scorer) subScorers[root];
+			int doc = scorer.Doc();
+			int i = root, size = subScorers.Count;
+			while (i <= (size >> 1) - 1)
+			{
+				int lchild = (i << 1) + 1;
+				Scorer lscorer = (Scorer) subScorers[lchild];
+				int ldoc = lscorer.Doc();
+				int rdoc = System.Int32.MaxValue, rchild = (i << 1) + 2;
+				Scorer rscorer = null;
+				if (rchild < size)
+				{
+					rscorer = (Scorer) subScorers[rchild];
+					rdoc = rscorer.Doc();
+				}
+				if (ldoc < doc)
+				{
+					if (rdoc < ldoc)
+					{
+						subScorers[i] = rscorer;
+						subScorers[rchild] = scorer;
+						i = rchild;
+					}
+					else
+					{
+						subScorers[i] = lscorer;
+						subScorers[lchild] = scorer;
+						i = lchild;
+					}
+				}
+				else if (rdoc < doc)
+				{
+					subScorers[i] = rscorer;
+					subScorers[rchild] = scorer;
+					i = rchild;
+				}
+				else
+					return ;
+			}
+		}
+		
+		// Remove the root Scorer from subScorers and re-establish it as a heap
+		private void  HeapRemoveRoot()
+		{
+			int size = subScorers.Count;
+			if (size == 1)
+				subScorers.RemoveAt(0);
+			else
+			{
+				subScorers[0] = subScorers[size - 1];
+				subScorers.RemoveAt(size - 1);
+				HeapAdjust(0);
+			}
+		}
+	}
+}
\ No newline at end of file



Mime
View raw message