FuzzyQuery.cs
上传用户:zhangkuixh
上传日期:2013-09-30
资源大小:5473k
文件大小:7k
源码类别:

搜索引擎

开发平台:

C#

  1. /*
  2.  * Copyright 2004 The Apache Software Foundation
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License");
  5.  * you may not use this file except in compliance with the License.
  6.  * You may obtain a copy of the License at
  7.  * 
  8.  * http://www.apache.org/licenses/LICENSE-2.0
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software
  11.  * distributed under the License is distributed on an "AS IS" BASIS,
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  * See the License for the specific language governing permissions and
  14.  * limitations under the License.
  15.  */
  16. using System;
  17. using IndexReader = Lucene.Net.Index.IndexReader;
  18. using Term = Lucene.Net.Index.Term;
  19. using PriorityQueue = Lucene.Net.Util.PriorityQueue;
  20. using ToStringUtils = Lucene.Net.Util.ToStringUtils;
  21. namespace Lucene.Net.Search
  22. {
  23. /// <summary>Implements the fuzzy search query. The similiarity measurement
  24. /// is based on the Levenshtein (edit distance) algorithm.
  25. /// </summary>
  26. [Serializable]
  27. public sealed class FuzzyQuery : MultiTermQuery
  28. {
  29. public const float defaultMinSimilarity = 0.5f;
  30. public const int defaultPrefixLength = 0;
  31. private float minimumSimilarity;
  32. private int prefixLength;
  33. /// <summary> Create a new FuzzyQuery that will match terms with a similarity 
  34. /// of at least <code>minimumSimilarity</code> to <code>term</code>.
  35. /// If a <code>prefixLength</code> &gt; 0 is specified, a common prefix
  36. /// of that length is also required.
  37. /// 
  38. /// </summary>
  39. /// <param name="term">the term to search for
  40. /// </param>
  41. /// <param name="minimumSimilarity">a value between 0 and 1 to set the required similarity
  42. /// between the query term and the matching terms. For example, for a
  43. /// <code>minimumSimilarity</code> of <code>0.5</code> a term of the same length
  44. /// as the query term is considered similar to the query term if the edit distance
  45. /// between both terms is less than <code>length(term)*0.5</code>
  46. /// </param>
  47. /// <param name="prefixLength">length of common (non-fuzzy) prefix
  48. /// </param>
  49. /// <throws>  IllegalArgumentException if minimumSimilarity is &gt;= 1 or &lt; 0 </throws>
  50. /// <summary> or if prefixLength &lt; 0
  51. /// </summary>
  52. public FuzzyQuery(Term term, float minimumSimilarity, int prefixLength):base(term)
  53. {
  54. if (minimumSimilarity >= 1.0f)
  55. throw new System.ArgumentException("minimumSimilarity >= 1");
  56. else if (minimumSimilarity < 0.0f)
  57. throw new System.ArgumentException("minimumSimilarity < 0");
  58. if (prefixLength < 0)
  59. throw new System.ArgumentException("prefixLength < 0");
  60. this.minimumSimilarity = minimumSimilarity;
  61. this.prefixLength = prefixLength;
  62. }
  63. /// <summary> Calls {@link #FuzzyQuery(Term, float) FuzzyQuery(term, minimumSimilarity, 0)}.</summary>
  64. public FuzzyQuery(Term term, float minimumSimilarity):this(term, minimumSimilarity, defaultPrefixLength)
  65. {
  66. }
  67. /// <summary> Calls {@link #FuzzyQuery(Term, float) FuzzyQuery(term, 0.5f, 0)}.</summary>
  68. public FuzzyQuery(Term term):this(term, defaultMinSimilarity, defaultPrefixLength)
  69. {
  70. }
  71. /// <summary> Returns the minimum similarity that is required for this query to match.</summary>
  72. /// <returns> float value between 0.0 and 1.0
  73. /// </returns>
  74. public float GetMinSimilarity()
  75. {
  76. return minimumSimilarity;
  77. }
  78. /// <summary> Returns the non-fuzzy prefix length. This is the number of characters at the start
  79. /// of a term that must be identical (not fuzzy) to the query term if the query
  80. /// is to match that term. 
  81. /// </summary>
  82. public int GetPrefixLength()
  83. {
  84. return prefixLength;
  85. }
  86. protected internal override FilteredTermEnum GetEnum(IndexReader reader)
  87. {
  88. return new FuzzyTermEnum(reader, GetTerm(), minimumSimilarity, prefixLength);
  89. }
  90. public override Query Rewrite(IndexReader reader)
  91. {
  92. FilteredTermEnum enumerator = GetEnum(reader);
  93. int maxClauseCount = BooleanQuery.GetMaxClauseCount();
  94. ScoreTermQueue stQueue = new ScoreTermQueue(maxClauseCount);
  95. try
  96. {
  97. do 
  98. {
  99. float minScore = 0.0f;
  100. float score = 0.0f;
  101. Term t = enumerator.Term();
  102. if (t != null)
  103. {
  104. score = enumerator.Difference();
  105. // terms come in alphabetical order, therefore if queue is full and score
  106. // not bigger than minScore, we can skip
  107. if (stQueue.Size() < maxClauseCount || score > minScore)
  108. {
  109. stQueue.Insert(new ScoreTerm(t, score));
  110. minScore = ((ScoreTerm) stQueue.Top()).score; // maintain minScore
  111. }
  112. }
  113. }
  114. while (enumerator.Next());
  115. }
  116. finally
  117. {
  118. enumerator.Close();
  119. }
  120. BooleanQuery query = new BooleanQuery(true);
  121. int size = stQueue.Size();
  122. for (int i = 0; i < size; i++)
  123. {
  124. ScoreTerm st = (ScoreTerm) stQueue.Pop();
  125. TermQuery tq = new TermQuery(st.term); // found a match
  126. tq.SetBoost(GetBoost() * st.score); // set the boost
  127. query.Add(tq, BooleanClause.Occur.SHOULD); // add to query
  128. }
  129. return query;
  130. }
  131. public override System.String ToString(System.String field)
  132. {
  133. System.Text.StringBuilder buffer = new System.Text.StringBuilder();
  134. Term term = GetTerm();
  135. if (!term.Field().Equals(field))
  136. {
  137. buffer.Append(term.Field());
  138. buffer.Append(":");
  139. }
  140. buffer.Append(term.Text());
  141. buffer.Append('~');
  142. buffer.Append(minimumSimilarity.ToString());
  143. buffer.Append(ToStringUtils.Boost(GetBoost()));
  144. return buffer.ToString();
  145. }
  146. private class ScoreTerm
  147. {
  148. public Term term;
  149. public float score;
  150. public ScoreTerm(Term term, float score)
  151. {
  152. this.term = term;
  153. this.score = score;
  154. }
  155. }
  156. private class ScoreTermQueue : PriorityQueue
  157. {
  158. public ScoreTermQueue(int size)
  159. {
  160. Initialize(size);
  161. }
  162. /* (non-Javadoc)
  163. * @see Lucene.Net.util.PriorityQueue#lessThan(java.lang.Object, java.lang.Object)
  164. */
  165. public override bool LessThan(System.Object a, System.Object b)
  166. {
  167. ScoreTerm termA = (ScoreTerm) a;
  168. ScoreTerm termB = (ScoreTerm) b;
  169. if (termA.score == termB.score)
  170. return termA.term.CompareTo(termB.term) > 0;
  171. else
  172. return termA.score < termB.score;
  173. }
  174. }
  175. public  override bool Equals(System.Object o)
  176. {
  177. if (this == o)
  178. return true;
  179. if (!(o is FuzzyQuery))
  180. return false;
  181. if (!base.Equals(o))
  182. return false;
  183. FuzzyQuery fuzzyQuery = (FuzzyQuery) o;
  184. if (minimumSimilarity != fuzzyQuery.minimumSimilarity)
  185. return false;
  186. if (prefixLength != fuzzyQuery.prefixLength)
  187. return false;
  188. return true;
  189. }
  190. public override int GetHashCode()
  191. {
  192. int result = base.GetHashCode();
  193.             result = 29 * result + minimumSimilarity != + 0.0f ? BitConverter.ToInt32(BitConverter.GetBytes(minimumSimilarity), 0) : 0;
  194. result = 29 * result + prefixLength;
  195. return result;
  196. }
  197. }
  198. }