50 lines
1.8 KiB
C#
50 lines
1.8 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|
|
} |