-
-
Notifications
You must be signed in to change notification settings - Fork 129
Description
Bug Description
SearchContext.SearchableFields and TaxonomySearchContext.SearchableFields cache their result after the first read. If the property is accessed before any documents have been indexed (e.g., during application startup when ExamineMultiFieldQueryParser is constructed via CreateQuery()), an empty array is cached permanently for the lifetime of that SearchContext instance.
After documents are indexed and the NRT reader is refreshed, IsSearcherCurrent() returns true (the refreshed reader IS current), so GetSearchContext() reuses the existing SearchContext with its stale empty _searchableFields. This causes ManagedQuery / Search(string) to generate queries with zero fields, returning zero results even though documents exist in the index.
Impact
ISearcher.Search(string)returns empty results despite documents being indexedManagedQuery()without explicit fields generates an empty query- Any code path that calls
CreateQuery()before the index is populated poisons the cache CreateQuery().All().SelectField().Execute()is not affected (doesn't useSearchableFields)
Affected Versions
- support/3.x branch (
SearchContext.cs) - v4 / main (
SearchContext.csandTaxonomySearchContext.cs)
Reproduction
- Create an application that registers Examine indexes
- During startup, before any documents are indexed, any code that calls
CreateQuery()triggersExamineMultiFieldQueryParserconstruction which accessesSearchableFields - Index documents (async/timer-based commit)
- Call
index.Searcher.Search("some text")— returns 0 results - Call
index.Searcher.CreateQuery().All().Execute()— returns documents correctly (proving they're in the index)
Root Cause
In SearchContext.SearchableFields:
if (_searchableFields == null)
{
var searcher = _searcherManager.Acquire();
// ... reads fields from reader ...
_searchableFields = fields.Where(...).ToArray(); // caches empty [] if index is empty
}
return _searchableFields; // returns cached [] foreverThe GetSearchContext() check uses IsSearcherCurrent() / _searcherManager.IsSearcherCurrent() which returns true after NRT refresh (the new reader IS current), so the SearchContext is never recreated.
Fix
Only cache _searchableFields when the result is non-empty. An empty index has nothing to search anyway, and re-reading on each call has negligible cost:
var filtered = fields.Where(...).ToArray();
if (filtered.Length > 0)
{
_searchableFields = filtered;
}
return filtered;Applied to both SearchContext and TaxonomySearchContext.