/* * 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.Linq; using Lucene.Net.Index; using IndexReader = Lucene.Net.Index.IndexReader; namespace Lucene.Net.Search { /// The abstract base class for queries. ///

Instantiable subclasses are: /// /// /// /// /// /// /// /// /// /// /// /// /// ///

A parser for queries is contained in: /// /// QueryParser /// ///

[Serializable] public abstract class Query : System.ICloneable { private float boost = 1.0f; // query boost factor /// Gets or sets the boost for this query clause to b. Documents /// matching this clause will (in addition to the normal weightings) have /// their score multiplied by b. The boost is 1.0 by default. /// public virtual float Boost { get { return boost; } set { boost = value; } } /// Prints a query to a string, with field assumed to be the /// default field and omitted. ///

The representation used is one that is supposed to be readable /// by QueryParser. However, /// there are the following limitations: /// /// If the query was created by the parser, the printed /// representation may not be exactly what was parsed. For example, /// characters that need to be escaped will be represented without /// the required backslash. /// Some of the more complicated queries (e.g. span queries) /// don't have a representation that can be parsed by QueryParser. /// ///

public abstract System.String ToString(System.String field); /// Prints a query to a string. public override System.String ToString() { return ToString(""); } /// Expert: Constructs an appropriate Weight implementation for this query. /// ///

/// Only implemented by primitive queries, which re-write to themselves. ///

public virtual Weight CreateWeight(Searcher searcher) { throw new System.NotSupportedException(); } /// Expert: Constructs and initializes a Weight for a top-level query. public virtual Weight Weight(Searcher searcher) { Query query = searcher.Rewrite(this); Weight weight = query.CreateWeight(searcher); float sum = weight.GetSumOfSquaredWeights(); float norm = GetSimilarity(searcher).QueryNorm(sum); if (float.IsInfinity(norm) || float.IsNaN(norm)) norm = 1.0f; weight.Normalize(norm); return weight; } /// Expert: called to re-write queries into primitive queries. For example, /// a PrefixQuery will be rewritten into a BooleanQuery that consists /// of TermQuerys. /// public virtual Query Rewrite(IndexReader reader) { return this; } /// Expert: called when re-writing queries under MultiSearcher. /// /// Create a single query suitable for use by all subsearchers (in 1-1 /// correspondence with queries). This is an optimization of the OR of /// all queries. We handle the common optimization cases of equal /// queries and overlapping clauses of boolean OR queries (as generated /// by MultiTermQuery.rewrite()). /// Be careful overriding this method as queries[0] determines which /// method will be called and is not necessarily of the same type as /// the other queries. /// public virtual Query Combine(Query[] queries) { var uniques = new System.Collections.Generic.HashSet(); for (int i = 0; i < queries.Length; i++) { Query query = queries[i]; BooleanClause[] clauses = null; // check if we can split the query into clauses bool splittable = (query is BooleanQuery); if (splittable) { BooleanQuery bq = (BooleanQuery) query; splittable = bq.IsCoordDisabled(); clauses = bq.GetClauses(); for (int j = 0; splittable && j < clauses.Length; j++) { splittable = (clauses[j].Occur == Occur.SHOULD); } } if (splittable) { for (int j = 0; j < clauses.Length; j++) { uniques.Add(clauses[j].Query); } } else { uniques.Add(query); } } // optimization: if we have just one query, just return it if (uniques.Count == 1) { return uniques.First(); } BooleanQuery result = new BooleanQuery(true); foreach (Query key in uniques) { result.Add(key, Occur.SHOULD); } return result; } /// Expert: adds all terms occuring in this query to the terms set. Only /// works if this query is in its rewritten form. /// /// /// UnsupportedOperationException if this query is not yet rewritten public virtual void ExtractTerms(System.Collections.Generic.ISet terms) { // needs to be implemented by query subclasses throw new System.NotSupportedException(); } /// Expert: merges the clauses of a set of BooleanQuery's into a single /// BooleanQuery. /// ///

A utility for use by implementations. ///

public static Query MergeBooleanQueries(params BooleanQuery[] queries) { var allClauses = new System.Collections.Generic.HashSet(); foreach (BooleanQuery booleanQuery in queries) { foreach (BooleanClause clause in booleanQuery) { allClauses.Add(clause); } } bool coordDisabled = queries.Length == 0?false:queries[0].IsCoordDisabled(); BooleanQuery result = new BooleanQuery(coordDisabled); foreach(BooleanClause clause in allClauses) { result.Add(clause); } return result; } /// Expert: Returns the Similarity implementation to be used for this query. /// Subclasses may override this method to specify their own Similarity /// implementation, perhaps one that delegates through that of the Searcher. /// By default the Searcher's Similarity implementation is returned. /// public virtual Similarity GetSimilarity(Searcher searcher) { return searcher.Similarity; } /// Returns a clone of this query. public virtual System.Object Clone() { try { return base.MemberwiseClone(); } catch (System.Exception e) { throw new System.SystemException("Clone not supported: " + e.Message); } } public override int GetHashCode() { int prime = 31; int result = 1; result = prime * result + BitConverter.ToInt32(BitConverter.GetBytes(boost), 0); return result; } public override bool Equals(System.Object obj) { if (this == obj) return true; if (obj == null) return false; if (GetType() != obj.GetType()) return false; Query other = (Query) obj; if (BitConverter.ToInt32(BitConverter.GetBytes(boost), 0) != BitConverter.ToInt32(BitConverter.GetBytes(other.boost), 0)) return false; return true; } } }