cvsimport
[beagle.git] / beagled / Lucene.Net / Index / IndexReader.cs
blob0d9c91af53d63a16352fee2f61bb16cca524fdf8
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.
17 using System;
18 using Document = Lucene.Net.Documents.Document;
19 using Field = Lucene.Net.Documents.Field;
20 using Similarity = Lucene.Net.Search.Similarity;
21 using Directory = Lucene.Net.Store.Directory;
22 using FSDirectory = Lucene.Net.Store.FSDirectory;
23 using IndexInput = Lucene.Net.Store.IndexInput;
24 using Lock = Lucene.Net.Store.Lock;
26 namespace Lucene.Net.Index
29 /// <summary>IndexReader is an abstract class, providing an interface for accessing an
30 /// index. Search of an index is done entirely through this abstract interface,
31 /// so that any subclass which implements it is searchable.
32 /// <p> Concrete subclasses of IndexReader are usually constructed with a call to
33 /// one of the static <code>open()</code> methods, e.g. {@link #Open(String)}.
34 /// <p> For efficiency, in this API documents are often referred to via
35 /// <i>document numbers</i>, non-negative integers which each name a unique
36 /// document in the index. These document numbers are ephemeral--they may change
37 /// as documents are added to and deleted from an index. Clients should thus not
38 /// rely on a given document having the same number between sessions.
39 /// </summary>
40 /// <summary><p> An IndexReader can be opened on a directory for which an IndexWriter is
41 /// opened already, but it cannot be used to delete documents from the index then.
42 /// </summary>
43 /// <author> Doug Cutting
44 /// </author>
45 /// <version> $Id: IndexReader.cs,v 1.4 2006/10/02 17:08:52 joeshaw Exp $
46 /// </version>
47 public abstract class IndexReader
49 private class AnonymousClassWith : Lock.With
51 private void InitBlock(Lucene.Net.Store.Directory directory, bool closeDirectory)
53 this.directory = directory;
54 this.closeDirectory = closeDirectory;
56 private Lucene.Net.Store.Directory directory;
57 private bool closeDirectory;
58 internal AnonymousClassWith(Lucene.Net.Store.Directory directory, bool closeDirectory, Lucene.Net.Store.Lock Param1, long Param2):base(Param1, Param2)
60 InitBlock(directory, closeDirectory);
62 public override System.Object DoBody()
64 SegmentInfos infos = new SegmentInfos();
65 infos.Read(directory);
66 if (infos.Count == 1)
68 // index is optimized
69 return SegmentReader.Get(infos, infos.Info(0), closeDirectory);
71 IndexReader[] readers = new IndexReader[infos.Count];
72 for (int i = 0; i < infos.Count; i++)
73 readers[i] = SegmentReader.Get(infos.Info(i));
74 return new MultiReader(directory, infos, closeDirectory, readers);
77 private class AnonymousClassWith1 : Lock.With
79 private void InitBlock(IndexReader enclosingInstance)
81 this.enclosingInstance = enclosingInstance;
83 private IndexReader enclosingInstance;
84 public IndexReader Enclosing_Instance
86 get
88 return enclosingInstance;
92 internal AnonymousClassWith1(IndexReader enclosingInstance, Lucene.Net.Store.Lock Param1, long Param2) : base(Param1, Param2)
94 InitBlock(enclosingInstance);
96 public override System.Object DoBody()
98 Enclosing_Instance.DoCommit();
99 Enclosing_Instance.segmentInfos.Write(Enclosing_Instance.directory);
100 return null;
104 public sealed class FieldOption
106 private System.String option;
107 internal FieldOption()
110 internal FieldOption(System.String option)
112 this.option = option;
114 public override System.String ToString()
116 return this.option;
118 // all fields
119 public static readonly FieldOption ALL = new FieldOption("ALL");
120 // all indexed fields
121 public static readonly FieldOption INDEXED = new FieldOption("INDEXED");
122 // all fields which are not indexed
123 public static readonly FieldOption UNINDEXED = new FieldOption("UNINDEXED");
124 // all fields which are indexed with termvectors enables
125 public static readonly FieldOption INDEXED_WITH_TERMVECTOR = new FieldOption("INDEXED_WITH_TERMVECTOR");
126 // all fields which are indexed but don't have termvectors enabled
127 public static readonly FieldOption INDEXED_NO_TERMVECTOR = new FieldOption("INDEXED_NO_TERMVECTOR");
128 // all fields where termvectors are enabled. Please note that only standard termvector fields are returned
129 public static readonly FieldOption TERMVECTOR = new FieldOption("TERMVECTOR");
130 // all field with termvectors wiht positions enabled
131 public static readonly FieldOption TERMVECTOR_WITH_POSITION = new FieldOption("TERMVECTOR_WITH_POSITION");
132 // all fields where termvectors with offset position are set
133 public static readonly FieldOption TERMVECTOR_WITH_OFFSET = new FieldOption("TERMVECTOR_WITH_OFFSET");
134 // all fields where termvectors with offset and position values set
135 public static readonly FieldOption TERMVECTOR_WITH_POSITION_OFFSET = new FieldOption("TERMVECTOR_WITH_POSITION_OFFSET");
138 /// <summary> Constructor used if IndexReader is not owner of its directory.
139 /// This is used for IndexReaders that are used within other IndexReaders that take care or locking directories.
140 ///
141 /// </summary>
142 /// <param name="directory">Directory where IndexReader files reside.
143 /// </param>
144 protected internal IndexReader(Directory directory)
146 this.directory = directory;
149 /// <summary> Constructor used if IndexReader is owner of its directory.
150 /// If IndexReader is owner of its directory, it locks its directory in case of write operations.
151 ///
152 /// </summary>
153 /// <param name="directory">Directory where IndexReader files reside.
154 /// </param>
155 /// <param name="segmentInfos">Used for write-l
156 /// </param>
157 /// <param name="closeDirectory">
158 /// </param>
159 internal IndexReader(Directory directory, SegmentInfos segmentInfos, bool closeDirectory)
161 Init(directory, segmentInfos, closeDirectory, true);
164 internal virtual void Init(Directory directory, SegmentInfos segmentInfos, bool closeDirectory, bool directoryOwner)
166 this.directory = directory;
167 this.segmentInfos = segmentInfos;
168 this.directoryOwner = directoryOwner;
169 this.closeDirectory = closeDirectory;
172 private Directory directory;
173 private bool directoryOwner;
174 private bool closeDirectory;
176 private SegmentInfos segmentInfos;
177 private Lock writeLock;
178 private bool stale;
179 private bool hasChanges;
182 /// <summary>Returns an IndexReader reading the index in an FSDirectory in the named
183 /// path.
184 /// </summary>
185 public static IndexReader Open(System.String path)
187 return Open(FSDirectory.GetDirectory(path, false), true);
190 /// <summary>Returns an IndexReader reading the index in an FSDirectory in the named
191 /// path.
192 /// </summary>
193 public static IndexReader Open(System.IO.FileInfo path)
195 return Open(FSDirectory.GetDirectory(path, false), true);
198 /// <summary>Returns an IndexReader reading the index in the given Directory. </summary>
199 public static IndexReader Open(Directory directory)
201 return Open(directory, false);
204 private static IndexReader Open(Directory directory, bool closeDirectory)
206 lock (directory)
208 // in- & inter-process sync
209 return (IndexReader) new AnonymousClassWith(directory, closeDirectory, directory.MakeLock(IndexWriter.COMMIT_LOCK_NAME), IndexWriter.COMMIT_LOCK_TIMEOUT).Run();
213 /// <summary>Returns the directory this index resides in. </summary>
214 public virtual Directory Directory()
216 return directory;
219 /// <summary> Returns the time the index in the named directory was last modified.
220 /// Do not use this to check whether the reader is still up-to-date, use
221 /// {@link #IsCurrent()} instead.
222 /// </summary>
223 public static long LastModified(System.String directory)
225 return LastModified(new System.IO.FileInfo(directory));
228 /// <summary> Returns the time the index in the named directory was last modified.
229 /// Do not use this to check whether the reader is still up-to-date, use
230 /// {@link #IsCurrent()} instead.
231 /// </summary>
232 public static long LastModified(System.IO.FileInfo directory)
234 return FSDirectory.FileModified(directory, IndexFileNames.SEGMENTS);
237 /// <summary> Returns the time the index in the named directory was last modified.
238 /// Do not use this to check whether the reader is still up-to-date, use
239 /// {@link #IsCurrent()} instead.
240 /// </summary>
241 public static long LastModified(Directory directory)
243 return directory.FileModified(IndexFileNames.SEGMENTS);
246 /// <summary> Reads version number from segments files. The version number is
247 /// initialized with a timestamp and then increased by one for each change of
248 /// the index.
249 ///
250 /// </summary>
251 /// <param name="directory">where the index resides.
252 /// </param>
253 /// <returns> version number.
254 /// </returns>
255 /// <throws> IOException if segments file cannot be read </throws>
256 public static long GetCurrentVersion(System.String directory)
258 return GetCurrentVersion(new System.IO.FileInfo(directory));
261 /// <summary> Reads version number from segments files. The version number is
262 /// initialized with a timestamp and then increased by one for each change of
263 /// the index.
264 ///
265 /// </summary>
266 /// <param name="directory">where the index resides.
267 /// </param>
268 /// <returns> version number.
269 /// </returns>
270 /// <throws> IOException if segments file cannot be read </throws>
271 public static long GetCurrentVersion(System.IO.FileInfo directory)
273 Directory dir = FSDirectory.GetDirectory(directory, false);
274 long version = GetCurrentVersion(dir);
275 dir.Close();
276 return version;
279 /// <summary> Reads version number from segments files. The version number is
280 /// initialized with a timestamp and then increased by one for each change of
281 /// the index.
282 ///
283 /// </summary>
284 /// <param name="directory">where the index resides.
285 /// </param>
286 /// <returns> version number.
287 /// </returns>
288 /// <throws> IOException if segments file cannot be read. </throws>
289 public static long GetCurrentVersion(Directory directory)
291 return SegmentInfos.ReadCurrentVersion(directory);
294 /// <summary> Version number when this IndexReader was opened.</summary>
295 public virtual long GetVersion()
297 return segmentInfos.GetVersion();
300 /// <summary> Check whether this IndexReader still works on a current version of the index.
301 /// If this is not the case you will need to re-open the IndexReader to
302 /// make sure you see the latest changes made to the index.
303 ///
304 /// </summary>
305 /// <throws> IOException </throws>
306 public virtual bool IsCurrent()
308 if (SegmentInfos.ReadCurrentVersion(directory) != segmentInfos.GetVersion())
310 return false;
312 return true;
315 /// <summary> Return an array of term frequency vectors for the specified document.
316 /// The array contains a vector for each vectorized field in the document.
317 /// Each vector contains terms and frequencies for all terms in a given vectorized field.
318 /// If no such fields existed, the method returns null. The term vectors that are
319 /// returned my either be of type TermFreqVector or of type TermPositionsVector if
320 /// positions or offsets have been stored.
321 ///
322 /// </summary>
323 /// <param name="docNumber">document for which term frequency vectors are returned
324 /// </param>
325 /// <returns> array of term frequency vectors. May be null if no term vectors have been
326 /// stored for the specified document.
327 /// </returns>
328 /// <throws> IOException if index cannot be accessed </throws>
329 /// <seealso cref="Lucene.Net.document.Field.TermVector">
330 /// </seealso>
331 abstract public TermFreqVector[] GetTermFreqVectors(int docNumber);
334 /// <summary> Return a term frequency vector for the specified document and field. The
335 /// returned vector contains terms and frequencies for the terms in
336 /// the specified field of this document, if the field had the storeTermVector
337 /// flag set. If termvectors had been stored with positions or offsets, a
338 /// TermPositionsVector is returned.
339 ///
340 /// </summary>
341 /// <param name="docNumber">document for which the term frequency vector is returned
342 /// </param>
343 /// <param name="field">field for which the term frequency vector is returned.
344 /// </param>
345 /// <returns> term frequency vector May be null if field does not exist in the specified
346 /// document or term vector was not stored.
347 /// </returns>
348 /// <throws> IOException if index cannot be accessed </throws>
349 /// <seealso cref="Lucene.Net.document.Field.TermVector">
350 /// </seealso>
351 abstract public TermFreqVector GetTermFreqVector(int docNumber, System.String field);
353 /// <summary> Returns <code>true</code> if an index exists at the specified directory.
354 /// If the directory does not exist or if there is no index in it.
355 /// <code>false</code> is returned.
356 /// </summary>
357 /// <param name="directory">the directory to check for an index
358 /// </param>
359 /// <returns> <code>true</code> if an index exists; <code>false</code> otherwise
360 /// </returns>
361 public static bool IndexExists(System.String directory)
363 bool tmpBool;
364 if (System.IO.File.Exists((new System.IO.FileInfo(System.IO.Path.Combine(directory, IndexFileNames.SEGMENTS))).FullName))
365 tmpBool = true;
366 else
367 tmpBool = System.IO.Directory.Exists((new System.IO.FileInfo(System.IO.Path.Combine(directory, IndexFileNames.SEGMENTS))).FullName);
368 return tmpBool;
371 /// <summary> Returns <code>true</code> if an index exists at the specified directory.
372 /// If the directory does not exist or if there is no index in it.
373 /// </summary>
374 /// <param name="directory">the directory to check for an index
375 /// </param>
376 /// <returns> <code>true</code> if an index exists; <code>false</code> otherwise
377 /// </returns>
378 public static bool IndexExists(System.IO.FileInfo directory)
380 bool tmpBool;
381 if (System.IO.File.Exists((new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, IndexFileNames.SEGMENTS))).FullName))
382 tmpBool = true;
383 else
384 tmpBool = System.IO.Directory.Exists((new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, IndexFileNames.SEGMENTS))).FullName);
385 return tmpBool;
388 /// <summary> Returns <code>true</code> if an index exists at the specified directory.
389 /// If the directory does not exist or if there is no index in it.
390 /// </summary>
391 /// <param name="directory">the directory to check for an index
392 /// </param>
393 /// <returns> <code>true</code> if an index exists; <code>false</code> otherwise
394 /// </returns>
395 /// <throws> IOException if there is a problem with accessing the index </throws>
396 public static bool IndexExists(Directory directory)
398 return directory.FileExists(IndexFileNames.SEGMENTS);
401 /// <summary>Returns the number of documents in this index. </summary>
402 public abstract int NumDocs();
404 /// <summary>Returns one greater than the largest possible document number.
405 /// This may be used to, e.g., determine how big to allocate an array which
406 /// will have an element for every document number in an index.
407 /// </summary>
408 public abstract int MaxDoc();
410 /// <summary>Returns the stored fields of the <code>n</code><sup>th</sup>
411 /// <code>Document</code> in this index.
412 /// </summary>
413 public abstract Document Document(int n);
415 /// <summary>Returns true if document <i>n</i> has been deleted </summary>
416 public abstract bool IsDeleted(int n);
418 /// <summary>Returns true if any documents have been deleted </summary>
419 public abstract bool HasDeletions();
421 /// <summary>Returns true if there are norms stored for this field. </summary>
422 public virtual bool HasNorms(System.String field)
424 // backward compatible implementation.
425 // SegmentReader has an efficient implementation.
426 return Norms(field) != null;
429 /// <summary>Returns the byte-encoded normalization factor for the named field of
430 /// every document. This is used by the search code to score documents.
431 ///
432 /// </summary>
433 /// <seealso cref="Field.SetBoost(float)">
434 /// </seealso>
435 public abstract byte[] Norms(System.String field);
437 /// <summary>Reads the byte-encoded normalization factor for the named field of every
438 /// document. This is used by the search code to score documents.
439 ///
440 /// </summary>
441 /// <seealso cref="Field.SetBoost(float)">
442 /// </seealso>
443 public abstract void Norms(System.String field, byte[] bytes, int offset);
445 /// <summary>Expert: Resets the normalization factor for the named field of the named
446 /// document. The norm represents the product of the field's {@link
447 /// Field#SetBoost(float) boost} and its {@link Similarity#LengthNorm(String,
448 /// int) length normalization}. Thus, to preserve the length normalization
449 /// values when resetting this, one should base the new value upon the old.
450 ///
451 /// </summary>
452 /// <seealso cref="Norms(String)">
453 /// </seealso>
454 /// <seealso cref="Similarity.DecodeNorm(byte)">
455 /// </seealso>
456 public void SetNorm(int doc, System.String field, byte value_Renamed)
458 lock (this)
460 if (directoryOwner)
461 AquireWriteLock();
462 DoSetNorm(doc, field, value_Renamed);
463 hasChanges = true;
467 /// <summary>Implements setNorm in subclass.</summary>
468 protected internal abstract void DoSetNorm(int doc, System.String field, byte value_Renamed);
470 /// <summary>Expert: Resets the normalization factor for the named field of the named
471 /// document.
472 ///
473 /// </summary>
474 /// <seealso cref="Norms(String)">
475 /// </seealso>
476 /// <seealso cref="Similarity.DecodeNorm(byte)">
477 /// </seealso>
478 public virtual void SetNorm(int doc, System.String field, float value_Renamed)
480 SetNorm(doc, field, Similarity.EncodeNorm(value_Renamed));
483 /// <summary>Returns an enumeration of all the terms in the index.
484 /// The enumeration is ordered by Term.compareTo(). Each term
485 /// is greater than all that precede it in the enumeration.
486 /// </summary>
487 public abstract TermEnum Terms();
489 /// <summary>Returns an enumeration of all terms after a given term.
490 /// The enumeration is ordered by Term.compareTo(). Each term
491 /// is greater than all that precede it in the enumeration.
492 /// </summary>
493 public abstract TermEnum Terms(Term t);
495 /// <summary>Returns the number of documents containing the term <code>t</code>. </summary>
496 public abstract int DocFreq(Term t);
498 /// <summary>Returns an enumeration of all the documents which contain
499 /// <code>term</code>. For each document, the document number, the frequency of
500 /// the term in that document is also provided, for use in search scoring.
501 /// Thus, this method implements the mapping:
502 /// <p><ul>
503 /// Term &nbsp;&nbsp; =&gt; &nbsp;&nbsp; &lt;docNum, freq&gt;<sup>*</sup>
504 /// </ul>
505 /// <p>The enumeration is ordered by document number. Each document number
506 /// is greater than all that precede it in the enumeration.
507 /// </summary>
508 public virtual TermDocs TermDocs(Term term)
510 TermDocs termDocs = TermDocs();
511 termDocs.Seek(term);
512 return termDocs;
515 /// <summary>Returns an unpositioned {@link TermDocs} enumerator. </summary>
516 public abstract TermDocs TermDocs();
518 /// <summary>Returns an enumeration of all the documents which contain
519 /// <code>term</code>. For each document, in addition to the document number
520 /// and frequency of the term in that document, a list of all of the ordinal
521 /// positions of the term in the document is available. Thus, this method
522 /// implements the mapping:
523 ///
524 /// <p><ul>
525 /// Term &nbsp;&nbsp; =&gt; &nbsp;&nbsp; &lt;docNum, freq,
526 /// &lt;pos<sub>1</sub>, pos<sub>2</sub>, ...
527 /// pos<sub>freq-1</sub>&gt;
528 /// &gt;<sup>*</sup>
529 /// </ul>
530 /// <p> This positional information faciliates phrase and proximity searching.
531 /// <p>The enumeration is ordered by document number. Each document number is
532 /// greater than all that precede it in the enumeration.
533 /// </summary>
534 public virtual TermPositions TermPositions(Term term)
536 TermPositions termPositions = TermPositions();
537 termPositions.Seek(term);
538 return termPositions;
541 /// <summary>Returns an unpositioned {@link TermPositions} enumerator. </summary>
542 public abstract TermPositions TermPositions();
544 /// <summary> Tries to acquire the WriteLock on this directory.
545 /// this method is only valid if this IndexReader is directory owner.
546 ///
547 /// </summary>
548 /// <throws> IOException If WriteLock cannot be acquired. </throws>
549 private void AquireWriteLock()
551 if (stale)
552 throw new System.IO.IOException("IndexReader out of date and no longer valid for delete, undelete, or setNorm operations");
554 if (this.writeLock == null)
556 Lock writeLock = directory.MakeLock(IndexWriter.WRITE_LOCK_NAME);
557 if (!writeLock.Obtain(IndexWriter.WRITE_LOCK_TIMEOUT))
558 // obtain write lock
560 throw new System.IO.IOException("Index locked for write: " + writeLock);
562 this.writeLock = writeLock;
564 // we have to check whether index has changed since this reader was opened.
565 // if so, this reader is no longer valid for deletion
566 if (SegmentInfos.ReadCurrentVersion(directory) > segmentInfos.GetVersion())
568 stale = true;
569 this.writeLock.Release();
570 this.writeLock = null;
571 throw new System.IO.IOException("IndexReader out of date and no longer valid for delete, undelete, or setNorm operations");
576 /// <summary>Deletes the document numbered <code>docNum</code>. Once a document is
577 /// deleted it will not appear in TermDocs or TermPostitions enumerations.
578 /// Attempts to read its field with the {@link #document}
579 /// method will result in an error. The presence of this document may still be
580 /// reflected in the {@link #docFreq} statistic, though
581 /// this will be corrected eventually as the index is further modified.
582 ///
583 /// </summary>
584 /// <deprecated> Use {@link #DeleteDocument(int docNum)} instead.
585 /// </deprecated>
586 public void Delete(int docNum)
588 lock (this)
590 DeleteDocument(docNum);
594 /// <summary>Deletes the document numbered <code>docNum</code>. Once a document is
595 /// deleted it will not appear in TermDocs or TermPostitions enumerations.
596 /// Attempts to read its field with the {@link #document}
597 /// method will result in an error. The presence of this document may still be
598 /// reflected in the {@link #docFreq} statistic, though
599 /// this will be corrected eventually as the index is further modified.
600 /// </summary>
601 public void DeleteDocument(int docNum)
603 lock (this)
605 if (directoryOwner)
606 AquireWriteLock();
607 DoDelete(docNum);
608 hasChanges = true;
613 /// <summary>Implements deletion of the document numbered <code>docNum</code>.
614 /// Applications should call {@link #Delete(int)} or {@link #Delete(Term)}.
615 /// </summary>
616 protected internal abstract void DoDelete(int docNum);
618 /// <summary>Deletes all documents containing <code>term</code>.
619 /// This is useful if one uses a document field to hold a unique ID string for
620 /// the document. Then to delete such a document, one merely constructs a
621 /// term with the appropriate field and the unique ID string as its text and
622 /// passes it to this method.
623 /// See {@link #Delete(int)} for information about when this deletion will
624 /// become effective.
625 /// </summary>
626 /// <returns> the number of documents deleted
627 ///
628 /// </returns>
629 /// <deprecated> Use {@link #DeleteDocuments(Term term)} instead.
630 /// </deprecated>
631 public int Delete(Term term)
633 return DeleteDocuments(term);
636 /// <summary>Deletes all documents containing <code>term</code>.
637 /// This is useful if one uses a document field to hold a unique ID string for
638 /// the document. Then to delete such a document, one merely constructs a
639 /// term with the appropriate field and the unique ID string as its text and
640 /// passes it to this method.
641 /// See {@link #Delete(int)} for information about when this deletion will
642 /// become effective.
643 /// </summary>
644 /// <returns> the number of documents deleted
645 /// </returns>
646 public int DeleteDocuments(Term term)
648 TermDocs docs = TermDocs(term);
649 if (docs == null)
650 return 0;
651 int n = 0;
654 while (docs.Next())
656 DeleteDocument(docs.Doc());
657 n++;
660 finally
662 docs.Close();
664 return n;
667 /// <summary>Undeletes all documents currently marked as deleted in this index.</summary>
668 public void UndeleteAll()
670 lock (this)
672 if (directoryOwner)
673 AquireWriteLock();
674 DoUndeleteAll();
675 hasChanges = true;
679 /// <summary>Implements actual undeleteAll() in subclass. </summary>
680 protected internal abstract void DoUndeleteAll();
682 /// <summary> Commit changes resulting from delete, undeleteAll, or setNorm operations
683 ///
684 /// </summary>
685 /// <throws> IOException </throws>
686 protected internal void Commit()
688 lock (this)
690 if (hasChanges)
692 if (directoryOwner)
694 lock (directory)
696 // in- & inter-process sync
697 new AnonymousClassWith1(this, directory.MakeLock(IndexWriter.COMMIT_LOCK_NAME), IndexWriter.COMMIT_LOCK_TIMEOUT).Run();
699 if (writeLock != null)
701 writeLock.Release(); // release write lock
702 writeLock = null;
705 else
706 DoCommit();
708 hasChanges = false;
712 /// <summary>Implements commit. </summary>
713 protected internal abstract void DoCommit();
715 /// <summary> Closes files associated with this index.
716 /// Also saves any new deletions to disk.
717 /// No other methods should be called after this has been called.
718 /// </summary>
719 public void Close()
721 lock (this)
723 Commit();
724 DoClose();
725 if (closeDirectory)
726 directory.Close();
727 System.GC.SuppressFinalize(this);
731 /// <summary>Implements close. </summary>
732 protected internal abstract void DoClose();
734 /// <summary>Release the write lock, if needed. </summary>
735 ~IndexReader()
737 if (writeLock != null)
739 writeLock.Release(); // release write lock
740 writeLock = null;
744 /// <summary> Returns a list of all unique field names that exist in the index pointed
745 /// to by this IndexReader.
746 /// </summary>
747 /// <returns> Collection of Strings indicating the names of the fields
748 /// </returns>
749 /// <throws> IOException if there is a problem with accessing the index </throws>
750 /// <summary>
751 /// </summary>
752 /// <deprecated> Replaced by {@link #GetFieldNames(IndexReader.FieldOption)}
753 /// </deprecated>
754 public abstract System.Collections.ICollection GetFieldNames();
756 /// <summary> Returns a list of all unique field names that exist in the index pointed
757 /// to by this IndexReader. The boolean argument specifies whether the fields
758 /// returned are indexed or not.
759 /// </summary>
760 /// <param name="indexed"><code>true</code> if only indexed fields should be returned;
761 /// <code>false</code> if only unindexed fields should be returned.
762 /// </param>
763 /// <returns> Collection of Strings indicating the names of the fields
764 /// </returns>
765 /// <throws> IOException if there is a problem with accessing the index </throws>
766 /// <summary>
767 /// </summary>
768 /// <deprecated> Replaced by {@link #GetFieldNames(IndexReader.FieldOption)}
769 /// </deprecated>
770 public abstract System.Collections.ICollection GetFieldNames(bool indexed);
772 /// <summary> </summary>
773 /// <param name="storedTermVector">if true, returns only Indexed fields that have term vector info,
774 /// else only indexed fields without term vector info
775 /// </param>
776 /// <returns> Collection of Strings indicating the names of the fields
777 ///
778 /// </returns>
779 /// <deprecated> Replaced by {@link #GetFieldNames(IndexReader.FieldOption)}
780 /// </deprecated>
781 public virtual System.Collections.ICollection GetIndexedFieldNames(bool storedTermVector)
783 if (storedTermVector)
785 System.Collections.Hashtable fieldSet = new System.Collections.Hashtable();
786 foreach (object item in GetIndexedFieldNames(Field.TermVector.YES))
788 if (fieldSet.ContainsKey(item) == false)
790 fieldSet.Add(item, item);
793 foreach (object item in GetIndexedFieldNames(Field.TermVector.WITH_POSITIONS))
795 if (fieldSet.ContainsKey(item) == false)
797 fieldSet.Add(item, item);
800 foreach (object item in GetIndexedFieldNames(Field.TermVector.WITH_OFFSETS))
802 if (fieldSet.ContainsKey(item) == false)
804 fieldSet.Add(item, item);
807 foreach (object item in GetIndexedFieldNames(Field.TermVector.WITH_POSITIONS_OFFSETS))
809 if (fieldSet.ContainsKey(item) == false)
811 fieldSet.Add(item, item);
814 return fieldSet;
816 else
817 return GetIndexedFieldNames(Field.TermVector.NO);
820 /// <summary> Get a list of unique field names that exist in this index, are indexed, and have
821 /// the specified term vector information.
822 ///
823 /// </summary>
824 /// <param name="tvSpec">specifies which term vector information should be available for the fields
825 /// </param>
826 /// <returns> Collection of Strings indicating the names of the fields
827 ///
828 /// </returns>
829 /// <deprecated> Replaced by {@link #GetFieldNames(IndexReader.FieldOption)}
830 /// </deprecated>
831 public abstract System.Collections.ICollection GetIndexedFieldNames(Field.TermVector tvSpec);
833 /// <summary> Get a list of unique field names that exist in this index and have the specified
834 /// field option information.
835 /// </summary>
836 /// <param name="fldOption">specifies which field option should be available for the returned fields
837 /// </param>
838 /// <returns> Collection of Strings indicating the names of the fields.
839 /// </returns>
840 /// <seealso cref="IndexReader.FieldOption">
841 /// </seealso>
842 public abstract System.Collections.ICollection GetFieldNames(FieldOption fldOption);
844 /// <summary> Returns <code>true</code> iff the index in the named directory is
845 /// currently locked.
846 /// </summary>
847 /// <param name="directory">the directory to check for a lock
848 /// </param>
849 /// <throws> IOException if there is a problem with accessing the index </throws>
850 public static bool IsLocked(Directory directory)
852 return directory.MakeLock(IndexWriter.WRITE_LOCK_NAME).IsLocked() || directory.MakeLock(IndexWriter.COMMIT_LOCK_NAME).IsLocked();
855 /// <summary> Returns <code>true</code> iff the index in the named directory is
856 /// currently locked.
857 /// </summary>
858 /// <param name="directory">the directory to check for a lock
859 /// </param>
860 /// <throws> IOException if there is a problem with accessing the index </throws>
861 public static bool IsLocked(System.String directory)
863 Directory dir = FSDirectory.GetDirectory(directory, false);
864 bool result = IsLocked(dir);
865 dir.Close();
866 return result;
869 /// <summary> Forcibly unlocks the index in the named directory.
870 /// <P>
871 /// Caution: this should only be used by failure recovery code,
872 /// when it is known that no other process nor thread is in fact
873 /// currently accessing this index.
874 /// </summary>
875 public static void Unlock(Directory directory)
877 directory.MakeLock(IndexWriter.WRITE_LOCK_NAME).Release();
878 directory.MakeLock(IndexWriter.COMMIT_LOCK_NAME).Release();
881 /// <summary> Prints the filename and size of each file within a given compound file.
882 /// Add the -extract flag to extract files to the current working directory.
883 /// In order to make the extracted version of the index work, you have to copy
884 /// the segments file from the compound index into the directory where the extracted files are stored.
885 /// </summary>
886 /// <param name="args">Usage: Lucene.Net.index.IndexReader [-extract] &lt;cfsfile&gt;
887 /// </param>
888 [STAThread]
889 public static void Main(System.String[] args)
891 System.String filename = null;
892 bool extract = false;
894 for (int i = 0; i < args.Length; ++i)
896 if (args[i].Equals("-extract"))
898 extract = true;
900 else if (filename == null)
902 filename = args[i];
906 if (filename == null)
908 System.Console.Out.WriteLine("Usage: Lucene.Net.index.IndexReader [-extract] <cfsfile>");
909 return ;
912 Directory dir = null;
913 CompoundFileReader cfr = null;
917 System.IO.FileInfo file = new System.IO.FileInfo(filename);
918 System.String dirname = new System.IO.FileInfo(file.FullName).DirectoryName;
919 filename = file.Name;
920 dir = FSDirectory.GetDirectory(dirname, false);
921 cfr = new CompoundFileReader(dir, filename);
923 System.String[] files = cfr.List();
924 System.Array.Sort(files); // sort the array of filename so that the output is more readable
926 for (int i = 0; i < files.Length; ++i)
928 long len = cfr.FileLength(files[i]);
930 if (extract)
932 System.Console.Out.WriteLine("extract " + files[i] + " with " + len + " bytes to local directory...");
933 IndexInput ii = cfr.OpenInput(files[i]);
935 System.IO.FileStream f = new System.IO.FileStream(files[i], System.IO.FileMode.Create);
937 // read and write with a small buffer, which is more effectiv than reading byte by byte
938 byte[] buffer = new byte[1024];
939 int chunk = buffer.Length;
940 while (len > 0)
942 int bufLen = (int) System.Math.Min(chunk, len);
943 ii.ReadBytes(buffer, 0, bufLen);
945 byte[] byteArray = new byte[buffer.Length];
946 for (int index=0; index < buffer.Length; index++)
947 byteArray[index] = (byte) buffer[index];
949 f.Write(byteArray, 0, bufLen);
951 len -= bufLen;
954 f.Close();
955 ii.Close();
957 else
958 System.Console.Out.WriteLine(files[i] + ": " + len + " bytes");
961 catch (System.IO.IOException ioe)
963 System.Console.Error.WriteLine(ioe.StackTrace);
965 finally
969 if (dir != null)
970 dir.Close();
971 if (cfr != null)
972 cfr.Close();
974 catch (System.IO.IOException ioe)
976 System.Console.Error.WriteLine(ioe.StackTrace);