All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pageseeder.flint.lucene.query.Predicate Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2015 Allette Systems (Australia)
 * http://www.allette.com.au
 *
 * Licensed 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.
 */
package org.pageseeder.flint.lucene.query;

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.search.Query;
import org.pageseeder.flint.lucene.search.Fields;
import org.pageseeder.flint.lucene.util.Beta;
import org.pageseeder.xmlwriter.XMLWritable;
import org.pageseeder.xmlwriter.XMLWriter;

/**
 * A simple parameter to represent a Lucene predicate produced by a query parser.
 *
 * 

The predicate is similar to the {@link Question} except that it can be used for * more powerful search; it is however more difficult to produce similar predicates. * *

It acts on one or multiple fields, each field can have a different boost level. * *

Use the factory methods to create new predicate. * * @author Christophe Lauret (Weborganic) * @version 16 August 2010 */ @Beta public final class Predicate implements SearchParameter, XMLWritable { /** * The lucene predicate entered by the user. */ private final String _predicate; /** * The field names mapped to their boost value. */ private final Map _fields; /** * The computed query. */ private Query _query = null; // Constructors // ============================================================================================== /** * Creates a new question. * *

This is a low level API constructor; to ensure that this class works well, ensure that the * fields cannot be modified externally and that field names do not include empty strings. * * @param fields The fields to search mapped to their respective boost. * @param predicate The text before parsing. * * @throws NullPointerException If either argument is null. */ Predicate(Map fields, String predicate) throws NullPointerException { if (fields == null) throw new NullPointerException("fields"); if (predicate == null) throw new NullPointerException("predicate"); this._fields = fields; this._predicate = predicate; } // Methods // ============================================================================================== /** * Returns the list of fields this question applies to. * * @return the list of fields this question applies to. */ public Collection fields() { return this._fields.keySet(); } /** * Returns the underlying predicate string. * * @return the underlying predicate string. */ public String predicate() { return this._predicate; } /** * Returns the boost value for the specified field. * * @param field the name of the field. * * @return the corresponding boost value. */ public float getBoost(String field) { Float boost = this._fields.get(field); return boost != null ? boost : 1.0f; } /** * A question is empty if either the predicate or the fields are empty. * * @return true if either the predicate or the fields are empty; * false if the predicate has a value and there is at least one field. */ @Override public boolean isEmpty() { return this._predicate.isEmpty() || this._fields.isEmpty(); } /** * Computes the query for this question. * *

This only needs to be done once. * * @param analyzer The analyser used by the underlying index. * * @throws ParseException If the question could not be parsed properly. */ private void compute(Analyzer analyzer) throws ParseException { String[] fields = this._fields.keySet().toArray(new String[]{}); MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, analyzer); this._query = parser.parse(this._predicate); } /** * Computes the query for this question using the {@link StandardAnalyzer}. * *

This method ignores any Lucene specific syntax by removing it from the input string. * * @throws ParseException If the question could not be parsed properly. */ private void compute() throws ParseException { compute(new StandardAnalyzer()); } /** * Returns this object as Lucene query instance. * * @see #isEmpty() * * @return this object as a Lucene query instance, or null if this query is empty. * @throws IllegalStateException if the query has not been computed before - should not happen if using factory * methods. */ @Override public Query toQuery() throws IllegalStateException { // Return null if empty if (isEmpty()) return null; // Query was not computed if (this._query == null) throw new IllegalStateException("Query has not been computed - call compute(Analyzer)"); return this._query; } /** * {@inheritDoc} */ @Override public void toXML(XMLWriter xml) throws IOException { xml.openElement("predicate", true); // indicate whether this search term is empty xml.attribute("is-empty", Boolean.toString(isEmpty())); if (this._query != null) { xml.attribute("query", this._query.toString()); } // details of the question for (Entry field : this._fields.entrySet()) { xml.openElement("field"); Float boost = field.getValue(); xml.attribute("boost", boost != null? boost.toString() : "1.0"); xml.writeText(field.getKey()); xml.closeElement(); } xml.element("text", this._predicate); xml.closeElement(); } /** * {@inheritDoc} */ @Override public String toString() { return this._predicate + " in " + this._fields.entrySet(); } // Factory methods // ============================================================================================== /** * A factory method to create a new predicate and compute it using the Lucene {@link MultiFieldQueryParser}. * * @param field The default field for the predicate. * @param predicate The predicate to parse * @param analyzer The analyser to use when parsing the predicate. * * @return a new predicate. * * @throws ParseException if the predicate could not be parsed. */ public static Predicate newPredicate(String field, String predicate, Analyzer analyzer) throws ParseException { Map fields = Collections.singletonMap(field, 1.0f); Predicate q = new Predicate(fields, predicate); q.compute(analyzer); return q; } /** * A factory method to create a new predicate and compute it using the Lucene {@link MultiFieldQueryParser}. * * @param fields The list of default fields for the predicate. * @param predicate The predicate to parse * @param analyzer The analyser to use when parsing the predicate. * * @return a new predicate. * * @throws ParseException if the predicate could not be parsed. */ public static Predicate newPredicate(List fields, String predicate, Analyzer analyzer) throws ParseException { List names = Fields.filterNames(fields); Map map = Fields.asBoostMap(names); Predicate q = new Predicate(map, predicate); q.compute(analyzer); return q; } /** * A factory method to create a new question and compute it using the Lucene {@link MultiFieldQueryParser}. * * @param fields The list of fields for the question. * @param predicate The predicate to parse * @param analyzer The analyser to use when parsing the predicate. * * @return a new predicate. * * @throws ParseException if the predicate could not be parsed. */ public static Predicate newPredicate(Map fields, String predicate, Analyzer analyzer) throws ParseException { Predicate q = new Predicate(fields, predicate); q.compute(analyzer); return q; } /** * A factory method to create a new question and compute it using the Lucene {@link MultiFieldQueryParser} * and the {@link StandardAnalyzer}. * * @param fields The list of fields for the question. * @param predicate The predicate to parse * * @return a new predicate. * * @throws ParseException if the predicate could not be parsed. */ public static Predicate newPredicate(List fields, String predicate) throws ParseException { List names = Fields.filterNames(fields); Map map = Fields.asBoostMap(names); Predicate q = new Predicate(map, predicate); q.compute(); return q; } /** * A factory method to create a new question and compute it using the Lucene {@link MultiFieldQueryParser} * and the {@link StandardAnalyzer}. * * @param fields The list of fields for the question. * @param predicate The predicate to parse * * @return a new predicate. * * @throws ParseException if the predicate could not be parsed. */ public static Predicate newPredicate(Map fields, String predicate) throws ParseException { Predicate q = new Predicate(fields, predicate); q.compute(); return q; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy