PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/Raven.Database/Extensions/IndexingExtensions.cs

http://github.com/ravendb/ravendb
C# | 293 lines | 248 code | 38 blank | 7 comment | 76 complexity | 0d0c53d27b920b0c068a734b87d3003e MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-3-Clause
  1. //-----------------------------------------------------------------------
  2. // <copyright file="IndexingExtensions.cs" company="Hibernating Rhinos LTD">
  3. // Copyright (c) Hibernating Rhinos LTD. All rights reserved.
  4. // </copyright>
  5. //-----------------------------------------------------------------------
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Globalization;
  9. using System.Linq;
  10. using System.Reflection;
  11. using System.Runtime.CompilerServices;
  12. using System.Runtime.InteropServices;
  13. using Lucene.Net.Analysis;
  14. using Lucene.Net.Analysis.Standard;
  15. using Lucene.Net.Documents;
  16. using Lucene.Net.Index;
  17. using Lucene.Net.Search;
  18. using Raven.Abstractions.Data;
  19. using Raven.Abstractions.Indexing;
  20. using Raven.Database.Indexing;
  21. using Raven.Database.Indexing.Sorting;
  22. using Raven.Database.Indexing.Sorting.Custom;
  23. using Raven.Database.Linq;
  24. using Raven.Database.Queries;
  25. using Spatial4n.Core.Shapes;
  26. using Spatial4n.Core.Shapes.Impl;
  27. using Constants = Raven.Abstractions.Data.Constants;
  28. namespace Raven.Database.Extensions
  29. {
  30. public static class IndexingExtensions
  31. {
  32. public static Analyzer CreateAnalyzerInstance(string name, string analyzerTypeAsString)
  33. {
  34. var analyzerType = GetAnalyzerType(name, analyzerTypeAsString);
  35. try
  36. {
  37. var assembly = analyzerType.Assembly;
  38. // try to get parameterless ctor
  39. var ctors = analyzerType.GetConstructor(Type.EmptyTypes);
  40. if (ctors != null)
  41. return (Analyzer)Activator.CreateInstance(assembly.FullName, analyzerType.FullName).Unwrap();
  42. ctors = analyzerType.GetConstructor(new[] { typeof(Lucene.Net.Util.Version) });
  43. if (ctors != null)
  44. return (Analyzer)Activator
  45. .CreateInstance(assembly.FullName, analyzerType.FullName, false, BindingFlags.CreateInstance | BindingFlags.Public | BindingFlags.Instance, null, new object[] { Lucene.Net.Util.Version.LUCENE_30 }, CultureInfo.InvariantCulture, null)
  46. .Unwrap();
  47. }
  48. catch (Exception e)
  49. {
  50. throw new InvalidOperationException(
  51. "Could not create new analyzer instance '" + analyzerTypeAsString + "' for field: " +
  52. name, e);
  53. }
  54. throw new InvalidOperationException(
  55. "Could not create new analyzer instance '" + analyzerTypeAsString + "' for field: " + name + ". No recognizable constructor found.");
  56. }
  57. public static Type GetAnalyzerType(string name, string analyzerTypeAsString)
  58. {
  59. var luceneAssembly = typeof (StandardAnalyzer).Assembly;
  60. var analyzerType = luceneAssembly.GetType(analyzerTypeAsString) ??
  61. Type.GetType(analyzerTypeAsString) ??
  62. luceneAssembly.GetType("Lucene.Net.Analysis." + analyzerTypeAsString) ??
  63. luceneAssembly.GetType("Lucene.Net.Analysis.Standard." + analyzerTypeAsString);
  64. if (analyzerType == null)
  65. throw new InvalidOperationException("Cannot find analyzer type '" + analyzerTypeAsString + "' for field: " + name);
  66. return analyzerType;
  67. }
  68. public static Field.Index GetIndex(this IndexDefinition self, string name, Field.Index? defaultIndex)
  69. {
  70. if (self.Indexes == null)
  71. return defaultIndex ?? Field.Index.ANALYZED_NO_NORMS;
  72. FieldIndexing value;
  73. if (self.Indexes.TryGetValue(name, out value) == false)
  74. {
  75. if (self.Indexes.TryGetValue(Constants.AllFields, out value) == false)
  76. {
  77. string ignored;
  78. if (self.Analyzers.TryGetValue(name, out ignored) ||
  79. self.Analyzers.TryGetValue(Constants.AllFields, out ignored))
  80. {
  81. return Field.Index.ANALYZED; // if there is a custom analyzer, the value should be analyzed
  82. }
  83. return defaultIndex ?? Field.Index.ANALYZED_NO_NORMS;
  84. }
  85. }
  86. switch (value)
  87. {
  88. case FieldIndexing.No:
  89. return Field.Index.NO;
  90. case FieldIndexing.Analyzed:
  91. return Field.Index.ANALYZED_NO_NORMS;
  92. case FieldIndexing.NotAnalyzed:
  93. return Field.Index.NOT_ANALYZED_NO_NORMS;
  94. case FieldIndexing.Default:
  95. return defaultIndex ?? Field.Index.ANALYZED_NO_NORMS;
  96. default:
  97. throw new ArgumentOutOfRangeException();
  98. }
  99. }
  100. public static Field.Store GetStorage(this IndexDefinition self, string name, Field.Store defaultStorage)
  101. {
  102. if (self.Stores == null)
  103. return defaultStorage;
  104. FieldStorage value;
  105. if (self.Stores.TryGetValue(name, out value) == false)
  106. {
  107. // do we have a overriding default?
  108. if (self.Stores.TryGetValue(Constants.AllFields, out value) == false)
  109. return defaultStorage;
  110. }
  111. switch (value)
  112. {
  113. case FieldStorage.Yes:
  114. return Field.Store.YES;
  115. case FieldStorage.No:
  116. return Field.Store.NO;
  117. default:
  118. throw new ArgumentOutOfRangeException();
  119. }
  120. }
  121. public static Field.TermVector GetTermVector(this IndexDefinition self, string name, Field.TermVector defaultTermVector)
  122. {
  123. if (self.TermVectors == null)
  124. return defaultTermVector;
  125. FieldTermVector value;
  126. if (self.TermVectors.TryGetValue(name, out value) == false)
  127. return defaultTermVector;
  128. if (value != FieldTermVector.No && self.GetIndex(name, null) == Field.Index.NO)
  129. {
  130. throw new InvalidOperationException(string.Format("TermVectors cannot be enabled for the field {0} because Indexing is set to No", name));
  131. }
  132. switch (value)
  133. {
  134. case FieldTermVector.No:
  135. return Field.TermVector.NO;
  136. case FieldTermVector.WithOffsets:
  137. return Field.TermVector.WITH_OFFSETS;
  138. case FieldTermVector.WithPositions:
  139. return Field.TermVector.WITH_POSITIONS;
  140. case FieldTermVector.WithPositionsAndOffsets:
  141. return Field.TermVector.WITH_POSITIONS_OFFSETS;
  142. case FieldTermVector.Yes:
  143. return Field.TermVector.YES;
  144. default:
  145. throw new ArgumentOutOfRangeException();
  146. }
  147. }
  148. [CLSCompliant(false)]
  149. public static Sort GetSort(this IndexQuery self, IndexDefinition indexDefinition, AbstractViewGenerator viewGenerator)
  150. {
  151. var spatialQuery = self as SpatialIndexQuery;
  152. var sortedFields = self.SortedFields;
  153. if (sortedFields == null || sortedFields.Length <= 0)
  154. {
  155. if (spatialQuery == null || string.IsNullOrEmpty(self.Query) == false)
  156. return null;
  157. sortedFields = new[] { new SortedField(Constants.DistanceFieldName), };
  158. }
  159. return new Sort(sortedFields
  160. .Select(sortedField =>
  161. {
  162. if (sortedField.Field == Constants.TemporaryScoreValue)
  163. {
  164. return SortField.FIELD_SCORE;
  165. }
  166. if (sortedField.Field.StartsWith(Constants.RandomFieldName))
  167. {
  168. var parts = sortedField.Field.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
  169. if (parts.Length < 2) // truly random
  170. return new RandomSortField(Guid.NewGuid().ToString());
  171. return new RandomSortField(parts[1]);
  172. }
  173. if (sortedField.Field.StartsWith(Constants.CustomSortFieldName))
  174. {
  175. var parts = sortedField.Field.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
  176. if (parts.Length < 2) // truly random
  177. throw new InvalidOperationException("Cannot figure out type for custom sort");
  178. return new CustomSortField(parts[1], self, parts[0][parts[0].Length-1] == '-');
  179. }
  180. if (sortedField.Field.StartsWith(Constants.DistanceFieldName))
  181. {
  182. SpatialField spatialField = null;
  183. Shape shape ;
  184. if (sortedField.Field.Length == Constants.DistanceFieldName.Length)
  185. {
  186. if (spatialQuery == null)
  187. throw new InvalidOperationException("Illegal Spatial Sort Parameter: Blank Spatial sort cannot be used without a spatial query");
  188. spatialField = viewGenerator.GetSpatialField(spatialQuery.SpatialFieldName);
  189. shape = spatialField.ReadShape(spatialQuery.QueryShape);
  190. }
  191. else
  192. {
  193. var sortParams = sortedField.Field.Split(';');
  194. double lat, lng;
  195. if (sortParams.Length <3 || !double.TryParse(sortParams[1], out lat) || !double.TryParse(sortParams[2], out lng))
  196. throw new InvalidOperationException("Illegal Spatial Sort Parameter");
  197. string spatialFieldName;
  198. if (sortParams.Length >= 4)
  199. {
  200. spatialFieldName = sortParams[3];
  201. }
  202. else
  203. {
  204. if (spatialQuery == null)
  205. {
  206. spatialFieldName = Constants.DefaultSpatialFieldName;
  207. }
  208. else
  209. {
  210. spatialFieldName = spatialQuery.SpatialFieldName;
  211. }
  212. }
  213. spatialField = viewGenerator.GetSpatialField(spatialFieldName);
  214. shape = new PointImpl(lng, lat, spatialField.GetContext());
  215. }
  216. var dsort = new SpatialDistanceFieldComparatorSource(spatialField, shape.GetCenter());
  217. return new SortField(sortedField.Field, dsort, sortedField.Descending);
  218. }
  219. var sortOptions = GetSortOption(indexDefinition, sortedField.Field, self);
  220. if (sortOptions == null || sortOptions == SortOptions.None)
  221. return new SortField(sortedField.Field, CultureInfo.InvariantCulture, sortedField.Descending);
  222. if (sortOptions.Value == SortOptions.Short)
  223. sortOptions = SortOptions.Int;
  224. return new SortField(sortedField.Field, (int)sortOptions.Value, sortedField.Descending);
  225. })
  226. .ToArray());
  227. }
  228. private const string _Range = "_Range";
  229. private const string _SortHint = "SortHint-";
  230. private static CompareInfo InvariantCompare = CultureInfo.InvariantCulture.CompareInfo;
  231. public static SortOptions? GetSortOption(this IndexDefinition self, string name, IndexQuery query)
  232. {
  233. SortOptions value;
  234. if (InvariantCompare.IsSuffix(name, _Range, CompareOptions.None))
  235. {
  236. string nameWithoutRange = name.Substring(0, name.Length - _Range.Length);
  237. if (self.SortOptions.TryGetValue(nameWithoutRange, out value))
  238. return value;
  239. if (self.SortOptions.TryGetValue(Constants.AllFields, out value))
  240. return value;
  241. if (query != null && query.SortHints != null && query.SortHints.TryGetValue(_SortHint + nameWithoutRange, out value))
  242. return value;
  243. }
  244. if (self.SortOptions.TryGetValue(name, out value))
  245. return value;
  246. if (self.SortOptions.TryGetValue(Constants.AllFields, out value))
  247. return value;
  248. if (query == null || query.SortHints == null)
  249. return value;
  250. if (!query.SortHints.TryGetValue(_SortHint + name, out value))
  251. return SortOptions.None;
  252. return value;
  253. }
  254. }
  255. }