static void ProcessBooleanClause(BooleanQuery bq, BooleanClause bc) { BooleanQuery query = new BooleanQuery(); foreach (QueryClause clause in bc.Children) { ProcessClause(query, clause); } bq.Add( query, Translate(bc.Type) ); }
public virtual void TestNoPayload() { PayloadTermQuery q1 = new PayloadTermQuery(new Term(PayloadHelper.NO_PAYLOAD_FIELD, "zero"), new MaxPayloadFunction()); PayloadTermQuery q2 = new PayloadTermQuery(new Term(PayloadHelper.NO_PAYLOAD_FIELD, "foo"), new MaxPayloadFunction()); BooleanClause c1 = new BooleanClause(q1, BooleanClause.Occur.MUST); BooleanClause c2 = new BooleanClause(q2, BooleanClause.Occur.MUST_NOT); BooleanQuery query = new BooleanQuery(); query.Add(c1); query.Add(c2); TopDocs hits = Searcher.Search(query, null, 100); Assert.IsTrue(hits != null, "hits is null and it shouldn't be"); Assert.IsTrue(hits.TotalHits == 1, "hits Size: " + hits.TotalHits + " is not: " + 1); int[] results = new int[1]; results[0] = 0; //hits.ScoreDocs[0].Doc; CheckHits.CheckHitCollector(Random(), query, PayloadHelper.NO_PAYLOAD_FIELD, Searcher, results); }
public override Query Rewrite(IndexReader r) { if (!query.Clauses.Any()) { return(new MatchAllDocsQuery()); } IList <Filter> filters = new List <Filter>(); IList <Query> queries = new List <Query>(); IList <BooleanClause> clauses = query.Clauses; Query baseQuery; int startIndex; if (drillDownDims.Count == query.Clauses.Count()) { baseQuery = new MatchAllDocsQuery(); startIndex = 0; } else { baseQuery = clauses[0].Query; startIndex = 1; } for (int i = startIndex; i < clauses.Count; i++) { BooleanClause clause = clauses[i]; Query queryClause = clause.Query; Filter filter = GetFilter(queryClause); if (filter != null) { filters.Add(filter); } else { queries.Add(queryClause); } } if (filters.Count == 0) { return(query); } else { // Wrap all filters using FilteredQuery // TODO: this is hackish; we need to do it because // BooleanQuery can't be trusted to handle the // "expensive filter" case. Really, each Filter should // know its cost and we should take that more // carefully into account when picking the right // strategy/optimization: Query wrapped; if (queries.Count == 0) { wrapped = baseQuery; } else { // disable coord BooleanQuery wrappedBQ = new BooleanQuery(true); if ((baseQuery is MatchAllDocsQuery) == false) { wrappedBQ.Add(baseQuery, Occur.MUST); } foreach (Query q in queries) { wrappedBQ.Add(q, Occur.MUST); } wrapped = wrappedBQ; } foreach (Filter filter in filters) { wrapped = new FilteredQuery(wrapped, filter, FilteredQuery.QUERY_FIRST_FILTER_STRATEGY); } return(wrapped); } }
protected internal virtual void AddClause(IList <BooleanClause> clauses, int conj, int mods, Query q) { bool required, prohibited; // If this term is introduced by AND, make the preceding term required, // unless it's already prohibited if (clauses.Count > 0 && conj == CONJ_AND) { BooleanClause c = clauses[clauses.Count - 1]; if (!c.IsProhibited) { c.Occur = Occur.MUST; } } if (clauses.Count > 0 && DefaultOperator == AND_OPERATOR && conj == CONJ_OR) { // If this term is introduced by OR, make the preceding term optional, // unless it's prohibited (that means we leave -a OR b but +a OR b-->a OR b) // notice if the input is a OR b, first term is parsed as required; without // this modification a OR b would parsed as +a OR b BooleanClause c = clauses[clauses.Count - 1]; if (!c.IsProhibited) { c.Occur = Occur.SHOULD; } } // We might have been passed a null query; the term might have been // filtered away by the analyzer. if (q == null) { return; } if (DefaultOperator == OR_OPERATOR) { // We set REQUIRED if we're introduced by AND or +; PROHIBITED if // introduced by NOT or -; make sure not to set both. prohibited = (mods == MOD_NOT); required = (mods == MOD_REQ); if (conj == CONJ_AND && !prohibited) { required = true; } } else { // We set PROHIBITED if we're introduced by NOT or -; We set REQUIRED // if not PROHIBITED and not introduced by OR prohibited = (mods == MOD_NOT); required = (!prohibited && conj != CONJ_OR); } if (required && !prohibited) { clauses.Add(NewBooleanClause(q, Occur.MUST)); } else if (!required && !prohibited) { clauses.Add(NewBooleanClause(q, Occur.SHOULD)); } else if (!required && prohibited) { clauses.Add(NewBooleanClause(q, Occur.MUST_NOT)); } else { throw new Exception("Clause cannot be both required and prohibited"); } }
public override Scorer GetScorer(AtomicReaderContext context, IBits acceptDocs) { IList <Scorer> required = new JCG.List <Scorer>(); IList <Scorer> prohibited = new JCG.List <Scorer>(); IList <Scorer> optional = new JCG.List <Scorer>(); IEnumerator <BooleanClause> cIter = outerInstance.clauses.GetEnumerator(); foreach (Weight w in m_weights) { cIter.MoveNext(); BooleanClause c = cIter.Current; Scorer subScorer = w.GetScorer(context, acceptDocs); if (subScorer == null) { if (c.IsRequired) { return(null); } } else if (c.IsRequired) { required.Add(subScorer); } else if (c.IsProhibited) { prohibited.Add(subScorer); } else { optional.Add(subScorer); } } if (required.Count == 0 && optional.Count == 0) { // no required and optional clauses. return(null); } else if (optional.Count < outerInstance.m_minNrShouldMatch) { // either >1 req scorer, or there are 0 req scorers and at least 1 // optional scorer. Therefore if there are not enough optional scorers // no documents will be matched by the query return(null); } // simple conjunction if (optional.Count == 0 && prohibited.Count == 0) { float coord = disableCoord ? 1.0f : Coord(required.Count, m_maxCoord); return(new ConjunctionScorer(this, required.ToArray(), coord)); } // simple disjunction if (required.Count == 0 && prohibited.Count == 0 && outerInstance.m_minNrShouldMatch <= 1 && optional.Count > 1) { var coord = new float[optional.Count + 1]; for (int i = 0; i < coord.Length; i++) { coord[i] = disableCoord ? 1.0f : Coord(i, m_maxCoord); } return(new DisjunctionSumScorer(this, optional.ToArray(), coord)); } // Return a BooleanScorer2 return(new BooleanScorer2(this, disableCoord, outerInstance.m_minNrShouldMatch, required, prohibited, optional, m_maxCoord)); }
public override Explanation Explain(AtomicReaderContext context, int doc) { int minShouldMatch = outerInstance.MinimumNumberShouldMatch; ComplexExplanation sumExpl = new ComplexExplanation(); sumExpl.Description = "sum of:"; int coord = 0; float sum = 0.0f; bool fail = false; int shouldMatchCount = 0; using (IEnumerator <BooleanClause> cIter = outerInstance.clauses.GetEnumerator()) { foreach (Weight w in m_weights) { cIter.MoveNext(); BooleanClause c = cIter.Current; if (w.GetScorer(context, context.AtomicReader.LiveDocs) == null) { if (c.IsRequired) { fail = true; Explanation r = new Explanation(0.0f, "no match on required clause (" + c.Query.ToString() + ")"); sumExpl.AddDetail(r); } continue; } Explanation e = w.Explain(context, doc); if (e.IsMatch) { if (!c.IsProhibited) { sumExpl.AddDetail(e); sum += e.Value; coord++; } else { Explanation r = new Explanation(0.0f, "match on prohibited clause (" + c.Query.ToString() + ")"); r.AddDetail(e); sumExpl.AddDetail(r); fail = true; } if (c.Occur == Occur_e.SHOULD) { shouldMatchCount++; } } else if (c.IsRequired) { Explanation r = new Explanation(0.0f, "no match on required clause (" + c.Query.ToString() + ")"); r.AddDetail(e); sumExpl.AddDetail(r); fail = true; } } } if (fail) { sumExpl.Match = false; sumExpl.Value = 0.0f; sumExpl.Description = "Failure to meet condition(s) of required/prohibited clause(s)"; return(sumExpl); } else if (shouldMatchCount < minShouldMatch) { sumExpl.Match = false; sumExpl.Value = 0.0f; sumExpl.Description = "Failure to match minimum number " + "of optional clauses: " + minShouldMatch; return(sumExpl); } sumExpl.Match = 0 < coord ? true : false; sumExpl.Value = sum; float coordFactor = disableCoord ? 1.0f : Coord(coord, m_maxCoord); if (coordFactor == 1.0f) { return(sumExpl); // eliminate wrapper } else { ComplexExplanation result = new ComplexExplanation(sumExpl.IsMatch, sum * coordFactor, "product of:"); result.AddDetail(sumExpl); result.AddDetail(new Explanation(coordFactor, "coord(" + coord + "/" + m_maxCoord + ")")); return(result); } }
/// <summary> /// Creates the price range query. /// </summary> /// <param name="priceLists">The price lists.</param> /// <param name="index">The index.</param> /// <param name="field">The field.</param> /// <param name="currency">The currency.</param> /// <param name="lowerbound">The lowerbound.</param> /// <param name="upperbound">The upperbound.</param> /// <param name="lowerboundincluded"> /// if set to <c>true</c> [lowerboundincluded]. /// </param> /// <param name="upperboundincluded"> /// if set to <c>true</c> [upperboundincluded]. /// </param> /// <returns></returns> private static BooleanQuery CreatePriceRangeQuery( string[] priceLists, int index, string field, string currency, string lowerbound, string upperbound, bool lowerboundincluded, bool upperboundincluded) { var query = new BooleanQuery(); // create left part var filter = new TermRangeFilter( String.Format("{0}_{1}_{2}", field, currency, priceLists[index - 1].ToLower()), "*", "*", true, false); var leftClause = new BooleanClause(new ConstantScoreQuery(filter), Occur.MUST_NOT); query.Add(leftClause); // create right part if (index == priceLists.Count()) // last element { //var rangefilter = NumericRangeFilter.; var filter2 = new TermRangeFilter( String.Format("{0}_{1}_{2}", field, currency, priceLists[index - 1].ToLower()), lowerbound, upperbound, lowerboundincluded, upperboundincluded); var rightClause = new BooleanClause(new ConstantScoreQuery(filter2), Occur.MUST); query.Add(rightClause); } else { query.Add( CreatePriceRangeQuery( priceLists, index + 1, field, currency, lowerbound, upperbound, lowerboundincluded, upperboundincluded), Occur.SHOULD); } return query; }
public override BooleanClause VisitBooleanClause(BooleanClause clause) { _text.Append(clause.GetOccur()); return(base.VisitBooleanClause(clause)); }
/// <summary> /// Searches the specified query. /// </summary> /// <param name="query">The query.</param> /// <param name="searchType">Type of the search.</param> /// <param name="entities">The entities.</param> /// <param name="fieldCriteria">The field criteria.</param> /// <param name="size">The size.</param> /// <param name="from">From.</param> /// <param name="totalResultsAvailable">The total results available.</param> /// <returns></returns> public override List <IndexModelBase> Search(string query, SearchType searchType, List <int> entities, SearchFieldCriteria fieldCriteria, int?size, int?from, out long totalResultsAvailable) { List <IndexModelBase> documents = new List <IndexModelBase>(); totalResultsAvailable = 0; bool allEntities = false; BooleanQuery queryContainer = new BooleanQuery(); List <string> combinedFields = new List <string>(); List <Type> indexModelTypes = new List <Type>(); Dictionary <string, Analyzer> combinedFieldAnalyzers = new Dictionary <string, Analyzer>(); using (RockContext rockContext = new RockContext()) { var entityTypeService = new EntityTypeService(rockContext); if (entities == null || entities.Count == 0) { // add all entities allEntities = true; var selectedEntityTypes = EntityTypeCache.All().Where(e => e.IsIndexingSupported && e.IsIndexingEnabled && e.FriendlyName != "Site"); foreach (var entityTypeCache in selectedEntityTypes) { entities.Add(entityTypeCache.Id); } } foreach (var entityId in entities) { // get entities search model name var entityType = entityTypeService.GetNoTracking(entityId); indexModelTypes.Add(entityType.IndexModelType); // check if this is a person model, if so we need to add two model types one for person and the other for businesses // wish there was a cleaner way to do this if (entityType.Guid == SystemGuid.EntityType.PERSON.AsGuid()) { indexModelTypes.Add(typeof(BusinessIndex)); } } indexModelTypes = indexModelTypes.Distinct().ToList(); } CombineIndexTypes(indexModelTypes, out combinedFields, out combinedFieldAnalyzers); var entityFieldFilter = new BooleanQuery(); if (entities != null && entities.Count != 0 && !allEntities) { Occur occur = fieldCriteria.SearchType == CriteriaSearchType.And ? Occur.MUST : Occur.SHOULD; var indexModelTypesQuery = new BooleanQuery(); foreach (var modelType in indexModelTypes) { var modelFilter = new BooleanQuery(); modelFilter.Add(new TermQuery(new Term("type", modelType.Name.ToLower())), Occur.MUST); if (fieldCriteria != null && fieldCriteria.FieldValues?.Count > 0) { var fieldQuery = new BooleanQuery(); foreach (var field in fieldCriteria.FieldValues) { var fieldName = field.Field.Substring(0, 1).ToUpper() + field.Field.Substring(1); if (modelType.GetProperty(fieldName) != null) { // Add field filter var phraseQuery = new PhraseQuery(); foreach (var word in field.Value.Split(' ')) { phraseQuery.Add(new Term(fieldName, word.ToLower())); } BooleanClause booleanClause = new BooleanClause(phraseQuery, occur); booleanClause.Query.Boost = field.Boost; fieldQuery.Add(booleanClause); } } if (fieldQuery.Clauses.Count() > 0) { modelFilter.Add(fieldQuery, Occur.MUST); } } indexModelTypesQuery.Add(modelFilter, Occur.SHOULD); } entityFieldFilter.Add(indexModelTypesQuery, Occur.MUST); queryContainer.Add(entityFieldFilter, Occur.MUST); } switch (searchType) { case SearchType.ExactMatch: { var wordQuery = new BooleanQuery(); if (!string.IsNullOrWhiteSpace(query)) { var words = query.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); foreach (var word in words) { var innerQuery = new BooleanQuery(); combinedFields.ForEach(f => innerQuery.Add(new PrefixQuery(new Term(f, word.ToLower())), Occur.SHOULD)); wordQuery.Add(innerQuery, Occur.SHOULD); } } if (wordQuery.Count() != 0) { queryContainer.Add(wordQuery, Occur.MUST); } // special logic to support emails if (query.Contains("@")) { queryContainer.Add(new BooleanClause(new TermQuery(new Term("Email", query)), Occur.SHOULD)); } // special logic to support phone search if (query.IsDigitsOnly()) { queryContainer.Add(new BooleanClause(new WildcardQuery(new Term("PhoneNumbers", "*" + query + "*")), Occur.SHOULD)); } // add a search for all the words as one single search term foreach (var field in combinedFields) { var phraseQuery = new PhraseQuery(); phraseQuery.Add(new Term(field, query.ToLower())); queryContainer.Add(phraseQuery, Occur.SHOULD); } break; } case SearchType.Fuzzy: { foreach (var field in combinedFields) { queryContainer.Add(new FuzzyQuery(new Term(field, query.ToLower())), Occur.SHOULD); } break; } case SearchType.Wildcard: { bool enablePhraseSearch = true; if (!string.IsNullOrWhiteSpace(query)) { BooleanQuery wildcardQuery = new BooleanQuery(); // break each search term into a separate query and add the * to the end of each var queryTerms = query.Split(' ').Select(p => p.Trim()).ToList(); // special logic to support emails if (queryTerms.Count == 1 && query.Contains("@")) { wildcardQuery.Add(new WildcardQuery(new Term("Email", "*" + query.ToLower() + "*")), Occur.SHOULD); enablePhraseSearch = false; } else { foreach (var queryTerm in queryTerms) { if (!string.IsNullOrWhiteSpace(queryTerm)) { var innerQuery = new BooleanQuery(); combinedFields.ForEach(f => innerQuery.Add(new PrefixQuery(new Term(f, queryTerm.ToLower())), Occur.SHOULD)); wildcardQuery.Add(innerQuery, Occur.MUST); } } // add special logic to help boost last names if (queryTerms.Count() > 1 && (indexModelTypes.Contains(typeof(PersonIndex)) || indexModelTypes.Contains(typeof(BusinessIndex)))) { BooleanQuery nameQuery = new BooleanQuery { { new PrefixQuery(new Term("FirstName", queryTerms.First().ToLower())), Occur.MUST }, { new PrefixQuery(new Term("LastName", queryTerms.Last().ToLower())) { Boost = 30 }, Occur.MUST } }; wildcardQuery.Add(nameQuery, Occur.SHOULD); nameQuery = new BooleanQuery { { new PrefixQuery(new Term("NickName", queryTerms.First().ToLower())), Occur.MUST }, { new PrefixQuery(new Term("LastName", queryTerms.Last().ToLower())) { Boost = 30 }, Occur.MUST } }; wildcardQuery.Add(nameQuery, Occur.SHOULD); } // special logic to support phone search if (query.IsDigitsOnly()) { wildcardQuery.Add(new PrefixQuery(new Term("PhoneNumbers", queryTerms.First().ToLower())), Occur.SHOULD); } } queryContainer.Add(wildcardQuery, Occur.MUST); } // add a search for all the words as one single search term if (enablePhraseSearch) { // add a search for all the words as one single search term foreach (var field in combinedFields) { var phraseQuery = new PhraseQuery(); phraseQuery.Add(new Term(field, query.ToLower())); queryContainer.Add(phraseQuery, Occur.SHOULD); } } break; } } int returnSize = 10; if (size.HasValue) { returnSize = size.Value; } try { OpenReader(); } catch (IndexNotFoundException) { // Issue opening index. Most likely cause is the index is empty so return an empty results set. return(new List <IndexModelBase>()); } TopDocs topDocs = null; if (from.HasValue) { TopScoreDocCollector collector = TopScoreDocCollector.Create(returnSize * 10, true); // Search for 10 pages with returnSize entries in each page _indexSearcher.Search(queryContainer, collector); topDocs = collector.GetTopDocs(from.Value, returnSize); } else { topDocs = _indexSearcher.Search(queryContainer, returnSize); } totalResultsAvailable = topDocs.TotalHits; if (topDocs != null) { foreach (var hit in topDocs.ScoreDocs) { var document = LuceneDocToIndexModel(queryContainer, hit); if (document != null) { documents.Add(document); } } } return(documents); }
public override string ToString() { return(BooleanClause.ToString(occur) + filter.ToString()); }
public override void Add(BooleanClause clause) { throw new NotSupportedException(); }
public SingleQueryFilter(BooleanClause clause = BooleanClause.And) { this.Clause = clause; _predicateSet = new HashSet <FieldPredicate>(FieldPredicateComparer); }
/// <summary> /// Wrapper to set HasQuery flag /// </summary> /// <param name="clause"></param> internal void QueryAdd(BooleanClause clause) { this.HasQuery = true; this.Query.Add(clause); }