/* * 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 Analyzer = Lucene.Net.Analysis.Analyzer; using BooleanClause = Lucene.Net.Search.BooleanClause; using BooleanQuery = Lucene.Net.Search.BooleanQuery; using MultiPhraseQuery = Lucene.Net.Search.MultiPhraseQuery; using PhraseQuery = Lucene.Net.Search.PhraseQuery; using Query = Lucene.Net.Search.Query; namespace Lucene.Net.QueryParsers { /// A QueryParser which constructs queries to search multiple fields. /// /// /// Kelvin Tan, Daniel Naber /// /// $Revision: 472959 $ /// public class MultiFieldQueryParser : QueryParser { private System.String[] fields; private System.Collections.IDictionary boosts; /// Creates a MultiFieldQueryParser. /// Allows passing of a map with term to Boost, and the boost to apply to each term. /// ///

It will, when parse(String query) /// is called, construct a query like this (assuming the query consists of /// two terms and you specify the two fields title and body):

/// /// /// (title:term1 body:term1) (title:term2 body:term2) /// /// ///

When setDefaultOperator(AND_OPERATOR) is set, the result will be:

/// /// /// +(title:term1 body:term1) +(title:term2 body:term2) /// /// ///

When you pass a boost (title=>5 body=>10) you can get

/// /// /// +(title:term1^5.0 body:term1^10.0) +(title:term2^5.0 body:term2^10.0) /// /// ///

In other words, all the query's terms must appear, but it doesn't matter in /// what fields they appear.

///
public MultiFieldQueryParser(System.String[] fields, Analyzer analyzer, System.Collections.IDictionary boosts):this(fields, analyzer) { this.boosts = boosts; } /// Creates a MultiFieldQueryParser. /// ///

It will, when parse(String query) /// is called, construct a query like this (assuming the query consists of /// two terms and you specify the two fields title and body):

/// /// /// (title:term1 body:term1) (title:term2 body:term2) /// /// ///

When setDefaultOperator(AND_OPERATOR) is set, the result will be:

/// /// /// +(title:term1 body:term1) +(title:term2 body:term2) /// /// ///

In other words, all the query's terms must appear, but it doesn't matter in /// what fields they appear.

///
public MultiFieldQueryParser(System.String[] fields, Analyzer analyzer):base(null, analyzer) { this.fields = fields; } public override Query GetFieldQuery(System.String field, System.String queryText, int slop) { if (field == null) { System.Collections.ArrayList clauses = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); for (int i = 0; i < fields.Length; i++) { Query q = base.GetFieldQuery(fields[i], queryText); if (q != null) { //If the user passes a map of boosts if (boosts != null) { //Get the boost from the map and apply them System.Single boost = (System.Single) boosts[fields[i]]; //if (boost != null) // {{Aroush-2.1 there is no null for 'boost' if (boosts[fields[i]] != null) // {{Aroush-2.1 will this line do? { q.SetBoost((float) boost); } } if (q is PhraseQuery) { ((PhraseQuery) q).SetSlop(slop); } if (q is MultiPhraseQuery) { ((MultiPhraseQuery) q).SetSlop(slop); } clauses.Add(new BooleanClause(q, BooleanClause.Occur.SHOULD)); } } if (clauses.Count == 0) // happens for stopwords return null; return GetBooleanQuery(clauses, true); } return base.GetFieldQuery(field, queryText); } public override Query GetFieldQuery(System.String field, System.String queryText) { return GetFieldQuery(field, queryText, 0); } public override Query GetFuzzyQuery(System.String field, System.String termStr, float minSimilarity) { if (field == null) { System.Collections.ArrayList clauses = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); for (int i = 0; i < fields.Length; i++) { clauses.Add(new BooleanClause(base.GetFuzzyQuery(fields[i], termStr, minSimilarity), BooleanClause.Occur.SHOULD)); } return GetBooleanQuery(clauses, true); } return base.GetFuzzyQuery(field, termStr, minSimilarity); } public override Query GetPrefixQuery(System.String field, System.String termStr) { if (field == null) { System.Collections.ArrayList clauses = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); for (int i = 0; i < fields.Length; i++) { clauses.Add(new BooleanClause(base.GetPrefixQuery(fields[i], termStr), BooleanClause.Occur.SHOULD)); } return GetBooleanQuery(clauses, true); } return base.GetPrefixQuery(field, termStr); } public override Query GetWildcardQuery(System.String field, System.String termStr) { if (field == null) { System.Collections.ArrayList clauses = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); for (int i = 0; i < fields.Length; i++) { clauses.Add(new BooleanClause(base.GetWildcardQuery(fields[i], termStr), BooleanClause.Occur.SHOULD)); } return GetBooleanQuery(clauses, true); } return base.GetWildcardQuery(field, termStr); } public override Query GetRangeQuery(System.String field, System.String part1, System.String part2, bool inclusive) { if (field == null) { System.Collections.ArrayList clauses = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); for (int i = 0; i < fields.Length; i++) { clauses.Add(new BooleanClause(base.GetRangeQuery(fields[i], part1, part2, inclusive), BooleanClause.Occur.SHOULD)); } return GetBooleanQuery(clauses, true); } return base.GetRangeQuery(field, part1, part2, inclusive); } /// Parses a query which searches on the fields specified. ///

/// If x fields are specified, this effectively constructs: ///

		/// 
		/// (field1:query1) (field2:query2) (field3:query3)...(fieldx:queryx)
		/// 
		/// 
///
/// Queries strings to parse /// /// Fields to search on /// /// Analyzer to use /// /// ParseException if query parsing fails /// IllegalArgumentException if the length of the queries array differs /// from the length of the fields array /// public static Query Parse(System.String[] queries, System.String[] fields, Analyzer analyzer) { if (queries.Length != fields.Length) throw new System.ArgumentException("queries.length != fields.length"); BooleanQuery bQuery = new BooleanQuery(); for (int i = 0; i < fields.Length; i++) { QueryParser qp = new QueryParser(fields[i], analyzer); Query q = qp.Parse(queries[i]); bQuery.Add(q, BooleanClause.Occur.SHOULD); } return bQuery; } /// Parses a query, searching on the fields specified. /// Use this if you need to specify certain fields as required, /// and others as prohibited. ///

		/// Usage:
		/// 
		/// String[] fields = {"filename", "contents", "description"};
		/// BooleanClause.Occur[] flags = {BooleanClause.Occur.SHOULD,
		/// BooleanClause.Occur.MUST,
		/// BooleanClause.Occur.MUST_NOT};
		/// MultiFieldQueryParser.parse("query", fields, flags, analyzer);
		/// 
		/// 
///

/// The code above would construct a query: ///

		/// 
		/// (filename:query) +(contents:query) -(description:query)
		/// 
		/// 
/// ///
/// Query string to parse /// /// Fields to search on /// /// Flags describing the fields /// /// Analyzer to use /// /// ParseException if query parsing fails /// IllegalArgumentException if the length of the fields array differs /// from the length of the flags array /// public static Query Parse(System.String query, System.String[] fields, BooleanClause.Occur[] flags, Analyzer analyzer) { if (fields.Length != flags.Length) throw new System.ArgumentException("fields.length != flags.length"); BooleanQuery bQuery = new BooleanQuery(); for (int i = 0; i < fields.Length; i++) { QueryParser qp = new QueryParser(fields[i], analyzer); Query q = qp.Parse(query); bQuery.Add(q, flags[i]); } return bQuery; } /// Parses a query, searching on the fields specified. /// Use this if you need to specify certain fields as required, /// and others as prohibited. ///

		/// Usage:
		/// 
		/// String[] query = {"query1", "query2", "query3"};
		/// String[] fields = {"filename", "contents", "description"};
		/// BooleanClause.Occur[] flags = {BooleanClause.Occur.SHOULD,
		/// BooleanClause.Occur.MUST,
		/// BooleanClause.Occur.MUST_NOT};
		/// MultiFieldQueryParser.parse(query, fields, flags, analyzer);
		/// 
		/// 
///

/// The code above would construct a query: ///

		/// 
		/// (filename:query1) +(contents:query2) -(description:query3)
		/// 
		/// 
/// ///
/// Queries string to parse /// /// Fields to search on /// /// Flags describing the fields /// /// Analyzer to use /// /// ParseException if query parsing fails /// IllegalArgumentException if the length of the queries, fields, /// and flags array differ /// public static Query Parse(System.String[] queries, System.String[] fields, BooleanClause.Occur[] flags, Analyzer analyzer) { if (!(queries.Length == fields.Length && queries.Length == flags.Length)) throw new System.ArgumentException("queries, fields, and flags array have have different length"); BooleanQuery bQuery = new BooleanQuery(); for (int i = 0; i < fields.Length; i++) { QueryParser qp = new QueryParser(fields[i], analyzer); Query q = qp.Parse(queries[i]); bQuery.Add(q, flags[i]); } return bQuery; } } }