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

搜索引擎

开发平台:

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 TermPositions = Lucene.Net.Index.TermPositions;
  20. using ToStringUtils = Lucene.Net.Util.ToStringUtils;
  21. namespace Lucene.Net.Search
  22. {
  23. /// <summary>A Query that matches documents containing a particular sequence of terms.
  24. /// A PhraseQuery is built by QueryParser for input like <code>"new york"</code>.
  25. /// 
  26. /// <p>This query may be combined with other terms or queries with a {@link BooleanQuery}.
  27. /// </summary>
  28. [Serializable]
  29. public class PhraseQuery : Query
  30. {
  31. private System.String field;
  32. private System.Collections.ArrayList terms = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
  33. private System.Collections.ArrayList positions = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
  34. private int slop = 0;
  35. /// <summary>Constructs an empty phrase query. </summary>
  36. public PhraseQuery()
  37. {
  38. }
  39. /// <summary>Sets the number of other words permitted between words in query phrase.
  40. /// If zero, then this is an exact phrase search.  For larger values this works
  41. /// like a <code>WITHIN</code> or <code>NEAR</code> operator.
  42. /// <p>The slop is in fact an edit-distance, where the units correspond to
  43. /// moves of terms in the query phrase out of position.  For example, to switch
  44. /// the order of two words requires two moves (the first move places the words
  45. /// atop one another), so to permit re-orderings of phrases, the slop must be
  46. /// at least two.
  47. /// <p>More exact matches are scored higher than sloppier matches, thus search
  48. /// results are sorted by exactness.
  49. /// <p>The slop is zero by default, requiring exact matches.
  50. /// </summary>
  51. public virtual void  SetSlop(int s)
  52. {
  53. slop = s;
  54. }
  55. /// <summary>Returns the slop.  See setSlop(). </summary>
  56. public virtual int GetSlop()
  57. {
  58. return slop;
  59. }
  60. /// <summary> Adds a term to the end of the query phrase.
  61. /// The relative position of the term is the one immediately after the last term added.
  62. /// </summary>
  63. public virtual void  Add(Term term)
  64. {
  65. int position = 0;
  66. if (positions.Count > 0)
  67. position = ((System.Int32) positions[positions.Count - 1]) + 1;
  68. Add(term, position);
  69. }
  70. /// <summary> Adds a term to the end of the query phrase.
  71. /// The relative position of the term within the phrase is specified explicitly.
  72. /// This allows e.g. phrases with more than one term at the same position
  73. /// or phrases with gaps (e.g. in connection with stopwords).
  74. /// 
  75. /// </summary>
  76. /// <param name="term">
  77. /// </param>
  78. /// <param name="position">
  79. /// </param>
  80. public virtual void  Add(Term term, int position)
  81. {
  82. if (terms.Count == 0)
  83. field = term.Field();
  84. else if (term.Field() != field)
  85. {
  86. throw new System.ArgumentException("All phrase terms must be in the same field: " + term);
  87. }
  88. terms.Add(term);
  89. positions.Add((System.Int32) position);
  90. }
  91. /// <summary>Returns the set of terms in this phrase. </summary>
  92. public virtual Term[] GetTerms()
  93. {
  94. return (Term[]) terms.ToArray(typeof(Term));
  95. }
  96. /// <summary> Returns the relative positions of terms in this phrase.</summary>
  97. public virtual int[] GetPositions()
  98. {
  99. int[] result = new int[positions.Count];
  100. for (int i = 0; i < positions.Count; i++)
  101. result[i] = ((System.Int32) positions[i]);
  102. return result;
  103. }
  104. [Serializable]
  105. private class PhraseWeight : Weight
  106. {
  107. private void  InitBlock(PhraseQuery enclosingInstance)
  108. {
  109. this.enclosingInstance = enclosingInstance;
  110. }
  111. private PhraseQuery enclosingInstance;
  112. public PhraseQuery Enclosing_Instance
  113. {
  114. get
  115. {
  116. return enclosingInstance;
  117. }
  118. }
  119. private Similarity similarity;
  120. private float value_Renamed;
  121. private float idf;
  122. private float queryNorm;
  123. private float queryWeight;
  124. public PhraseWeight(PhraseQuery enclosingInstance, Searcher searcher)
  125. {
  126. InitBlock(enclosingInstance);
  127. this.similarity = Enclosing_Instance.GetSimilarity(searcher);
  128. idf = similarity.Idf(Enclosing_Instance.terms, searcher);
  129. }
  130. public override System.String ToString()
  131. {
  132. return "weight(" + Enclosing_Instance + ")";
  133. }
  134. public virtual Query GetQuery()
  135. {
  136. return Enclosing_Instance;
  137. }
  138. public virtual float GetValue()
  139. {
  140. return value_Renamed;
  141. }
  142. public virtual float SumOfSquaredWeights()
  143. {
  144. queryWeight = idf * Enclosing_Instance.GetBoost(); // compute query weight
  145. return queryWeight * queryWeight; // square it
  146. }
  147. public virtual void  Normalize(float queryNorm)
  148. {
  149. this.queryNorm = queryNorm;
  150. queryWeight *= queryNorm; // normalize query weight
  151. value_Renamed = queryWeight * idf; // idf for document 
  152. }
  153. public virtual Scorer Scorer(IndexReader reader)
  154. {
  155. if (Enclosing_Instance.terms.Count == 0)
  156. // optimize zero-term case
  157. return null;
  158. TermPositions[] tps = new TermPositions[Enclosing_Instance.terms.Count];
  159. for (int i = 0; i < Enclosing_Instance.terms.Count; i++)
  160. {
  161. TermPositions p = reader.TermPositions((Term) Enclosing_Instance.terms[i]);
  162. if (p == null)
  163. return null;
  164. tps[i] = p;
  165. }
  166. if (Enclosing_Instance.slop == 0)
  167. // optimize exact case
  168. return new ExactPhraseScorer(this, tps, Enclosing_Instance.GetPositions(), similarity, reader.Norms(Enclosing_Instance.field));
  169. else
  170. return new SloppyPhraseScorer(this, tps, Enclosing_Instance.GetPositions(), similarity, Enclosing_Instance.slop, reader.Norms(Enclosing_Instance.field));
  171. }
  172. public virtual Explanation Explain(IndexReader reader, int doc)
  173. {
  174. Explanation result = new Explanation();
  175. result.SetDescription("weight(" + GetQuery() + " in " + doc + "), product of:");
  176. System.Text.StringBuilder docFreqs = new System.Text.StringBuilder();
  177. System.Text.StringBuilder query = new System.Text.StringBuilder();
  178. query.Append('"');
  179. for (int i = 0; i < Enclosing_Instance.terms.Count; i++)
  180. {
  181. if (i != 0)
  182. {
  183. docFreqs.Append(" ");
  184. query.Append(" ");
  185. }
  186. Term term = (Term) Enclosing_Instance.terms[i];
  187. docFreqs.Append(term.Text());
  188. docFreqs.Append("=");
  189. docFreqs.Append(reader.DocFreq(term));
  190. query.Append(term.Text());
  191. }
  192. query.Append('"');
  193. Explanation idfExpl = new Explanation(idf, "idf(" + Enclosing_Instance.field + ": " + docFreqs + ")");
  194. // explain query weight
  195. Explanation queryExpl = new Explanation();
  196. queryExpl.SetDescription("queryWeight(" + GetQuery() + "), product of:");
  197. Explanation boostExpl = new Explanation(Enclosing_Instance.GetBoost(), "boost");
  198. if (Enclosing_Instance.GetBoost() != 1.0f)
  199. queryExpl.AddDetail(boostExpl);
  200. queryExpl.AddDetail(idfExpl);
  201. Explanation queryNormExpl = new Explanation(queryNorm, "queryNorm");
  202. queryExpl.AddDetail(queryNormExpl);
  203. queryExpl.SetValue(boostExpl.GetValue() * idfExpl.GetValue() * queryNormExpl.GetValue());
  204. result.AddDetail(queryExpl);
  205. // explain field weight
  206. Explanation fieldExpl = new Explanation();
  207. fieldExpl.SetDescription("fieldWeight(" + Enclosing_Instance.field + ":" + query + " in " + doc + "), product of:");
  208. Explanation tfExpl = Scorer(reader).Explain(doc);
  209. fieldExpl.AddDetail(tfExpl);
  210. fieldExpl.AddDetail(idfExpl);
  211. Explanation fieldNormExpl = new Explanation();
  212. byte[] fieldNorms = reader.Norms(Enclosing_Instance.field);
  213. float fieldNorm = fieldNorms != null?Similarity.DecodeNorm(fieldNorms[doc]):0.0f;
  214. fieldNormExpl.SetValue(fieldNorm);
  215. fieldNormExpl.SetDescription("fieldNorm(field=" + Enclosing_Instance.field + ", doc=" + doc + ")");
  216. fieldExpl.AddDetail(fieldNormExpl);
  217. fieldExpl.SetValue(tfExpl.GetValue() * idfExpl.GetValue() * fieldNormExpl.GetValue());
  218. result.AddDetail(fieldExpl);
  219. // combine them
  220. result.SetValue(queryExpl.GetValue() * fieldExpl.GetValue());
  221. if (queryExpl.GetValue() == 1.0f)
  222. return fieldExpl;
  223. return result;
  224. }
  225. }
  226. protected internal override Weight CreateWeight(Searcher searcher)
  227. {
  228. if (terms.Count == 1)
  229. {
  230. // optimize one-term case
  231. Term term = (Term) terms[0];
  232. Query termQuery = new TermQuery(term);
  233. termQuery.SetBoost(GetBoost());
  234. return termQuery.CreateWeight(searcher);
  235. }
  236. return new PhraseWeight(this, searcher);
  237. }
  238. /// <seealso cref="Lucene.Net.search.Query.ExtractTerms(java.util.Set)">
  239. /// </seealso>
  240. public override void  ExtractTerms(System.Collections.Hashtable queryTerms)
  241. {
  242. foreach (Term term in terms)
  243. {
  244. queryTerms.Add(term, term);
  245. }
  246. }
  247. /// <summary>Prints a user-readable version of this query. </summary>
  248. public override System.String ToString(System.String f)
  249. {
  250. System.Text.StringBuilder buffer = new System.Text.StringBuilder();
  251. if (!field.Equals(f))
  252. {
  253. buffer.Append(field);
  254. buffer.Append(":");
  255. }
  256. buffer.Append(""");
  257. for (int i = 0; i < terms.Count; i++)
  258. {
  259. buffer.Append(((Term) terms[i]).Text());
  260. if (i != terms.Count - 1)
  261. buffer.Append(" ");
  262. }
  263. buffer.Append(""");
  264. if (slop != 0)
  265. {
  266. buffer.Append("~");
  267. buffer.Append(slop);
  268. }
  269. buffer.Append(ToStringUtils.Boost(GetBoost()));
  270. return buffer.ToString();
  271. }
  272. /// <summary>Returns true iff <code>o</code> is equal to this. </summary>
  273. public  override bool Equals(System.Object o)
  274. {
  275. if (!(o is PhraseQuery))
  276. return false;
  277. PhraseQuery other = (PhraseQuery) o;
  278.             return (this.GetBoost() == other.GetBoost()) && 
  279.                 (this.slop == other.slop) && 
  280.                 this.terms.Equals(other.terms) && 
  281.                 this.positions.Equals(other.positions);
  282. }
  283. /// <summary>Returns a hash code value for this object.</summary>
  284. public override int GetHashCode()
  285. {
  286. return BitConverter.ToInt32(BitConverter.GetBytes(GetBoost()), 0) ^ slop ^ terms.GetHashCode() ^ positions.GetHashCode();
  287. }
  288. // {{Aroush-1.9}} Do we need this?!
  289. override public System.Object Clone()
  290. {
  291. return null;
  292. }
  293. }
  294. }