public SimpleFacetedSearch(IndexReader reader, string[] groupByFields) { this._Reader = reader; List<FieldValuesBitSets> fieldValuesBitSets = new List<FieldValuesBitSets>(); //STEP 1 //f1 = A, B //f2 = I, J //f3 = 1, 2, 3 int maxFacets = 1; List<List<string>> inputToCP = new List<List<string>>(); foreach (string field in groupByFields) { FieldValuesBitSets f = new FieldValuesBitSets(reader, field); maxFacets *= f.FieldValueBitSetPair.Count; if (maxFacets > MAX_FACETS) throw new Exception("Facet count exceeded " + MAX_FACETS); fieldValuesBitSets.Add(f); inputToCP.Add(f.FieldValueBitSetPair.Keys.ToList()); } //STEP 2 // comb1: A I 1 // comb2: A I 2 etc. var cp = inputToCP.CartesianProduct(); //SETP 3 //create a single BitSet for each combination //BitSet1: A AND I AND 1 //BitSet2: A AND I AND 2 etc. //and remove impossible comb's (for ex, B J 3) from list. Parallel.ForEach(cp, combinations => { OpenBitSetDISI bitSet = new OpenBitSetDISI(_Reader.MaxDoc()); bitSet.Set(0, bitSet.Size()); List<string> comb = combinations.ToList(); for (int j = 0; j < comb.Count; j++) { bitSet.And(fieldValuesBitSets[j].FieldValueBitSetPair[comb[j]]); } //STEP 3 if (bitSet.Cardinality() > 0) { lock(_Groups) _Groups.Add(new KeyValuePair<List<string>, OpenBitSetDISI>(comb, bitSet)); } }); //Now _Groups has 7 rows (as <List<string>, BitSet> pairs) }