/// <summary> /// Returns a single <seealso cref="Fields"/> instance for this /// reader, merging fields/terms/docs/positions on the /// fly. this method will return null if the reader /// has no postings. /// /// <p><b>NOTE</b>: this is a slow way to access postings. /// It's better to get the sub-readers and iterate through them /// yourself. /// </summary> public static Fields GetFields(IndexReader reader) { IList<AtomicReaderContext> leaves = reader.Leaves(); switch (leaves.Count) { case 0: // no fields return null; case 1: // already an atomic reader / reader with one leave return leaves[0].AtomicReader.Fields(); default: IList<Fields> fields = new List<Fields>(); IList<ReaderSlice> slices = new List<ReaderSlice>(); foreach (AtomicReaderContext ctx in leaves) { AtomicReader r = ctx.AtomicReader; Fields f = r.Fields(); if (f != null) { fields.Add(f); slices.Add(new ReaderSlice(ctx.DocBase, r.MaxDoc(), fields.Count - 1)); } } if (fields.Count == 0) { return null; } else if (fields.Count == 1) { return fields[0]; } else { return new MultiFields(fields.ToArray(/*Fields.EMPTY_ARRAY*/), slices.ToArray(/*ReaderSlice.EMPTY_ARRAY*/)); } } }
/// <summary> /// Expert: attempts to delete by document ID, as long as /// the provided reader is a near-real-time reader (from {@link /// DirectoryReader#open(IndexWriter,boolean)}). If the /// provided reader is an NRT reader obtained from this /// writer, and its segment has not been merged away, then /// the delete succeeds and this method returns true; else, it /// returns false the caller must then separately delete by /// Term or Query. /// /// <b>NOTE</b>: this method can only delete documents /// visible to the currently open NRT reader. If you need /// to delete documents indexed after opening the NRT /// reader you must use the other deleteDocument methods /// (e.g., <seealso cref="#deleteDocuments(Term)"/>). /// </summary> public virtual bool TryDeleteDocument(IndexReader readerIn, int docID) { lock (this) { AtomicReader reader; if (readerIn is AtomicReader) { // Reader is already atomic: use the incoming docID: reader = (AtomicReader)readerIn; } else { // Composite reader: lookup sub-reader and re-base docID: IList<AtomicReaderContext> leaves = readerIn.Leaves(); int subIndex = ReaderUtil.SubIndex(docID, leaves); reader = leaves[subIndex].AtomicReader; docID -= leaves[subIndex].DocBase; Debug.Assert(docID >= 0); Debug.Assert(docID < reader.MaxDoc()); } if (!(reader is SegmentReader)) { throw new System.ArgumentException("the reader must be a SegmentReader or composite reader containing only SegmentReaders"); } SegmentCommitInfo info = ((SegmentReader)reader).SegmentInfo; // TODO: this is a slow linear search, but, number of // segments should be contained unless something is // seriously wrong w/ the index, so it should be a minor // cost: if (segmentInfos.IndexOf(info) != -1) { ReadersAndUpdates rld = readerPool.Get(info, false); if (rld != null) { lock (BufferedUpdatesStream) { rld.InitWritableLiveDocs(); if (rld.Delete(docID)) { int fullDelCount = rld.Info.DelCount + rld.PendingDeleteCount; if (fullDelCount == rld.Info.Info.DocCount) { // If a merge has already registered for this // segment, we leave it in the readerPool; the // merge will skip merging it and will then drop // it once it's done: if (!mergingSegments.Contains(rld.Info)) { segmentInfos.Remove(rld.Info); readerPool.Drop(rld.Info); Checkpoint(); } } // Must bump changeCount so if no other changes // happened, we still commit this change: Changed(); } //System.out.println(" yes " + info.info.name + " " + docID); return true; } } else { //System.out.println(" no rld " + info.info.name + " " + docID); } } else { //System.out.println(" no seg " + info.info.name + " " + docID); } return false; } }
/// <summary> /// Call this to get the (merged) FieldInfos for a /// composite reader. /// <p> /// NOTE: the returned field numbers will likely not /// correspond to the actual field numbers in the underlying /// readers, and codec metadata (<seealso cref="FieldInfo#getAttribute(String)"/> /// will be unavailable. /// </summary> public static FieldInfos GetMergedFieldInfos(IndexReader reader) { FieldInfos.Builder builder = new FieldInfos.Builder(); foreach (AtomicReaderContext ctx in reader.Leaves()) { builder.Add(ctx.AtomicReader.FieldInfos); } return builder.Finish(); }
/// <summary> /// Returns a single <seealso cref="Bits"/> instance for this /// reader, merging live Documents on the /// fly. this method will return null if the reader /// has no deletions. /// /// <p><b>NOTE</b>: this is a very slow way to access live docs. /// For example, each Bits access will require a binary search. /// It's better to get the sub-readers and iterate through them /// yourself. /// </summary> public static Bits GetLiveDocs(IndexReader reader) { if (reader.HasDeletions()) { IList<AtomicReaderContext> leaves = reader.Leaves(); int size = leaves.Count; Debug.Assert(size > 0, "A reader with deletions must have at least one leave"); if (size == 1) { return leaves[0].AtomicReader.LiveDocs; } Bits[] liveDocs = new Bits[size]; int[] starts = new int[size + 1]; for (int i = 0; i < size; i++) { // record all liveDocs, even if they are null AtomicReaderContext ctx = leaves[i]; liveDocs[i] = ctx.AtomicReader.LiveDocs; starts[i] = ctx.DocBase; } starts[size] = reader.MaxDoc(); return new MultiBits(liveDocs, starts, true); } else { return null; } }