vgquotes/Src/VideoGameQuotes.Api/Search/Lucene/LuceneEntitySearcher.cs

50 lines
1.8 KiB
C#
Raw Normal View History

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 {
/// <summary>
/// <see cref="ISearcher{T}"/> implementation for entities based on <c>Lucene.NET</c>
/// </summary>
public class LuceneEntitySearcher<T> : ISearcher<T> where T : Entity<T, int> {
private readonly QueryParser queryParser;
private readonly Directory indexDirectory;
private readonly ISearchService<T> searchService;
public LuceneEntitySearcher(QueryParser queryParser, Directory indexDirectory, ISearchService<T> searchService) {
this.queryParser = queryParser;
this.indexDirectory = indexDirectory;
this.searchService = searchService;
}
public IEnumerable<SearchResult<T>> Search(string searchString, int maxResults = 10) {
if (string.IsNullOrWhiteSpace(searchString)) {
return Enumerable.Empty<SearchResult<T>>();
}
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<T> { Entity = entity, Score = doc.score }).ToArray();
} finally {
searcher.Close();
}
}
}
}