public IEnumerable <QueryWordMatch> Apply(IntermediateQueryResult left, IntermediateQueryResult right) { // TODO Verify this assumption - forcing RIGHT to contain more will cause a bigger dictionary to be built // Swap over the variables to ensure we're performing as few iterations as possible in the intersection // "left" and "right" have no special meaning when performing an intersection var rightDictionary = right.Matches.ToDictionary(i => i.ItemId); foreach (var leftMatch in left.Matches) { if (rightDictionary.TryGetValue(leftMatch.ItemId, out var rightMatch)) { // Exists in both yield return(new QueryWordMatch( leftMatch.ItemId, MergeFields(leftMatch, rightMatch))); rightDictionary.Remove(leftMatch.ItemId); } else { // Exists only in current yield return(new QueryWordMatch(leftMatch.ItemId, leftMatch.FieldMatches)); } } // Any items still remaining in nextDictionary exist only in the new results so can just be yielded foreach (var rightMatch in rightDictionary.Values) { yield return(new QueryWordMatch(rightMatch.ItemId, rightMatch.FieldMatches)); } }
/// <summary> /// Applies the union operation to the <see cref="IntermediateQueryResult"/> instances. /// </summary> public static IEnumerable <ScoredToken> Apply(IntermediateQueryResult left, IntermediateQueryResult right) { // Swap over the variables to ensure we're performing as few iterations as possible in the intersection // "left" and "right" have no special meaning when performing an intersection var rightDictionary = right.Matches.ToDictionary(i => i.ItemId); foreach (var leftMatch in left.Matches) { if (rightDictionary.TryGetValue(leftMatch.ItemId, out var rightMatch)) { // Exists in both yield return(new ScoredToken( leftMatch.ItemId, MergeFields(leftMatch, rightMatch).ToList())); rightDictionary.Remove(leftMatch.ItemId); } else { // Exists only in current yield return(leftMatch); } } // Any items still remaining in nextDictionary exist only in the new results so can just be yielded foreach (var rightMatch in rightDictionary.Values) { yield return(rightMatch); } }
public IEnumerable <QueryWordMatch> Apply(IntermediateQueryResult left, IntermediateQueryResult right, int leftTolerance, int rightTolerance) { // TODO Verify this assumption - forcing RIGHT to contain more will cause a bigger dictionary to be built // Swap over the variables to ensure we're performing as few iterations as possible in the intersection // "left" and "right" have no special meaning when performing an intersection SwapIf(left.Matches.Count > right.Matches.Count, ref left, ref right); var rightItems = right.Matches.ToDictionary(m => m.ItemId); foreach (var leftMatch in left.Matches) { if (rightItems.TryGetValue(leftMatch.ItemId, out var rightMatch)) { var positionalMatches = PositionallyMatchAndCombineWords( leftMatch.FieldMatches, rightMatch.FieldMatches, leftTolerance, rightTolerance); if (positionalMatches.Count > 0) { yield return(new QueryWordMatch(leftMatch.ItemId, positionalMatches)); } } } }
/// <summary> /// Applies the intersection logic. /// </summary> public static IEnumerable <ScoredToken> Apply(IntermediateQueryResult left, IntermediateQueryResult right) { // Swap over the variables to ensure we're performing as few iterations as possible in the intersection // "left" and "right" have no special meaning when performing an intersection var swapLeftAndRight = left.Matches.Count > right.Matches.Count; SwapIf(swapLeftAndRight, ref left, ref right); var rightItems = right.Matches.ToDictionary(m => m.ItemId); foreach (var leftMatch in left.Matches) { if (rightItems.TryGetValue(leftMatch.ItemId, out var rightMatch)) { var positionalMatches = EnumerateFieldMatches( (swapLeftAndRight ? rightMatch : leftMatch).FieldMatches, (swapLeftAndRight ? leftMatch : rightMatch).FieldMatches); if (positionalMatches.Count > 0) { yield return(new ScoredToken(leftMatch.ItemId, positionalMatches)); } } } }
/// <summary> /// Applies the intersection to the <see cref="IntermediateQueryResult"/> instances. /// </summary> public static IEnumerable <ScoredToken> Apply(IntermediateQueryResult left, IntermediateQueryResult right, int leftTolerance, int rightTolerance) { // Swap over the variables to ensure we're performing as few iterations as possible in the intersection // Also swap the tolerance values around, otherwise we reverse the tolerance directionality. var swapLeftAndRight = left.Matches.Count > right.Matches.Count; SwapIf(swapLeftAndRight, ref left, ref right); SwapIf(swapLeftAndRight, ref leftTolerance, ref rightTolerance); var rightItems = right.Matches.ToDictionary(m => m.ItemId); foreach (var leftMatch in left.Matches) { if (rightItems.TryGetValue(leftMatch.ItemId, out var rightMatch)) { var positionalMatches = PositionallyMatchAndCombineTokens( swapLeftAndRight, leftMatch.FieldMatches, rightMatch.FieldMatches, leftTolerance, rightTolerance); if (positionalMatches.Count > 0) { yield return(new ScoredToken(leftMatch.ItemId, positionalMatches)); } } } }
/// <summary> /// Applies the intersection to the two <see cref="IntermediateQueryResult"/>s. /// </summary> public static IEnumerable <ScoredToken> Apply(IntermediateQueryResult left, IntermediateQueryResult right) { // Swap over left and right to ensure we're performing as few iterations as possible in the intersection // The trade-off here is that we're building a larger dictionary SwapIf(left.Matches.Count > right.Matches.Count, ref left, ref right); var rightItems = right.Matches.ToDictionary(m => m.ItemId); foreach (var leftMatch in left.Matches) { if (rightItems.TryGetValue(leftMatch.ItemId, out var rightMatch)) { yield return(new ScoredToken( leftMatch.ItemId, MergeFields(leftMatch, rightMatch).ToList())); } } }
/// <summary> /// Union this and the specified instance - this is the equivalent of an OR statement. /// </summary> public IntermediateQueryResult Union(IntermediateQueryResult results) { return(new IntermediateQueryResult(UnionMerger.Apply(this, results))); }
/// <summary> /// Intersects this and the specified instance - this is the equivalent of an AND statement. /// </summary> public IntermediateQueryResult Intersect(IntermediateQueryResult results) { return(new IntermediateQueryResult(IntersectMerger.Apply(this, results))); }
/// <summary> /// Intersects this and the specified instance, but only when the positions of the matched tokens are within a given tolerance. Matching tokens are combined /// into <see cref="CompositeTokenMatchLocation"/> instances. /// </summary> public IntermediateQueryResult CompositePositionalIntersect(IntermediateQueryResult results, int leftTolerance, int rightTolerance) { return(new IntermediateQueryResult(CompositePositionalIntersectMerger.Apply(this, results, leftTolerance, rightTolerance))); }
/// <summary> /// Intersects this and the specified instance, but only when the positions of the matched words on the left are preceding the words on the right. /// </summary> public IntermediateQueryResult PrecedingIntersect(IntermediateQueryResult results) { return(new IntermediateQueryResult(PrecedingIntersectMerger.Instance.Apply(this, results))); }