blob: a9eb77620e25bb6919ace73a50355264750c560e [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
using Lucene.Net.Analysis;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.Queries;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Lucene.Net.Util;
using NUnit.Framework;
namespace Lucene.Net.Tests.Queries
{
public class BooleanFilterTest : LuceneTestCase
{
private Directory directory;
private AtomicReader reader;
[SetUp]
public override void SetUp()
{
base.SetUp();
directory = NewDirectory();
RandomIndexWriter writer = new RandomIndexWriter(
#if FEATURE_INSTANCE_TESTDATA_INITIALIZATION
this,
#endif
Random, directory, new MockAnalyzer(Random, MockTokenizer.WHITESPACE, false));
AddDoc(writer, @"admin guest", @"010", @"20040101", @"Y");
AddDoc(writer, @"guest", @"020", @"20040101", @"Y");
AddDoc(writer, @"guest", @"020", @"20050101", @"Y");
AddDoc(writer, @"admin", @"020", @"20050101", @"Maybe");
AddDoc(writer, @"admin guest", @"030", @"20050101", @"N");
reader = SlowCompositeReaderWrapper.Wrap(writer.GetReader());
writer.Dispose();
}
[TearDown]
public override void TearDown()
{
reader.Dispose();
directory.Dispose();
base.TearDown();
}
private void AddDoc(RandomIndexWriter writer, string accessRights, string price, string date, string inStock)
{
Document doc = new Document();
doc.Add(NewTextField(@"accessRights", accessRights, Field.Store.YES));
doc.Add(NewTextField(@"price", price, Field.Store.YES));
doc.Add(NewTextField(@"date", date, Field.Store.YES));
doc.Add(NewTextField(@"inStock", inStock, Field.Store.YES));
writer.AddDocument(doc);
}
private Filter GetRangeFilter(string field, string lowerPrice, string upperPrice)
{
Filter f = TermRangeFilter.NewStringRange(field, lowerPrice, upperPrice, true, true);
return f;
}
private Filter GetTermsFilter(string field, string text)
{
return new TermsFilter(new Term(field, text));
}
private Filter GetWrappedTermQuery(string field, string text)
{
return new QueryWrapperFilter(new TermQuery(new Term(field, text)));
}
private Filter GetEmptyFilter()
{
return new AnonymousFilter(this);
}
private sealed class AnonymousFilter : Filter
{
public AnonymousFilter(BooleanFilterTest parent)
{
this.parent = parent;
}
private readonly BooleanFilterTest parent;
public override DocIdSet GetDocIdSet(AtomicReaderContext context, IBits acceptDocs)
{
return new FixedBitSet(context.AtomicReader.MaxDoc);
}
}
private Filter GetNullDISFilter()
{
return new AnonymousFilter1(this);
}
private sealed class AnonymousFilter1 : Filter
{
public AnonymousFilter1(BooleanFilterTest parent)
{
this.parent = parent;
}
private readonly BooleanFilterTest parent;
public override DocIdSet GetDocIdSet(AtomicReaderContext context, IBits acceptDocs)
{
return null;
}
}
private Filter GetNullDISIFilter()
{
return new AnonymousFilter2(this);
}
private sealed class AnonymousDocIdSet : DocIdSet
{
public override DocIdSetIterator GetIterator()
{
return null;
}
public override bool IsCacheable => true;
}
private sealed class AnonymousFilter2 : Filter
{
public AnonymousFilter2(BooleanFilterTest parent)
{
this.parent = parent;
}
private readonly BooleanFilterTest parent;
public override DocIdSet GetDocIdSet(AtomicReaderContext context, IBits acceptDocs)
{
return new AnonymousDocIdSet();
}
}
private void TstFilterCard(string mes, int expected, Filter filt)
{
DocIdSet docIdSet = filt.GetDocIdSet(reader.AtomicContext, reader.LiveDocs);
int actual = 0;
if (docIdSet != null)
{
DocIdSetIterator disi = docIdSet.GetIterator();
while (disi.NextDoc() != DocIdSetIterator.NO_MORE_DOCS)
{
actual++;
}
}
assertEquals(mes, expected, actual);
}
[Test]
public void TestShould()
{
BooleanFilter booleanFilter = new BooleanFilter();
booleanFilter.Add(GetTermsFilter(@"price", @"030"), Occur.SHOULD);
TstFilterCard(@"Should retrieves only 1 doc", 1, booleanFilter);
booleanFilter = new BooleanFilter();
booleanFilter.Add(GetWrappedTermQuery(@"price", @"030"), Occur.SHOULD);
TstFilterCard(@"Should retrieves only 1 doc", 1, booleanFilter);
}
[Test]
public void TestShoulds()
{
BooleanFilter booleanFilter = new BooleanFilter();
booleanFilter.Add(GetRangeFilter(@"price", @"010", @"020"), Occur.SHOULD);
booleanFilter.Add(GetRangeFilter(@"price", @"020", @"030"), Occur.SHOULD);
TstFilterCard(@"Shoulds are Ored together", 5, booleanFilter);
}
[Test]
public void TestShouldsAndMustNot()
{
BooleanFilter booleanFilter = new BooleanFilter();
booleanFilter.Add(GetRangeFilter(@"price", @"010", @"020"), Occur.SHOULD);
booleanFilter.Add(GetRangeFilter(@"price", @"020", @"030"), Occur.SHOULD);
booleanFilter.Add(GetTermsFilter(@"inStock", @"N"), Occur.MUST_NOT);
TstFilterCard(@"Shoulds Ored but AndNot", 4, booleanFilter);
booleanFilter.Add(GetTermsFilter(@"inStock", @"Maybe"), Occur.MUST_NOT);
TstFilterCard(@"Shoulds Ored but AndNots", 3, booleanFilter);
booleanFilter = new BooleanFilter();
booleanFilter.Add(GetRangeFilter(@"price", @"010", @"020"), Occur.SHOULD);
booleanFilter.Add(GetRangeFilter(@"price", @"020", @"030"), Occur.SHOULD);
booleanFilter.Add(GetWrappedTermQuery(@"inStock", @"N"), Occur.MUST_NOT);
TstFilterCard(@"Shoulds Ored but AndNot", 4, booleanFilter);
booleanFilter.Add(GetWrappedTermQuery(@"inStock", @"Maybe"), Occur.MUST_NOT);
TstFilterCard(@"Shoulds Ored but AndNots", 3, booleanFilter);
}
[Test]
public void TestShouldsAndMust()
{
BooleanFilter booleanFilter = new BooleanFilter();
booleanFilter.Add(GetRangeFilter(@"price", @"010", @"020"), Occur.SHOULD);
booleanFilter.Add(GetRangeFilter(@"price", @"020", @"030"), Occur.SHOULD);
booleanFilter.Add(GetTermsFilter(@"accessRights", @"admin"), Occur.MUST);
TstFilterCard(@"Shoulds Ored but MUST", 3, booleanFilter);
booleanFilter = new BooleanFilter();
booleanFilter.Add(GetRangeFilter(@"price", @"010", @"020"), Occur.SHOULD);
booleanFilter.Add(GetRangeFilter(@"price", @"020", @"030"), Occur.SHOULD);
booleanFilter.Add(GetWrappedTermQuery(@"accessRights", @"admin"), Occur.MUST);
TstFilterCard(@"Shoulds Ored but MUST", 3, booleanFilter);
}
[Test]
public void TestShouldsAndMusts()
{
BooleanFilter booleanFilter = new BooleanFilter();
booleanFilter.Add(GetRangeFilter(@"price", @"010", @"020"), Occur.SHOULD);
booleanFilter.Add(GetRangeFilter(@"price", @"020", @"030"), Occur.SHOULD);
booleanFilter.Add(GetTermsFilter(@"accessRights", @"admin"), Occur.MUST);
booleanFilter.Add(GetRangeFilter(@"date", @"20040101", @"20041231"), Occur.MUST);
TstFilterCard(@"Shoulds Ored but MUSTs ANDED", 1, booleanFilter);
}
[Test]
public void TestShouldsAndMustsAndMustNot()
{
BooleanFilter booleanFilter = new BooleanFilter();
booleanFilter.Add(GetRangeFilter(@"price", @"030", @"040"), Occur.SHOULD);
booleanFilter.Add(GetTermsFilter(@"accessRights", @"admin"), Occur.MUST);
booleanFilter.Add(GetRangeFilter(@"date", @"20050101", @"20051231"), Occur.MUST);
booleanFilter.Add(GetTermsFilter(@"inStock", @"N"), Occur.MUST_NOT);
TstFilterCard(@"Shoulds Ored but MUSTs ANDED and MustNot", 0, booleanFilter);
booleanFilter = new BooleanFilter();
booleanFilter.Add(GetRangeFilter(@"price", @"030", @"040"), Occur.SHOULD);
booleanFilter.Add(GetWrappedTermQuery(@"accessRights", @"admin"), Occur.MUST);
booleanFilter.Add(GetRangeFilter(@"date", @"20050101", @"20051231"), Occur.MUST);
booleanFilter.Add(GetWrappedTermQuery(@"inStock", @"N"), Occur.MUST_NOT);
TstFilterCard(@"Shoulds Ored but MUSTs ANDED and MustNot", 0, booleanFilter);
}
[Test]
public void TestJustMust()
{
BooleanFilter booleanFilter = new BooleanFilter();
booleanFilter.Add(GetTermsFilter(@"accessRights", @"admin"), Occur.MUST);
TstFilterCard(@"MUST", 3, booleanFilter);
booleanFilter = new BooleanFilter();
booleanFilter.Add(GetWrappedTermQuery(@"accessRights", @"admin"), Occur.MUST);
TstFilterCard(@"MUST", 3, booleanFilter);
}
[Test]
public void TestJustMustNot()
{
BooleanFilter booleanFilter = new BooleanFilter();
booleanFilter.Add(GetTermsFilter(@"inStock", @"N"), Occur.MUST_NOT);
TstFilterCard(@"MUST_NOT", 4, booleanFilter);
booleanFilter = new BooleanFilter();
booleanFilter.Add(GetWrappedTermQuery(@"inStock", @"N"), Occur.MUST_NOT);
TstFilterCard(@"MUST_NOT", 4, booleanFilter);
}
[Test]
public void TestMustAndMustNot()
{
BooleanFilter booleanFilter = new BooleanFilter();
booleanFilter.Add(GetTermsFilter(@"inStock", @"N"), Occur.MUST);
booleanFilter.Add(GetTermsFilter(@"price", @"030"), Occur.MUST_NOT);
TstFilterCard(@"MUST_NOT wins over MUST for same docs", 0, booleanFilter);
booleanFilter = new BooleanFilter();
booleanFilter.Add(GetWrappedTermQuery(@"inStock", @"N"), Occur.MUST);
booleanFilter.Add(GetWrappedTermQuery(@"price", @"030"), Occur.MUST_NOT);
TstFilterCard(@"MUST_NOT wins over MUST for same docs", 0, booleanFilter);
}
[Test]
public void TestEmpty()
{
BooleanFilter booleanFilter = new BooleanFilter();
TstFilterCard(@"empty BooleanFilter returns no results", 0, booleanFilter);
}
[Test]
public void TestCombinedNullDocIdSets()
{
BooleanFilter booleanFilter = new BooleanFilter();
booleanFilter.Add(GetTermsFilter(@"price", @"030"), Occur.MUST);
booleanFilter.Add(GetNullDISFilter(), Occur.MUST);
TstFilterCard(@"A MUST filter that returns a null DIS should never return documents", 0, booleanFilter);
booleanFilter = new BooleanFilter();
booleanFilter.Add(GetTermsFilter(@"price", @"030"), Occur.MUST);
booleanFilter.Add(GetNullDISIFilter(), Occur.MUST);
TstFilterCard(@"A MUST filter that returns a null DISI should never return documents", 0, booleanFilter);
booleanFilter = new BooleanFilter();
booleanFilter.Add(GetTermsFilter(@"price", @"030"), Occur.SHOULD);
booleanFilter.Add(GetNullDISFilter(), Occur.SHOULD);
TstFilterCard(@"A SHOULD filter that returns a null DIS should be invisible", 1, booleanFilter);
booleanFilter = new BooleanFilter();
booleanFilter.Add(GetTermsFilter(@"price", @"030"), Occur.SHOULD);
booleanFilter.Add(GetNullDISIFilter(), Occur.SHOULD);
TstFilterCard(@"A SHOULD filter that returns a null DISI should be invisible", 1, booleanFilter);
booleanFilter = new BooleanFilter();
booleanFilter.Add(GetTermsFilter(@"price", @"030"), Occur.MUST);
booleanFilter.Add(GetNullDISFilter(), Occur.MUST_NOT);
TstFilterCard(@"A MUST_NOT filter that returns a null DIS should be invisible", 1, booleanFilter);
booleanFilter = new BooleanFilter();
booleanFilter.Add(GetTermsFilter(@"price", @"030"), Occur.MUST);
booleanFilter.Add(GetNullDISIFilter(), Occur.MUST_NOT);
TstFilterCard(@"A MUST_NOT filter that returns a null DISI should be invisible", 1, booleanFilter);
}
[Test]
public void TestJustNullDocIdSets()
{
BooleanFilter booleanFilter = new BooleanFilter();
booleanFilter.Add(GetNullDISFilter(), Occur.MUST);
TstFilterCard(@"A MUST filter that returns a null DIS should never return documents", 0, booleanFilter);
booleanFilter = new BooleanFilter();
booleanFilter.Add(GetNullDISIFilter(), Occur.MUST);
TstFilterCard(@"A MUST filter that returns a null DISI should never return documents", 0, booleanFilter);
booleanFilter = new BooleanFilter();
booleanFilter.Add(GetNullDISFilter(), Occur.SHOULD);
TstFilterCard(@"A single SHOULD filter that returns a null DIS should never return documents", 0, booleanFilter);
booleanFilter = new BooleanFilter();
booleanFilter.Add(GetNullDISIFilter(), Occur.SHOULD);
TstFilterCard(@"A single SHOULD filter that returns a null DISI should never return documents", 0, booleanFilter);
booleanFilter = new BooleanFilter();
booleanFilter.Add(GetNullDISFilter(), Occur.MUST_NOT);
TstFilterCard(@"A single MUST_NOT filter that returns a null DIS should be invisible", 5, booleanFilter);
booleanFilter = new BooleanFilter();
booleanFilter.Add(GetNullDISIFilter(), Occur.MUST_NOT);
TstFilterCard(@"A single MUST_NOT filter that returns a null DIS should be invisible", 5, booleanFilter);
}
[Test]
public void TestNonMatchingShouldsAndMusts()
{
BooleanFilter booleanFilter = new BooleanFilter();
booleanFilter.Add(GetEmptyFilter(), Occur.SHOULD);
booleanFilter.Add(GetTermsFilter(@"accessRights", @"admin"), Occur.MUST);
TstFilterCard(@">0 shoulds with no matches should return no docs", 0, booleanFilter);
booleanFilter = new BooleanFilter();
booleanFilter.Add(GetNullDISFilter(), Occur.SHOULD);
booleanFilter.Add(GetTermsFilter(@"accessRights", @"admin"), Occur.MUST);
TstFilterCard(@">0 shoulds with no matches should return no docs", 0, booleanFilter);
booleanFilter = new BooleanFilter();
booleanFilter.Add(GetNullDISIFilter(), Occur.SHOULD);
booleanFilter.Add(GetTermsFilter(@"accessRights", @"admin"), Occur.MUST);
TstFilterCard(@">0 shoulds with no matches should return no docs", 0, booleanFilter);
}
[Test]
public void TestToStringOfBooleanFilterContainingTermsFilter()
{
BooleanFilter booleanFilter = new BooleanFilter();
booleanFilter.Add(GetTermsFilter(@"inStock", @"N"), Occur.MUST);
booleanFilter.Add(GetTermsFilter(@"isFragile", @"Y"), Occur.MUST);
assertEquals(@"BooleanFilter(+inStock:N +isFragile:Y)", booleanFilter.ToString());
}
[Test]
public void TestToStringOfWrappedBooleanFilters()
{
BooleanFilter orFilter = new BooleanFilter();
BooleanFilter stockFilter = new BooleanFilter();
stockFilter.Add(new FilterClause(GetTermsFilter(@"inStock", @"Y"), Occur.MUST));
stockFilter.Add(new FilterClause(GetTermsFilter(@"barCode", @"12345678"), Occur.MUST));
orFilter.Add(new FilterClause(stockFilter, Occur.SHOULD));
BooleanFilter productPropertyFilter = new BooleanFilter();
productPropertyFilter.Add(new FilterClause(GetTermsFilter(@"isHeavy", @"N"), Occur.MUST));
productPropertyFilter.Add(new FilterClause(GetTermsFilter(@"isDamaged", @"Y"), Occur.MUST));
orFilter.Add(new FilterClause(productPropertyFilter, Occur.SHOULD));
BooleanFilter composedFilter = new BooleanFilter();
composedFilter.Add(new FilterClause(orFilter, Occur.MUST));
assertEquals(@"BooleanFilter(+BooleanFilter(BooleanFilter(+inStock:Y +barCode:12345678) BooleanFilter(+isHeavy:N +isDamaged:Y)))", composedFilter.ToString());
}
}
}