/** * 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 System; using System.Collections.Generic; using System.Linq; using System.Text; using Lucene.Net.Index; using Lucene.Net.Util; namespace Lucene.Net.Search { public class BooleanFilter : Filter { /// /// The filters that are optional clauses. /// private List shouldFilters = null; /// /// The filters that are used for exclusion. /// private List notFilters = null; /// /// The filters that must be met. /// private List mustFilters = null; /// /// Get the iterator for a specific filter. /// /// The list of filters /// The index of the iterator to get. /// The reader for the index. /// private DocIdSetIterator GetDISI(List filters, int index, IndexReader reader) { return ((Filter)filters[index]).GetDocIdSet(reader).Iterator(); } /// /// Get the id set for the filter. /// /// The reader. /// The filter set to use. public override DocIdSet GetDocIdSet(IndexReader reader) { OpenBitSetDISI res = null; if (shouldFilters != null) { for (int i = 0; i < shouldFilters.Count; i++) { if (res == null) { res = new OpenBitSetDISI(GetDISI(shouldFilters, i, reader), reader.MaxDoc()); } else { DocIdSet dis = ((Filter)shouldFilters[i]).GetDocIdSet(reader); if (dis is OpenBitSet) { // optimized case for OpenBitSets res.Or((OpenBitSet)dis); } else { res.InPlaceOr(GetDISI(shouldFilters, i, reader)); } } } } if (notFilters != null) { for (int i = 0; i < notFilters.Count; i++) { if (res == null) { res = new OpenBitSetDISI(GetDISI(notFilters, i, reader), reader.MaxDoc()); res.Flip(0, reader.MaxDoc()); // NOTE: may set bits on deleted docs } else { DocIdSet dis = ((Filter)notFilters[i]).GetDocIdSet(reader); if (dis is OpenBitSet) { // optimized case for OpenBitSets res.AndNot((OpenBitSet)dis); } else { res.InPlaceNot(GetDISI(notFilters, i, reader)); } } } } if (mustFilters != null) { for (int i = 0; i < mustFilters.Count; i++) { if (res == null) { res = new OpenBitSetDISI(GetDISI(mustFilters, i, reader), reader.MaxDoc()); } else { DocIdSet dis = ((Filter)mustFilters[i]).GetDocIdSet(reader); if (dis is OpenBitSet) { // optimized case for OpenBitSets res.And((OpenBitSet)dis); } else { res.InPlaceAnd(GetDISI(mustFilters, i, reader)); } } } } if (res != null) return FinalResult(res, reader.MaxDoc()); else { //TODO: 2.- change return DocIdSet.EMPTY_DOCIDSET; return null; } } /// /// Add a filter clause. /// /// The clause to add. public void Add(BooleanFilterClause filterClause) { if (filterClause.Occur == BooleanClause.Occur.MUST) { if (mustFilters == null) { mustFilters = new List(); } mustFilters.Add(filterClause.Filter); } if (filterClause.Occur == BooleanClause.Occur.SHOULD) { if (shouldFilters == null) { shouldFilters = new List(); } shouldFilters.Add(filterClause.Filter); } if (filterClause.Occur == BooleanClause.Occur.MUST_NOT) { if (notFilters == null) { notFilters = new List(); } notFilters.Add(filterClause.Filter); } } // TODO: in 3.0, instead of removing this deprecated // method, make it a no-op and mark it final /** Provide a SortedVIntList when it is definitely smaller * than an OpenBitSet. * @deprecated Either use CachingWrapperFilter, or * switch to a different DocIdSet implementation yourself. */ protected DocIdSet FinalResult(OpenBitSetDISI result, int maxDocs) { return (result.Cardinality() < (maxDocs / 9)) ? (DocIdSet)new SortedVIntList(result) : (DocIdSet)result; } /// /// Determine equality between two lists. /// /// /// /// private bool EqualFilters(List filters1, List filters2) { return (filters1 == filters2) || ((filters1 != null) && filters1.Equals(filters2)); } /// /// Equality /// /// /// public override bool Equals(Object obj) { if (this == obj) return true; if ((obj == null) || !(obj is BooleanFilter)) return false; BooleanFilter other = (BooleanFilter)obj; return EqualFilters(notFilters, other.notFilters) && EqualFilters(mustFilters, other.mustFilters) && EqualFilters(shouldFilters, other.shouldFilters); } /// /// Hash code. /// /// public override int GetHashCode() { int hash = 7; hash = 31 * (hash + this.ListHash(this.mustFilters)); hash = 31 * (hash + this.ListHash(this.notFilters)); hash = 31 * (hash + this.ListHash(this.shouldFilters)); return hash; } private int ListHash(List filters) { int sum = 0; if (filters != null && filters.Count > 0) { for (int i = 0; i < filters.Count; i++) { sum += filters[i].GetHashCode(); } } return sum; } /// /// String representation. /// /// public override String ToString() { StringBuilder buffer = new StringBuilder(); buffer.Append("BooleanFilter("); AppendFilters(shouldFilters, "", buffer); AppendFilters(mustFilters, "+", buffer); AppendFilters(notFilters, "-", buffer); buffer.Append(")"); return buffer.ToString(); } /// /// Append individual filters. /// /// /// /// private void AppendFilters(List filters, String occurString, StringBuilder buffer) { if (filters != null) { for (int i = 0; i < filters.Count(); i++) { buffer.Append(' '); buffer.Append(occurString); buffer.Append(filters[i].ToString()); } } } } /// /// A spefic clause that makes up a part of the BooleanFilter /// public class BooleanFilterClause { /// /// Create a new BooleanFilterClause /// /// A Filter object /// A parameter implementation indicating SHOULD, MUST or MUST NOT public BooleanFilterClause(Filter filter, BooleanClause.Occur occur) { this.Occur = occur; this.Filter = filter; } /// /// The underlying filter for the clause. /// public Filter Filter { get; private set; } /// /// The occurrence of this clause. /// public BooleanClause.Occur Occur { get; private set; } } }