using System; using System.Collections.Generic; using System.Linq; using Lucene.Net.QueryParsers; using Lucene.Net.Search; using Portoa.Persistence; using VideoGameQuotes.Api.Persistence; using Directory = Lucene.Net.Store.Directory; namespace VideoGameQuotes.Api.Search.Lucene { /// /// implementation for entities based on Lucene.NET /// public class LuceneEntitySearcher : ISearcher where T : Entity { private readonly QueryParser queryParser; private readonly Directory indexDirectory; private readonly ISearchService searchService; public LuceneEntitySearcher(QueryParser queryParser, Directory indexDirectory, ISearchService searchService) { this.queryParser = queryParser; this.indexDirectory = indexDirectory; this.searchService = searchService; } public IEnumerable> Search(string searchString, int maxResults = 10) { if (string.IsNullOrWhiteSpace(searchString)) { return Enumerable.Empty>(); } if (maxResults < 0) { throw new ArgumentOutOfRangeException("maxResults", maxResults, "Maximum number of results must be greater than or equal to zero"); } if (maxResults == 0) { maxResults = int.MaxValue; } var query = queryParser.Parse(QueryParser.Escape(searchString)); var searcher = new IndexSearcher(indexDirectory, true); try { var docs = searcher .Search(query, maxResults) .scoreDocs; var quotes = searchService.FindByIds(docs.Select(doc => int.Parse(searcher.Doc(doc.doc).GetField("id").StringValue()))); return quotes.Zip(docs, (entity, doc) => new SearchResult { Entity = entity, Score = doc.score }).ToArray(); } finally { searcher.Close(); } } } }