Section navigation

Added

  • LuceneNet TF-IDF similarity benchmark for comparing classic vector-space scoring against LeanCorpus (bfe0461dc)
  • Similarity benchmarks now compare LeanCorpus BM25 term and Boolean queries with Lucene.NET (c42d2cf40)
  • Linux kernel e2e cache telemetry, before-and-after measurements, ADR011, and concurrency coverage (14c971ccf)
  • Lazy segment readers with a bounded 256-entry cache for lower open-time memory (14c971ccf)
  • A Linux kernel code-search example now reproduces and measures highly segmented index startup costs (295194537)
  • DwptFlushSnapshot captures immutable DWPT state via collection swap so the DWPT can index new documents while the snapshot flushes independently (a14c71a80)
  • SnapshotFlushSource implements IFlushSource over a snapshot so FlushCore and the postings write path read from owned copies (a14c71a80)
  • FlushPendingState tracks in-flight detached flushes for MaxConcurrentFlushes > 1 (a14c71a80)
  • SegmentFlusher.FlushFromSnapshot new entry point for snapshot-based flush I/O (a14c71a80)
  • IFlushSource.CopySortedPostingsUtf8 returns (byte[] TermUtf8, PostingAccumulator Acc)[] so flush sources produce term bytes directly from BytesRefHash (a14c71a80)
  • TermDictionaryWriter.BuildFstUtf8 accepts pre-sorted (byte[], long)[] to eliminate the decode-to-string-then-re-encode round-trip in dictionary construction (a14c71a80)
  • TermDictionaryReader.TryGetPostingsOffset(ReadOnlySpan\byte>) byte-native FST lookup for the delete hot path (a14c71a80)
  • DeleteTerm record struct with field ordinal, UTF-8 term bytes, and pre-encoded qualified-term prefix for compact delete storage (a14c71a80)
  • QueueDelete with deduplication on IndexWriter so hard deletes always win over soft deletes for the same field and term (a14c71a80)
  • ByteBlockPool and IntBlockPool segment-lifetime allocators in Codecs/Postings/ with bulk Reset (a14c71a80)
  • 6 integration tests for detached flush correctness covering concurrent flush and commit, snapshot consistency, UpdateDocument during Flush, Rollback, and Dispose (a14c71a80)
  • Architecture tests now guard namespace, dependency, storage and structural boundaries (49916e9b1)
  • HasBlockMetadata to PostingsEnum for exception-free WAND capability checks (f3305a51a)
  • Five integration tests to reproduce WAND crashes caused by absent terms in specific segments (f3305a51a)
  • Add WAND searcher to MoreLikeThisBenchmarks to directly compare WAND vs. scalar performance (f3305a51a)
  • Add MoreLikeThisSingleSegmentBenchmarks to safely isolate WAND segment-topology effects (f3305a51a)

