Lucene.Net  3.0.3
Lucene.Net is a port of the Lucene search engine library, written in C# and targeted at .NET runtime users.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
IndexSet.cs
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 using System;
19 using System.Collections;
20 using System.Collections.Generic;
21 using System.Collections.Specialized;
22 using System.Configuration;
23 using System.Xml;
24 using Lucene.Net.Distributed;
25 //using Lucene.Net.Distributed.Search;
26 using Lucene.Net.Distributed.Configuration;
27 using Documents = Lucene.Net.Documents;
28 using Lucene.Net.Analysis;
29 using Lucene.Net.Analysis.Standard;
30 using Lucene.Net.Index;
31 
32 namespace Lucene.Net.Distributed.Indexing
33 {
34  /// <summary>
35  /// Definition of configurable search indexes managed by the
36  /// LuceneUpdater windows service.
37  ///
38  /// An example configuration would look like the following:
39  /// <code>
40  /// <indexsets CompoundFile="true" DeltaDirectory="c:\indexes\indexdocuments">
41  /// <indexSet id="1" action="1" analyzer="1">
42  /// <add key="localpath" value="c:\lucene\masterindex\index1" />
43  /// <copy>
44  /// <targetPath indexA="\\LuceneServer\lucene\indexA\index1" indexB="\\LuceneServer\lucene\indexA\index1" />
45  /// <statusDir value="\\LuceneServer\lucene\statusfile\" />
46  /// </copy>
47  /// <add key="bottomid" value="1"/>
48  /// <add key="topid" value="1000"/>
49  /// <add key="idcolumn" value="pkId"/>
50  /// </indexSet>
51  /// </indexsets>
52  /// </code>
53  /// </summary>
54  public class IndexSet
55  {
56  #region Variables
57  private int _intId = -1;
58  private string _strLocalPath;
59  private string _strIdColumn;
60  private int _intBottomId;
61  private int _intTopId;
62  private CurrentIndex _oCurrentIndex;
63  private IndexAction _eIndexAction=IndexAction.NoAction;
64  private AnalyzerType _eAnalyzerType=AnalyzerType.StandardAnalyzer;
65  private Hashtable _htDocuments = new Hashtable();
66  private Hashtable _htIndexDocuments = new Hashtable();
67  private List<string> _alFileSystemDocuments = new List<string>();
68  #endregion
69 
70  #region Constructors
71  /// <summary>
72  /// Public constructor for IndexSet. An IndexSet is defined in XML configuration
73  /// and is loaded via a custom configuration handler.
74  /// </summary>
75  /// <param name="node">XmlNode definition for a given IndexSet</param>
76  public IndexSet(XmlNode node)
77  {
78  this.LoadValues(node);
79  }
80 
81  #endregion
82 
83  #region Internal voids
84  /// <summary>
85  /// Internal load method called from the constructor. Loads underlying values
86  /// based on Xml configuration.
87  /// </summary>
88  /// <param name="node">XmlNode definition for a given IndexSet</param>
89  internal void LoadValues(XmlNode node)
90  {
91  XmlAttributeCollection attributeCollection = node.Attributes;
92  try
93  {
94  this._intId = Convert.ToInt32(attributeCollection["id"].Value);
95  }
96  catch (Exception)
97  {
98  throw new ConfigurationErrorsException("IndexSet id invalid: " + Environment.NewLine + node.OuterXml);
99  }
100 
101  try
102  {
103  this._eIndexAction = (IndexAction)Enum.Parse(typeof(IndexAction), attributeCollection["action"].Value);
104  }
105  catch (Exception)
106  {
107  throw new ConfigurationErrorsException("IndexSet "+this._intId.ToString()+" IndexAction invalid: " + Environment.NewLine + node.OuterXml);
108  }
109 
110  try
111  {
112  if (attributeCollection["analyzer"] != null)
113  this._eAnalyzerType = (AnalyzerType)Enum.Parse(typeof(AnalyzerType), attributeCollection["analyzer"].Value);
114  }
115  catch (Exception)
116  {
117  throw new ConfigurationErrorsException("IndexSet " + this._intId.ToString() + " analyzer invalid: " + Environment.NewLine + node.OuterXml);
118  }
119 
120  if (node.ChildNodes.Count==0)
121  throw new ConfigurationErrorsException("IndexSet " + this._intId.ToString() + " configuration missing " + Environment.NewLine + node.OuterXml);
122 
123  foreach (XmlNode c in node.ChildNodes)
124  {
125  if (!c.HasChildNodes)
126  {
127  switch (c.Attributes["key"].Value.ToLower())
128  {
129  case "localpath":
130  this._strLocalPath = c.Attributes["value"].Value;
131  break;
132  case "idcolumn":
133  this._strIdColumn = c.Attributes["value"].Value;
134  break;
135  case "bottomid":
136  try
137  {
138  this._intBottomId = Convert.ToInt32(c.Attributes["value"].Value);
139  }
140  catch (Exception)
141  {
142  throw new ConfigurationErrorsException("IndexSet " + this._intId.ToString() + " bottomid invalid: " + Environment.NewLine + node.OuterXml);
143  }
144  break;
145  case "topid":
146  try
147  {
148  this._intTopId = Convert.ToInt32(c.Attributes["value"].Value);
149  }
150  catch (Exception)
151  {
152  throw new ConfigurationErrorsException("IndexSet " + this._intId.ToString() + " topid invalid: " + Environment.NewLine + node.OuterXml);
153  }
154  break;
155  }
156  }
157  else
158  {
159  switch(c.Name.ToLower())
160  {
161  case "copy":
162  if (this._strLocalPath!=null)
163  LoadCopy(c,this._strLocalPath);
164  else
165  LoadCopy(c,node);
166  break;
167  }
168  }
169  }
170  this.CheckValidSet(node);
171 
172  }
173 
174  internal void LoadCopy(XmlNode node, string localpath)
175  {
176  this._oCurrentIndex = new CurrentIndex(node,localpath);
177  }
178 
179  internal void LoadCopy(XmlNode node, XmlNode masternode)
180  {
181  foreach (XmlNode c in node.ChildNodes)
182  {
183  if (c.Attributes["key"] != null)
184  {
185  switch (c.Attributes["key"].Value.ToLower())
186  {
187  case "localpath":
188  this.LoadCopy(node, c.Attributes["value"].Value);
189  break;
190  }
191  }
192  }
193  }
194 
195  private void CheckValidSet(XmlNode node)
196  {
197  if (this._strLocalPath==null) throw new ConfigurationErrorsException("IndexSet " + this._intId.ToString() + " LocalPath invalid: " + Environment.NewLine + node.OuterXml);
198  if (this._eIndexAction==IndexAction.NoAction) throw new ConfigurationErrorsException("IndexSet " + this._intId.ToString() + " IndexAction undefined: " + Environment.NewLine + node.OuterXml);
199  if (this._strIdColumn==null) throw new ConfigurationErrorsException("IndexSet " + this._intId.ToString() + " IdColumn undefined: " + Environment.NewLine + node.OuterXml);
200  }
201 
202  #endregion
203 
204  #region Properties
205  /// <summary>
206  /// Unique identifier for an IndexSet within a configuration of multiple IndexSet objects
207  /// </summary>
208  public int Id
209  {
210  get {return this._intId;}
211  }
212 
213  /// <summary>
214  /// Enumeration dictating the type of updates to be applied to the underlying master index
215  /// </summary>
216  public IndexAction IndexAction
217  {
218  get {return this._eIndexAction;}
219  }
220 
221  /// <summary>
222  /// Enumeration dictating the type of Analyzer to be applied to IndexDocuments in update scenarios
223  /// </summary>
225  {
226  get {return this._eAnalyzerType;}
227  }
228 
229  /// <summary>
230  /// The Analyzer object used in application of IndexDocument updates
231  /// </summary>
232  public Analyzer Analzyer
233  {
234  get {return CurrentIndex.GetAnalyzer(this._eAnalyzerType);}
235  }
236 
237  /// <summary>
238  /// Filesystem path to the master index
239  /// </summary>
240  public string LocalPath
241  {
242  get {return this._strLocalPath;}
243  }
244 
245  /// <summary>
246  /// String name representing the unique key for the given record in the index
247  /// </summary>
248  public string IdColumn
249  {
250  get {return this._strIdColumn;}
251  }
252 
253  /// <summary>
254  /// Minimum IdColumn value for a record in this index
255  /// </summary>
256  public int BottomId
257  {
258  get {return this._intBottomId;}
259  }
260 
261  /// <summary>
262  /// Maximum IdColumn value for a record in this index
263  /// </summary>
264  public int TopId
265  {
266  get {return this._intTopId;}
267  }
268 
269  /// <summary>
270  /// CurrentIndex object associated with this IndexSet. The CurrentIndex is used
271  /// in determining index settings and maintenance as well as managing physical file updates
272  /// for index updates.
273  /// </summary>
275  {
276  get {return this._oCurrentIndex;}
277  }
278 
279  /// <summary>
280  /// List of filesystem paths representing files for the master index
281  /// </summary>
282  public List<string> FileSystemDocuments
283  {
284  get { return this._alFileSystemDocuments; }
285  }
286 
287  /// <summary>
288  /// Pending updates to be applied to the master index
289  /// </summary>
290  public Hashtable IndexDocuments
291  {
292  get { return this._htIndexDocuments; }
293  }
294 
295  /// <summary>
296  /// Retrieves the DeleteIndexDocuments from IndexDocuments
297  /// </summary>
298  public Hashtable Documents
299  {
300  get
301  {
302  this._htDocuments.Clear();
303  foreach (DictionaryEntry de in this._htIndexDocuments)
304  {
305  IndexDocument iDoc = (IndexDocument)de.Value;
306  if (!(iDoc is DeleteIndexDocument))
307  this._htDocuments.Add(iDoc.Document, iDoc.GetAnalyzer());
308  }
309  return this._htDocuments;
310  }
311  }
312  #endregion
313 
314  #region Methods
315  /// <summary>
316  /// Retrieves a NameValueCollection of records to first be deleted from an index. Name/Value
317  /// pair combination consists of IdColumn and RecordId from each IndexDocument in IndexDocuments.
318  /// </summary>
319  /// <returns></returns>
320  public NameValueCollection GetDeletionCollection()
321  {
322  NameValueCollection nvc = new NameValueCollection(this._htDocuments.Count);
323  foreach(DictionaryEntry de in this._htIndexDocuments)
324  nvc.Add(this.IdColumn, ((IndexDocument)de.Value).RecordId.ToString());
325  return nvc;
326  }
327 
328  /// <summary>
329  /// Clears the contents of Documents and IndexDocuments
330  /// </summary>
331  public void Reset()
332  {
333  this._htIndexDocuments.Clear();
334  this._htDocuments.Clear();
335  }
336 
337  /// <summary>
338  /// Executes a Lucene.Net optimization against the referenced index.
339  /// </summary>
340  public void Optimize()
341  {
342  if (IndexReader.IndexExists(this._strLocalPath))
343  {
344  IndexWriter idxWriter = new IndexWriter(this._strLocalPath, this.Analzyer, false);
345  idxWriter.SetMergeFactor(2);
346  idxWriter.Optimize();
347  idxWriter.Close();
348  }
349  }
350 
351  /// <summary>
352  /// Indicates if a given recordId exists within the configuration
353  /// definition of TopId and BottomId.
354  /// </summary>
355  /// <param name="recordId"></param>
356  /// <returns></returns>
357  public bool ContainsId(int recordId)
358  {
359  return (this._intTopId >= recordId && this._intBottomId <= recordId);
360  }
361  #endregion
362  }
363 }