Extend ISearchBuilder to support grouping clauses (#7850)

Fixes #5764
This commit is contained in:
Ryan Wawrzaszek
2017-09-21 15:37:57 -04:00
committed by Sébastien Ros
parent 7a734ec8bc
commit 521087d489
4 changed files with 88 additions and 0 deletions

View File

@@ -749,5 +749,73 @@ namespace Orchard.Tests.Modules.Indexing {
Assert.That(SearchBuilder.WithinRange("number", null, 123.456, true, false).Count(), Is.EqualTo(0));
Assert.That(SearchBuilder.WithinRange("integer", null, 123, true, false).Count(), Is.EqualTo(0));
}
[Test]
public void ShouldAllowGroupedClauses() {
_provider.CreateIndex("default");
_provider.Store("default", _provider.New(1).Add("body", "michael is in the kitchen").Analyze());
_provider.Store("default", _provider.New(2).Add("body", "michael has a cousin named michel").Analyze());
_provider.Store("default", _provider.New(3).Add("body", "speak inside the mic").Analyze());
_provider.Store("default", _provider.New(4).Add("body", "a dog is pursuing a cat").Analyze());
_provider.Store("default", _provider.New(5).Add("body", "michael speaks to elephants").Analyze());
var michael = SearchBuilder.WithField("body", "michael").GetBits();
var cousinKitchenOrCat = SearchBuilder.WithField("body", "cousin").WithField("body", "kitchen").WithField("body", "cat").GetBits();
Assert.That(michael.Count(), Is.EqualTo(3));
Assert.That(cousinKitchenOrCat.Count(), Is.EqualTo(3));
// Contains "michael" AND ("cousin" OR "kitchen" OR "cat")
var michaelAndCousinKitchenOrcat = SearchBuilder
.WithField("body", "michael").Mandatory()
.WithGroup(groupSearchBuilder => groupSearchBuilder
.WithField("body", "kitchen")
.WithField("body", "cousin")
.WithField("body", "cat")).Mandatory().GetBits();
Assert.That(michaelAndCousinKitchenOrcat.Count(), Is.EqualTo(2));
Assert.That(michael.And(cousinKitchenOrCat).Count(), Is.EqualTo(2));
}
[Test]
public void ShouldAllowNestedGroupedClauses()
{
_provider.CreateIndex("default");
_provider.Store("default", _provider.New(1).Add("body", "michael is in the kitchen with his cousin").Analyze());
_provider.Store("default", _provider.New(2).Add("body", "michael has a cousin named michel").Analyze());
_provider.Store("default", _provider.New(3).Add("body", "speak inside the mic").Analyze());
_provider.Store("default", _provider.New(4).Add("body", "a dog is pursuing a cat").Analyze());
_provider.Store("default", _provider.New(5).Add("body", "michael speaks to elephants").Analyze());
var michael = SearchBuilder.WithField("body", "michael").GetBits();
var elephant = SearchBuilder.WithField("body", "elephant").GetBits();
var cousinAndKitchen = SearchBuilder
.WithField("body", "cousin").Mandatory()
.WithField("body", "kitchen").Mandatory().GetBits();
// Contains "elephant" OR ("cousin" AND "kitchen")
var elephantOrCousinAndKitchen = SearchBuilder
.WithField("body", "elephant")
.WithGroup(nestedSearchBuilder => nestedSearchBuilder
.WithField("body", "cousin").Mandatory()
.WithField("body", "kitchen").Mandatory()
).GetBits();
// Contains "michael" AND ("elephant" OR ("cousin" AND "kitchen"))
var michaelAndElephantOrCousinAndKitchen = SearchBuilder
.WithField("body", "michael").Mandatory()
.WithGroup(groupSearchBuilder => groupSearchBuilder
.WithField("body", "elephant")
.WithGroup(nestedSearchBuilder => nestedSearchBuilder
.WithField("body", "cousin").Mandatory()
.WithField("body", "kitchen").Mandatory())
).Mandatory().GetBits();
Assert.That(michael.Count(), Is.EqualTo(3));
Assert.That(elephant.Count(), Is.EqualTo(1));
Assert.That(cousinAndKitchen.Count(), Is.EqualTo(1));
Assert.That(elephantOrCousinAndKitchen.Count(), Is.EqualTo(2));
Assert.That(michaelAndElephantOrCousinAndKitchen.Count(), Is.EqualTo(2));
}
}
}

View File

@@ -22,6 +22,7 @@ namespace Lucene.Services {
private readonly Directory _directory;
private string _indexName;
private Analyzer _analyzer;
private ILuceneAnalyzerProvider _analyzerProvider;
private readonly List<BooleanClause> _clauses;
private readonly List<BooleanClause> _filters;
@@ -47,8 +48,10 @@ namespace Lucene.Services {
string indexName) {
_directory = directory;
_indexName = indexName;
_analyzerProvider = analyzerProvider;
_analyzer = analyzerProvider.GetAnalyzer(_indexName);
Logger = NullLogger.Instance;
_count = MaxResults;
@@ -87,6 +90,18 @@ namespace Lucene.Services {
return this;
}
public ISearchBuilder WithGroup(Action<ISearchBuilder> grouping)
{
CreatePendingClause();
// a group is essentially a SearchBuilder
var groupSearchBuilder = new LuceneSearchBuilder(null, _analyzerProvider, _indexName);
grouping(groupSearchBuilder);
_query = groupSearchBuilder.CreateQuery();
return this;
}
public ISearchBuilder WithField(string field, int value) {
CreatePendingClause();
_query = NumericRangeQuery.NewIntRange(field, value, value, true, true);

View File

@@ -6,6 +6,7 @@ namespace Orchard.Indexing {
ISearchBuilder Parse(string defaultField, string query, bool escape = true);
ISearchBuilder Parse(string[] defaultFields, string query, bool escape = true);
ISearchBuilder WithGroup(Action<ISearchBuilder> groupSearchBuilder);
ISearchBuilder WithField(string field, bool value);
ISearchBuilder WithField(string field, DateTime value);
ISearchBuilder WithField(string field, string value);

View File

@@ -12,6 +12,10 @@ namespace Orchard.Indexing {
return this;
}
public ISearchBuilder WithGroup(Action<ISearchBuilder> groupSearchBuilder) {
return this;
}
public ISearchBuilder WithField(string field, bool value) {
return this;
}