I'm using Lucene.net 3.0.3.0(the latest version right now). I would like to know if using a single instance of IndexWriter and IndexSearcher is a good choice in production environment(considering thread safety). I read in the documentation that creating new objects of these instances is an expensive operation and internally lucene handles concurrent requests pretty well.
This is a question to the people who have used lucene.net in production environment; please let me know if this will work out!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lucene.Net.Search;
using Lucene.Net.Store;
using System.IO;
using Directory = Lucene.Net.Store.Directory;
using Version = Lucene.Net.Util.Version;
using Lucene.Net.Index;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Analysis;
namespace MXLuceneConsoleApp
{
/// <summary>
/// This helper class applies a singleton pattern to create Searcher and Writer objects as it's recommended to create them only once.
/// Also the searcher gets reinitialized, if any write happens.
/// </summary>
public class MXLuceneIndexHelper
{
private static IndexSearcher _searcher;
private static Directory _directory;
private static Lazy<IndexWriter> _writer = new Lazy<IndexWriter>(() => new IndexWriter(_directory, new StandardAnalyzer(Version.LUCENE_30), IndexWriter.MaxFieldLength.UNLIMITED));
//this private constructor makes it a singleton now.
private MXLuceneIndexHelper() { }
//Static constructor, opening the directory once for all.
static MXLuceneIndexHelper()
{
_directory = FSDirectory.Open(new DirectoryInfo(Environment.CurrentDirectory + "\\LuceneIndexDir"));
}
public static IndexSearcher IndexSearcher
{
get
{
if (_searcher == null)
{
InitializeSearcher();
}
else if (!_searcher.IndexReader.IsCurrent())
{
//_searcher.IndexReader.Reopen();
//refreshing the underlying Reader above doesn't do the trick, so I'm reinitializing the Searcher.
_searcher.Dispose();
InitializeSearcher();
}
return _searcher;
}
}
public static IndexWriter IndexWriter
{
get
{
//_writer.SetRAMBufferSizeMB(30.0);
return _writer.Value;
}
}
private static void InitializeSearcher()
{
_searcher = new IndexSearcher(_directory, false);
}
}//End of class
}
My understanding is that there should only ever be 1 instance of IndexWriter per index. There is built in locking that is enabled in Lucene by default to ensure this condition. As far as a singleton pattern, I think you should look at the new Lazy class in .NET 4. It handles all the locking and null checking for free.
As for IndexSearcher, you are free to have as many instances as you want. However, I think there are performance gains if you reuse the existing searcher. I can tell from your code that you know that reopening an existing searcher is much cheaper than creating a new one. Also there is built in caching in the searcher that is initilaized when you do the first search. You can also implement an IndexReaderWarmer to control when the searcher is warmed (like before the first search).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With