/*
* 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 IndexReader = Lucene.Net.Index.IndexReader;
namespace Lucene.Net.Search
{
/// The abstract base class for queries.
/// Instantiable subclasses are:
///
/// - {@link TermQuery}
///
- {@link MultiTermQuery}
///
- {@link BooleanQuery}
///
- {@link WildcardQuery}
///
- {@link PhraseQuery}
///
- {@link PrefixQuery}
///
- {@link MultiPhraseQuery}
///
- {@link FuzzyQuery}
///
- {@link RangeQuery}
///
- {@link Lucene.Net.search.spans.SpanQuery}
///
/// A parser for queries is contained in:
///
/// - {@link Lucene.Net.queryParser.QueryParser QueryParser}
///
///
[Serializable]
public abstract class Query : System.ICloneable
{
private float boost = 1.0f; // query boost factor
/// 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
.
///
public virtual void SetBoost(float b)
{
boost = b;
}
/// Gets the boost for this clause. 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 GetBoost()
{
return boost;
}
/// 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 {@link org.apache.lucene.queryParser.QueryParser 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.
///
protected internal 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.SumOfSquaredWeights();
float norm = GetSimilarity(searcher).QueryNorm(sum);
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() and RangeQuery.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)
{
System.Collections.Hashtable uniques = new System.Collections.Hashtable();
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].GetOccur() == BooleanClause.Occur.SHOULD);
}
}
if (splittable)
{
for (int j = 0; j < clauses.Length; j++)
{
Query tmp = clauses[j].GetQuery();
if (uniques.Contains(tmp) == false)
{
uniques.Add(tmp, tmp);
}
}
}
else
{
if (uniques.Contains(query) == false)
{
uniques.Add(query, query);
}
}
}
// optimization: if we have just one query, just return it
if (uniques.Count == 1)
{
System.Collections.IDictionaryEnumerator iter = uniques.GetEnumerator();
iter.MoveNext();
return iter.Value as Query;
}
System.Collections.IDictionaryEnumerator it = uniques.GetEnumerator();
BooleanQuery result = new BooleanQuery(true);
while (it.MoveNext())
{
result.Add((Query) it.Value, BooleanClause.Occur.SHOULD);
}
return result;
}
/// Expert: adds all terms occuring in this query to the terms set. Only
/// works if this query is in its {@link #rewrite rewritten} form.
///
///
/// UnsupportedOperationException if this query is not yet rewritten
public virtual void ExtractTerms(System.Collections.Hashtable 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 {@link #Combine(Query[])} implementations.
///
public static Query MergeBooleanQueries(Query[] queries)
{
System.Collections.Hashtable allClauses = new System.Collections.Hashtable();
for (int i = 0; i < queries.Length; i++)
{
BooleanClause[] clauses = ((BooleanQuery) queries[i]).GetClauses();
for (int j = 0; j < clauses.Length; j++)
{
allClauses.Add(clauses[j], clauses[j]);
}
}
bool coordDisabled = queries.Length == 0 ? false : ((BooleanQuery) queries[0]).IsCoordDisabled();
BooleanQuery result = new BooleanQuery(coordDisabled);
foreach (BooleanClause booleanClause in allClauses.Keys)
{
result.Add(booleanClause);
}
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.GetSimilarity();
}
/// Returns a clone of this query.
public virtual System.Object Clone()
{
try
{
return (Query) base.MemberwiseClone();
}
catch (System.Exception e)
{
throw new System.SystemException("Clone not supported: " + e.Message);
}
}
}
}