Changed

  • Hot scoring loops now get document ID and term frequency in a single PostingsEnum call instead of two separate property accesses, cutting per-hit overhead in half (bfe0461dc)
  • Collection frequency lookups are now cached per IndexSearcher instance, avoiding repeated cross-segment computation for the same term (bfe0461dc)
  • Search benchmarks now measure cache misses, fair sorting, explicit parallel opt-in, and scalar single-segment MLT (e3f1d25a7)
  • Benchmark runs now reuse standard search indexes and avoid duplicate jobs, cutting repeated setup and build time (c42d2cf40)
  • Parallel, SearcherManager, query-cache and segment-reader cache results are now easier to compare (c42d2cf40)
  • Heavy index data now loads on demand, with safe shared file lifetimes across directory instances (14c971ccf)
  • DwptManager.AddDocument threshold flush path captures snapshot under lock(dwpt), does I/O outside _writeLock, then briefly locks to publish (a14c71a80)
  • DwptManager.FlushDwptPool drains pending flushes first then flushes remaining DWPTs via FlushFromSnapshot (a14c71a80)
  • CommitCore and PrepareCommit call WaitForPendingFlushes before FlushDwptPool (a14c71a80)
  • UpdateDocument and UpdateDocuments call WaitForPendingFlushes before applying deletes so pending threshold-flush segments are published first (a14c71a80)
  • SegmentFlusher.FlushCore sorts terms by UTF-8 byte order via SequenceCompareTo instead of string.CompareOrdinal (a14c71a80)
  • DeletionApplier.ApplyPendingDeletions now uses ApplyDeletesByOrdinal with byte-native FST lookup instead of string-qualified-term construction (a14c71a80)
  • _pendingDeletes changed from List<(string,string,bool)> to List<DeleteTerm> with field ordinal and UTF-8 term storage (a14c71a80)
  • DocumentsWriterPerThread collection fields changed from readonly to mutable so ResetAfterSnapshot can swap them with fresh instances (a14c71a80)
  • NextSegmentOrdinal assignment in threshold flush uses Interlocked.Increment since the path no longer holds _writeLock (a14c71a80)
  • Write to SlowQueryLog asynchronously via a bounded channel to prevent slow I/O blocking search threads (3632683e4)
  • Codecs no longer depend on Search or Index internals (49916e9b1)
  • File-system access is now encapsulated by the Store layer (49916e9b1)
  • PorterStemmer has moved to Rowles.LeanCorpus.Analysis.Stemmers (49916e9b1)
  • Optimise CodecFileHeader reads using bulk IndexInput.ReadBytes to reduce decoding overhead (9c77ff7a3)

Fixed

  • BlockJoin benchmark LuceneNet baseline now uses ScoreMode.None instead of Max, so both engines measure parent-document matching without child scoring (bfe0461dc)
  • Collapse and facet benchmarks now use proper Lucene.Net SortedDocValues and facet infrastructure instead of naive string deduplication, giving realistic comparison numbers (bfe0461dc)
  • Highlighter benchmarks now highlight a consistent 100 documents per operation instead of the entire corpus, removing a hidden scale factor from measurements (bfe0461dc)
  • Parallel search benchmarks now disable merging in both engines, preserving the intended segment layout rather than letting it drift during the benchmark run (bfe0461dc)
  • The Porter benchmark no longer includes temporary token-list and sink allocations (c42d2cf40)
  • The single-segment MLT benchmark now builds and verifies an actual single-segment index (c42d2cf40)
  • Warm searches now pin segment state once and reuse field data across scoring hot paths (c42d2cf40)
  • Active postings and vector queries now keep their reader state alive until disposal (14c971ccf)
  • Swallowed exceptions in deletion policies now emit OpenTelemetry ActivityEvents so cleanup failures are observable (72b59fe49)
  • PostingsEnum now prevents copied instances from returning pooled buffers twice and waits for active enum operations before returning buffers to their pools (8cef21a86)
  • Dispose drains and publishes pending detached flushes before releasing the write lock so no flush work is lost on shutdown (a14c71a80)
  • StoredFieldsReader now serialises concurrent document reads to prevent block cache corruption from multi-threaded stored-field access (ad7c40a35)
  • Replace ConditionalWeakTable with ConcurrentDictionary in SearcherManager to prevent SearcherRef and IndexSearcher leaks on refresh (96c550269)
  • Vector readers now preserve mapped-file lifetime and deferred deletion behaviour (49916e9b1)
  • Dispose QuantisedVectorReader in SegmentReader.Dispose to prevent memory-mapped file leaks (d6e96315b)
  • Wait for background refresh to exit in SearcherManager.Dispose to prevent shutdown ObjectDisposedExceptions (da60cdb49)
  • Cap NumericAggregator histogram buckets at 100k to prevent OOM errors on extreme ratios (f5db3e27d)
  • Fix ExecuteBooleanStreaming crash on absent MLT terms by correctly handling empty postings (f3305a51a)
  • Pass segment-local shouldCount explicitly in ExecuteShouldOnlyWand instead of relying on array capacity (f3305a51a)
  • Clamp estimatedGlobal to _totalDocCount in MLT extraction to prevent negative IDF (f3305a51a)
  • Fix empty queries in MLT benchmarks by explicitly setting FieldNames and adding a Debug.Assert (f3305a51a)