Skip to content

Commit

Permalink
Efficient SkipMatches property on LookResult
Browse files Browse the repository at this point in the history
  • Loading branch information
Hendy committed Feb 20, 2019
1 parent f119be1 commit c81e5dd
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 68 deletions.
8 changes: 3 additions & 5 deletions src/Our.Umbraco.Look.BackOffice/Services/QueryService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,9 @@ internal static MatchesResult GetMatches(string searcherName, string sort, int s

matchesResult.TotalItemCount = lookResult.TotalItemCount;
matchesResult.Matches = lookResult
.Matches
.Skip(skip)
.SkipMatches(skip)
.Take(take)
.Select(x => (MatchesResult.Match)x)
.Select(x => (MatchesResult.Match)x) // convert match to model for serialization
.ToArray();

return matchesResult;
Expand Down Expand Up @@ -110,8 +109,7 @@ internal static MatchesResult GetTagMatches(string searcherName, string tagGroup

matchesResult.TotalItemCount = lookResult.TotalItemCount;
matchesResult.Matches = lookResult
.Matches
.Skip(skip)
.SkipMatches(skip)
.Take(take)
.Select(x => (MatchesResult.Match)x)
.ToArray();
Expand Down
4 changes: 2 additions & 2 deletions src/Our.Umbraco.Look/LookQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ public class LookQuery
private LookQueryCompiled _compiled = null;

/// <summary>
/// Property to override the default RequestFields behaviour
/// Property to override the default RequestFields behaviour (initially set to default)
/// </summary>
public RequestFields? RequestFields { get; set; } = null;
public RequestFields RequestFields { get; set; } = LookService.GetRequestFields();

/// <summary>
/// (Optional) set a raw Lucene query
Expand Down
123 changes: 93 additions & 30 deletions src/Our.Umbraco.Look/LookResult.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Examine;
using Lucene.Net.Search;
using Our.Umbraco.Look.Services;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -11,73 +13,109 @@ namespace Our.Umbraco.Look
/// </summary>
public class LookResult : ISearchResults
{
private LookQuery _lookQuery;

private TopDocs _topDocs;

/// <summary>
/// Flag used to indicate that _lookQuery, and _topDocs are populated (and results expected)
/// </summary>
private bool _hasMatches = false;

/// <summary>
/// Expected total number of results in the enumerable
/// </summary>
public int TotalItemCount { get; }
public int TotalItemCount { get; } = 0;

/// <summary>
/// Get the results enumerable with the LookMatch objects
/// </summary>
public IEnumerable<LookMatch> Matches { get; }
public IEnumerable<LookMatch> Matches
{
get
{
if (this._hasMatches)
{
return LookService
.GetLookMatches(
this._lookQuery.SearcherName,
this._lookQuery.SearchingContext.IndexSearcher,
this._topDocs.ScoreDocs,
this._lookQuery.RequestFields,
this._lookQuery.Compiled.GetHighlight,
this._lookQuery.Compiled.GetDistance);
}

return Enumerable.Empty<LookMatch>();
}
}

/// <summary>
/// Always returned as an array (which may be empty)
/// </summary>
public Facet[] Facets { get; }
public Facet[] Facets { get; } = new Facet[] { };

/// <summary>
/// When true, indicates the Look Query was parsed, contained a query clause and was executed correctly
/// </summary>
public bool Success { get; }
public bool Success { get; private set; } = false;

/// <summary>
/// Constructor for populated result
/// Default constructor for empty or error result
/// </summary>
/// <param name="lookMatches"></param>
/// <param name="total"></param>
/// <param name="facets"></param>
internal LookResult(IEnumerable<LookMatch> lookMatches, int total, Facet[] facets)
{
this.Matches = lookMatches;
this.TotalItemCount = total;
this.Facets = facets ?? new Facet[] { };
this.Success = true;
private LookResult()
{
}

/// <summary>
/// Constructor for an empty (success) result
/// Constructor with results
/// </summary>
internal LookResult()
/// <param name="lookQuery"></param>
/// <param name="topDocs"></param>
/// <param name="facets"></param>
internal LookResult(LookQuery lookQuery, TopDocs topDocs, Facet[] facets)
{
this.Matches = Enumerable.Empty<LookMatch>();
this.TotalItemCount = 0;
this.Facets = new Facet[] { };
this._lookQuery = lookQuery;
this._topDocs = topDocs;
this._hasMatches = true; // this constructor is only called when there are matches
this.TotalItemCount = topDocs.TotalHits;
this.Facets = facets;
this.Success = true;
}

/// <summary>
/// Constructor for an empty (failed) result with message for debug logging
/// Use this Skip for performace (and then cast each result to a LookMatch)
/// This skip method, performs the skip on the Lucene results array before each is inflated into a LookMatch
/// </summary>
/// <param name="loggingMessage">Message to debug log</param>
internal LookResult(string loggingMessage)
/// <param name="skip"></param>
/// <returns></returns>
public IEnumerable<SearchResult> Skip(int skip)
{
this.Matches = Enumerable.Empty<LookMatch>();
this.TotalItemCount = 0;
this.Facets = new Facet[] { };
this.Success = false;
if (this._hasMatches && skip > 0)
{
var scoreDocs = this._topDocs.ScoreDocs.Skip(skip).ToArray();

return LookService
.GetLookMatches(
this._lookQuery.SearcherName,
this._lookQuery.SearchingContext.IndexSearcher,
scoreDocs,
this._lookQuery.RequestFields,
this._lookQuery.Compiled.GetHighlight,
this._lookQuery.Compiled.GetDistance);
}

LogHelper.Debug(typeof(LookResult), loggingMessage);
return this.Matches;
}

/// <summary>
///
/// Helper to call the efficient skip method, but to return each result as a LookMatch (rather then the underlying Examine.SearchResult)
/// </summary>
/// <param name="skip"></param>
/// <returns></returns>
public IEnumerable<SearchResult> Skip(int skip)
public IEnumerable<LookMatch> SkipMatches(int skip)
{
return this.Matches.Skip(skip);
return this.Skip(skip).Select(x => (LookMatch)x);
}

/// <summary>
Expand All @@ -89,9 +127,34 @@ public IEnumerator<SearchResult> GetEnumerator()
return this.Matches.GetEnumerator();
}

/// <summary>
///
/// </summary>
/// <returns></returns>
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}

/// <summary>
/// Returns an empty (successful) LookResult
/// </summary>
/// <returns></returns>
internal static LookResult Empty()
{
return new LookResult() { Success = true };
}

/// <summary>
/// Return an empty (unsuccessful) LookResult, whilst logging error
/// </summary>
/// <param name="error"></param>
/// <returns></returns>
internal static LookResult Error(string logMessage)
{
LogHelper.Debug(typeof(LookResult), logMessage);

return new LookResult(); // { Success = false };
}
}
}
1 change: 1 addition & 0 deletions src/Our.Umbraco.Look/Our.Umbraco.Look.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@
<Compile Include="LookQuery.cs" />
<Compile Include="RequestFields.cs" />
<Compile Include="Models\SearchingContext.cs" />
<Compile Include="Services\LookService_GetRequestFields.cs" />
<Compile Include="SortOn.cs" />
<Compile Include="LookTag.cs" />
<Compile Include="TagFacetQuery.cs" />
Expand Down
16 changes: 5 additions & 11 deletions src/Our.Umbraco.Look/Services/LookService_GetLookMatches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ internal partial class LookService
/// <param name="getHighlight">Function used to get the highlight text for a given result text</param>
/// <param name="getDistance">Function used to calculate distance (if a location was supplied in the original query)</param>
/// <returns></returns>
private static IEnumerable<LookMatch> GetLookMatches(
internal static IEnumerable<LookMatch> GetLookMatches(
string searcherName,
IndexSearcher indexSearcher,
TopDocs topDocs,
ScoreDoc[] scoreDocs,
RequestFields requestFields,
Func<string, IHtmlString> getHighlight,
Func<int, double?> getDistance)
Expand Down Expand Up @@ -64,11 +64,7 @@ private static IEnumerable<LookMatch> GetLookMatches(

var getCultureInfo = new Func<string, CultureInfo>(x =>
{
if (int.TryParse(x, out int lcid))
{
return new CultureInfo(lcid);
}

if (int.TryParse(x, out int lcid)) { return new CultureInfo(lcid); }
return null;
});

Expand All @@ -84,7 +80,7 @@ private static IEnumerable<LookMatch> GetLookMatches(
return new LookTag[] { };
});

foreach (var scoreDoc in topDocs.ScoreDocs)
foreach (var scoreDoc in scoreDocs)
{
var docId = scoreDoc.doc;

Expand Down Expand Up @@ -139,9 +135,7 @@ private static IEnumerable<LookMatch> GetLookMatches(
{
// look fields only

// TODO: map fields


// TODO: map fields
}

yield return lookMatch;
Expand Down
14 changes: 14 additions & 0 deletions src/Our.Umbraco.Look/Services/LookService_GetRequestFields.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Our.Umbraco.Look.Services
{
internal partial class LookService
{
/// <summary>
/// Get the default request fields value
/// </summary>
/// <returns></returns>
internal static RequestFields GetRequestFields()
{
return LookService.Instance.RequestFields;
}
}
}
Loading

0 comments on commit c81e5dd

Please sign in to comment.