blob: b71846dfdd398e15f62885c5112df83c0f1f0521 [file] [log] [blame]
/*
* 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.
*/
package org.apache.lucene.queryparser.ext;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.queryparser.ext.Extensions.Pair;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.Query;
/**
* The {@link ExtendableQueryParser} enables arbitrary query parser extension
* based on a customizable field naming scheme. The lucene query syntax allows
* implicit and explicit field definitions as query prefix followed by a colon
* (':') character. The {@link ExtendableQueryParser} allows to encode extension
* keys into the field symbol associated with a registered instance of
* {@link ParserExtension}. A customizable separation character separates the
* extension key from the actual field symbol. The {@link ExtendableQueryParser}
* splits (@see {@link Extensions#splitExtensionField(String, String)}) the
* extension key from the field symbol and tries to resolve the associated
* {@link ParserExtension}. If the parser can't resolve the key or the field
* token does not contain a separation character, {@link ExtendableQueryParser}
* yields the same behavior as its super class {@link QueryParser}. Otherwise,
* if the key is associated with a {@link ParserExtension} instance, the parser
* builds an instance of {@link ExtensionQuery} to be processed by
* {@link ParserExtension#parse(ExtensionQuery)}.If a extension field does not
* contain a field part the default field for the query will be used.
* <p>
* To guarantee that an extension field is processed with its associated
* extension, the extension query part must escape any special characters like
* '*' or '['. If the extension query contains any whitespace characters, the
* extension query part must be enclosed in quotes.
* Example ('_' used as separation character):
* <pre>
* title_customExt:"Apache Lucene\?" OR content_customExt:prefix\*
* </pre>
*
* Search on the default field:
* <pre>
* _customExt:"Apache Lucene\?" OR _customExt:prefix\*
* </pre>
* <p>
* The {@link ExtendableQueryParser} itself does not implement the logic how
* field and extension key are separated or ordered. All logic regarding the
* extension key and field symbol parsing is located in {@link Extensions}.
* Customized extension schemes should be implemented by sub-classing
* {@link Extensions}.
* </p>
* <p>
* For details about the default encoding scheme see {@link Extensions}.
* </p>
*
* @see Extensions
* @see ParserExtension
* @see ExtensionQuery
*/
public class ExtendableQueryParser extends QueryParser {
private final String defaultField;
private final Extensions extensions;
/**
* Default empty extensions instance
*/
private static final Extensions DEFAULT_EXTENSION = new Extensions();
/**
* Creates a new {@link ExtendableQueryParser} instance
*
* @param f
* the default query field
* @param a
* the analyzer used to find terms in a query string
*/
public ExtendableQueryParser(final String f, final Analyzer a) {
this(f, a, DEFAULT_EXTENSION);
}
/**
* Creates a new {@link ExtendableQueryParser} instance
*
* @param f
* the default query field
* @param a
* the analyzer used to find terms in a query string
* @param ext
* the query parser extensions
*/
public ExtendableQueryParser(final String f,
final Analyzer a, final Extensions ext) {
super(f, a);
this.defaultField = f;
this.extensions = ext;
}
/**
* Returns the extension field delimiter character.
*
* @return the extension field delimiter character.
*/
public char getExtensionFieldDelimiter() {
return extensions.getExtensionFieldDelimiter();
}
@Override
protected Query getFieldQuery(final String field, final String queryText, boolean quoted)
throws ParseException {
final Pair<String,String> splitExtensionField = this.extensions
.splitExtensionField(defaultField, field);
final ParserExtension extension = this.extensions
.getExtension(splitExtensionField.cud);
if (extension != null) {
return extension.parse(new ExtensionQuery(this, splitExtensionField.cur,
queryText));
}
return super.getFieldQuery(field, queryText, quoted);
}
}