improve query string parsing by reusing the same parser (bounded to the query parser context)

This commit is contained in:
kimchy 2010-09-12 15:39:07 +02:00
parent ed5ffd6591
commit 2442e1fb16
17 changed files with 676 additions and 168 deletions

View File

@ -17,12 +17,9 @@
* under the License.
*/
package org.elasticsearch.index.query.support;
package org.apache.lucene.queryParser;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.MultiTermQuery;
import org.apache.lucene.search.Query;
@ -52,11 +49,28 @@ public class MapperQueryParser extends QueryParser {
private FieldMapper currentMapper;
public MapperQueryParser(String defaultField, Analyzer analyzer,
QueryParseContext parseContext) {
super(Lucene.QUERYPARSER_VERSION, defaultField, analyzer);
public MapperQueryParser(QueryParseContext parseContext) {
super(Lucene.QUERYPARSER_VERSION, null, null);
this.parseContext = parseContext;
}
public MapperQueryParser(QueryParserSettings settings, QueryParseContext parseContext) {
super(Lucene.QUERYPARSER_VERSION, settings.defaultField(), settings.analyzer());
this.parseContext = parseContext;
reset(settings);
}
public void reset(QueryParserSettings settings) {
this.field = settings.defaultField();
this.analyzer = settings.analyzer();
setMultiTermRewriteMethod(MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT);
setEnablePositionIncrements(settings.enablePositionIncrements());
setAllowLeadingWildcard(settings.allowLeadingWildcard());
setLowercaseExpandedTerms(settings.lowercaseExpandedTerms());
setPhraseSlop(settings.phraseSlop());
setDefaultOperator(settings.defaultOperator());
setFuzzyMinSim(settings.fuzzyMinSim());
setFuzzyPrefixLength(settings.fuzzyPrefixLength());
}
@Override protected Query newTermQuery(Term term) {

View File

@ -17,15 +17,11 @@
* under the License.
*/
package org.elasticsearch.index.query.support;
package org.apache.lucene.queryParser;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.*;
import org.elasticsearch.common.trove.ExtTObjectFloatHashMap;
import org.elasticsearch.index.query.xcontent.QueryParseContext;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
@ -34,29 +30,20 @@ import java.util.List;
*/
public class MultiFieldMapperQueryParser extends MapperQueryParser {
private List<String> fields;
private MultiFieldQueryParserSettings settings;
private ExtTObjectFloatHashMap<String> boosts;
private float tieBreaker = 0.0f;
private boolean useDisMax = true;
public MultiFieldMapperQueryParser(List<String> fields, @Nullable ExtTObjectFloatHashMap<String> boosts, Analyzer analyzer, QueryParseContext parseContext) {
super(null, analyzer, parseContext);
this.fields = fields;
this.boosts = boosts;
if (this.boosts != null) {
boosts.defaultReturnValue(1.0f);
}
public MultiFieldMapperQueryParser(QueryParseContext parseContext) {
super(parseContext);
}
public void setTieBreaker(float tieBreaker) {
this.tieBreaker = tieBreaker;
public MultiFieldMapperQueryParser(MultiFieldQueryParserSettings settings, QueryParseContext parseContext) {
super(settings, parseContext);
this.settings = settings;
}
public void setUseDisMax(boolean useDisMax) {
this.useDisMax = useDisMax;
public void reset(MultiFieldQueryParserSettings settings) {
super.reset(settings);
this.settings = settings;
}
@Override public Query getFieldQuery(String field, String queryText) throws ParseException {
@ -69,10 +56,10 @@ public class MultiFieldMapperQueryParser extends MapperQueryParser {
applySlop(q, slop);
return q;
}
if (useDisMax) {
DisjunctionMaxQuery disMaxQuery = new DisjunctionMaxQuery(tieBreaker);
if (settings.useDisMax()) {
DisjunctionMaxQuery disMaxQuery = new DisjunctionMaxQuery(settings.tieBreaker());
boolean added = false;
for (String field : fields) {
for (String field : settings.fields()) {
Query q = super.getFieldQuery(field, queryText);
if (q != null) {
added = true;
@ -87,7 +74,7 @@ public class MultiFieldMapperQueryParser extends MapperQueryParser {
return disMaxQuery;
} else {
List<BooleanClause> clauses = new ArrayList<BooleanClause>();
for (String field : fields) {
for (String field : settings.fields()) {
Query q = super.getFieldQuery(field, queryText);
if (q != null) {
applyBoost(field, q);
@ -105,10 +92,10 @@ public class MultiFieldMapperQueryParser extends MapperQueryParser {
if (xField != null) {
return super.getRangeQuery(xField, part1, part2, inclusive);
}
if (useDisMax) {
DisjunctionMaxQuery disMaxQuery = new DisjunctionMaxQuery(tieBreaker);
if (settings.useDisMax()) {
DisjunctionMaxQuery disMaxQuery = new DisjunctionMaxQuery(settings.tieBreaker());
boolean added = false;
for (String field : fields) {
for (String field : settings.fields()) {
Query q = super.getRangeQuery(field, part1, part2, inclusive);
if (q != null) {
added = true;
@ -122,7 +109,7 @@ public class MultiFieldMapperQueryParser extends MapperQueryParser {
return disMaxQuery;
} else {
List<BooleanClause> clauses = new ArrayList<BooleanClause>();
for (String field : fields) {
for (String field : settings.fields()) {
Query q = super.getRangeQuery(field, part1, part2, inclusive);
if (q != null) {
applyBoost(field, q);
@ -139,10 +126,10 @@ public class MultiFieldMapperQueryParser extends MapperQueryParser {
if (xField != null) {
return super.getPrefixQuery(xField, termStr);
}
if (useDisMax) {
DisjunctionMaxQuery disMaxQuery = new DisjunctionMaxQuery(tieBreaker);
if (settings.useDisMax()) {
DisjunctionMaxQuery disMaxQuery = new DisjunctionMaxQuery(settings.tieBreaker());
boolean added = false;
for (String field : fields) {
for (String field : settings.fields()) {
Query q = super.getPrefixQuery(field, termStr);
if (q != null) {
added = true;
@ -156,7 +143,7 @@ public class MultiFieldMapperQueryParser extends MapperQueryParser {
return disMaxQuery;
} else {
List<BooleanClause> clauses = new ArrayList<BooleanClause>();
for (String field : fields) {
for (String field : settings.fields()) {
Query q = super.getPrefixQuery(field, termStr);
if (q != null) {
applyBoost(field, q);
@ -173,10 +160,10 @@ public class MultiFieldMapperQueryParser extends MapperQueryParser {
if (xField != null) {
return super.getWildcardQuery(xField, termStr);
}
if (useDisMax) {
DisjunctionMaxQuery disMaxQuery = new DisjunctionMaxQuery(tieBreaker);
if (settings.useDisMax()) {
DisjunctionMaxQuery disMaxQuery = new DisjunctionMaxQuery(settings.tieBreaker());
boolean added = false;
for (String field : fields) {
for (String field : settings.fields()) {
Query q = super.getWildcardQuery(field, termStr);
if (q != null) {
added = true;
@ -190,7 +177,7 @@ public class MultiFieldMapperQueryParser extends MapperQueryParser {
return disMaxQuery;
} else {
List<BooleanClause> clauses = new ArrayList<BooleanClause>();
for (String field : fields) {
for (String field : settings.fields()) {
Query q = super.getWildcardQuery(field, termStr);
if (q != null) {
applyBoost(field, q);
@ -207,10 +194,10 @@ public class MultiFieldMapperQueryParser extends MapperQueryParser {
if (xField != null) {
return super.getFuzzyQuery(xField, termStr, minSimilarity);
}
if (useDisMax) {
DisjunctionMaxQuery disMaxQuery = new DisjunctionMaxQuery(tieBreaker);
if (settings.useDisMax()) {
DisjunctionMaxQuery disMaxQuery = new DisjunctionMaxQuery(settings.tieBreaker());
boolean added = false;
for (String field : fields) {
for (String field : settings.fields()) {
Query q = super.getFuzzyQuery(field, termStr, minSimilarity);
if (q != null) {
added = true;
@ -224,7 +211,7 @@ public class MultiFieldMapperQueryParser extends MapperQueryParser {
return disMaxQuery;
} else {
List<BooleanClause> clauses = new ArrayList<BooleanClause>();
for (String field : fields) {
for (String field : settings.fields()) {
Query q = super.getFuzzyQuery(field, termStr, minSimilarity);
applyBoost(field, q);
clauses.add(new BooleanClause(q, BooleanClause.Occur.SHOULD));
@ -234,8 +221,8 @@ public class MultiFieldMapperQueryParser extends MapperQueryParser {
}
private void applyBoost(String field, Query q) {
if (boosts != null) {
float boost = boosts.get(field);
if (settings.boosts() != null) {
float boost = settings.boosts().get(field);
q.setBoost(boost);
}
}

View File

@ -0,0 +1,96 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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;
import org.elasticsearch.common.trove.ExtTObjectFloatHashMap;
import java.util.List;
/**
* @author kimchy (shay.banon)
*/
public class MultiFieldQueryParserSettings extends QueryParserSettings {
List<String> fields = null;
ExtTObjectFloatHashMap<String> boosts = null;
float tieBreaker = 0.0f;
boolean useDisMax = true;
public List<String> fields() {
return fields;
}
public void fields(List<String> fields) {
this.fields = fields;
}
public ExtTObjectFloatHashMap<String> boosts() {
return boosts;
}
public void boosts(ExtTObjectFloatHashMap<String> boosts) {
this.boosts = boosts;
}
public float tieBreaker() {
return tieBreaker;
}
public void tieBreaker(float tieBreaker) {
this.tieBreaker = tieBreaker;
}
public boolean useDisMax() {
return useDisMax;
}
public void useDisMax(boolean useDisMax) {
this.useDisMax = useDisMax;
}
@Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
// if there is a single field, its the same as single mapper parser / settings
// we take for that also in the code
if (fields == null || fields.size() == 1) return super.equals(o);
if (!super.equals(o)) return false;
MultiFieldQueryParserSettings that = (MultiFieldQueryParserSettings) o;
if (Float.compare(that.tieBreaker, tieBreaker) != 0) return false;
if (useDisMax != that.useDisMax) return false;
if (boosts != null ? !boosts.equals(that.boosts) : that.boosts != null) return false;
if (fields != null ? !fields.equals(that.fields) : that.fields != null) return false;
return true;
}
@Override public int hashCode() {
int result = super.hashCode();
result = 31 * result + (fields != null ? fields.hashCode() : 0);
result = 31 * result + (boosts != null ? boosts.hashCode() : 0);
result = 31 * result + (tieBreaker != +0.0f ? Float.floatToIntBits(tieBreaker) : 0);
result = 31 * result + (useDisMax ? 1 : 0);
return result;
}
}

View File

@ -0,0 +1,176 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.search.FuzzyQuery;
/**
* @author kimchy (shay.banon)
*/
public class QueryParserSettings {
private String queryString;
private String defaultField;
private float boost = 1.0f;
private MapperQueryParser.Operator defaultOperator = QueryParser.Operator.OR;
private boolean allowLeadingWildcard = true;
private boolean lowercaseExpandedTerms = true;
private boolean enablePositionIncrements = true;
private int phraseSlop = 0;
private float fuzzyMinSim = FuzzyQuery.defaultMinSimilarity;
private int fuzzyPrefixLength = FuzzyQuery.defaultPrefixLength;
private boolean escape = false;
private Analyzer analyzer = null;
public String queryString() {
return queryString;
}
public void queryString(String queryString) {
this.queryString = queryString;
}
public String defaultField() {
return defaultField;
}
public void defaultField(String defaultField) {
this.defaultField = defaultField;
}
public float boost() {
return boost;
}
public void boost(float boost) {
this.boost = boost;
}
public QueryParser.Operator defaultOperator() {
return defaultOperator;
}
public void defaultOperator(QueryParser.Operator defaultOperator) {
this.defaultOperator = defaultOperator;
}
public boolean allowLeadingWildcard() {
return allowLeadingWildcard;
}
public void allowLeadingWildcard(boolean allowLeadingWildcard) {
this.allowLeadingWildcard = allowLeadingWildcard;
}
public boolean lowercaseExpandedTerms() {
return lowercaseExpandedTerms;
}
public void lowercaseExpandedTerms(boolean lowercaseExpandedTerms) {
this.lowercaseExpandedTerms = lowercaseExpandedTerms;
}
public boolean enablePositionIncrements() {
return enablePositionIncrements;
}
public void enablePositionIncrements(boolean enablePositionIncrements) {
this.enablePositionIncrements = enablePositionIncrements;
}
public int phraseSlop() {
return phraseSlop;
}
public void phraseSlop(int phraseSlop) {
this.phraseSlop = phraseSlop;
}
public float fuzzyMinSim() {
return fuzzyMinSim;
}
public void fuzzyMinSim(float fuzzyMinSim) {
this.fuzzyMinSim = fuzzyMinSim;
}
public int fuzzyPrefixLength() {
return fuzzyPrefixLength;
}
public void fuzzyPrefixLength(int fuzzyPrefixLength) {
this.fuzzyPrefixLength = fuzzyPrefixLength;
}
public boolean escape() {
return escape;
}
public void escape(boolean escape) {
this.escape = escape;
}
public Analyzer analyzer() {
return analyzer;
}
public void analyzer(Analyzer analyzer) {
this.analyzer = analyzer;
}
@Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
QueryParserSettings that = (QueryParserSettings) o;
if (allowLeadingWildcard != that.allowLeadingWildcard) return false;
if (Float.compare(that.boost, boost) != 0) return false;
if (enablePositionIncrements != that.enablePositionIncrements) return false;
if (escape != that.escape) return false;
if (Float.compare(that.fuzzyMinSim, fuzzyMinSim) != 0) return false;
if (fuzzyPrefixLength != that.fuzzyPrefixLength) return false;
if (lowercaseExpandedTerms != that.lowercaseExpandedTerms) return false;
if (phraseSlop != that.phraseSlop) return false;
if (analyzer != null ? !analyzer.equals(that.analyzer) : that.analyzer != null) return false;
if (defaultField != null ? !defaultField.equals(that.defaultField) : that.defaultField != null) return false;
if (defaultOperator != that.defaultOperator) return false;
if (queryString != null ? !queryString.equals(that.queryString) : that.queryString != null) return false;
return true;
}
@Override public int hashCode() {
int result = queryString != null ? queryString.hashCode() : 0;
result = 31 * result + (defaultField != null ? defaultField.hashCode() : 0);
result = 31 * result + (boost != +0.0f ? Float.floatToIntBits(boost) : 0);
result = 31 * result + (defaultOperator != null ? defaultOperator.hashCode() : 0);
result = 31 * result + (allowLeadingWildcard ? 1 : 0);
result = 31 * result + (lowercaseExpandedTerms ? 1 : 0);
result = 31 * result + (enablePositionIncrements ? 1 : 0);
result = 31 * result + phraseSlop;
result = 31 * result + (fuzzyMinSim != +0.0f ? Float.floatToIntBits(fuzzyMinSim) : 0);
result = 31 * result + fuzzyPrefixLength;
result = 31 * result + (escape ? 1 : 0);
result = 31 * result + (analyzer != null ? analyzer.hashCode() : 0);
return result;
}
}

View File

@ -20,8 +20,11 @@
package org.elasticsearch.cache;
import org.elasticsearch.cache.memory.ByteBufferCache;
import org.elasticsearch.cache.query.parser.QueryParserCache;
import org.elasticsearch.cache.query.parser.none.NoneQueryParserCache;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
/**
@ -31,9 +34,16 @@ public class NodeCache extends AbstractComponent {
private final ByteBufferCache byteBufferCache;
@Inject public NodeCache(Settings settings, ByteBufferCache byteBufferCache) {
private final QueryParserCache queryParserCache;
public NodeCache() {
this(ImmutableSettings.Builder.EMPTY_SETTINGS, new ByteBufferCache(ImmutableSettings.Builder.EMPTY_SETTINGS), new NoneQueryParserCache());
}
@Inject public NodeCache(Settings settings, ByteBufferCache byteBufferCache, QueryParserCache queryParserCache) {
super(settings);
this.byteBufferCache = byteBufferCache;
this.queryParserCache = queryParserCache;
}
public void close() {
@ -43,4 +53,8 @@ public class NodeCache extends AbstractComponent {
public ByteBufferCache byteBuffer() {
return byteBufferCache;
}
public QueryParserCache queryParser() {
return queryParserCache;
}
}

View File

@ -20,15 +20,25 @@
package org.elasticsearch.cache;
import org.elasticsearch.cache.memory.ByteBufferCache;
import org.elasticsearch.cache.query.parser.QueryParserCacheModule;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.settings.Settings;
/**
* @author kimchy (shay.banon)
*/
public class NodeCacheModule extends AbstractModule {
private final Settings settings;
public NodeCacheModule(Settings settings) {
this.settings = settings;
}
@Override protected void configure() {
bind(NodeCache.class).asEagerSingleton();
bind(ByteBufferCache.class).asEagerSingleton();
new QueryParserCacheModule(settings).configure(binder());
}
}

View File

@ -0,0 +1,32 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.elasticsearch.cache.query.parser;
import org.apache.lucene.search.Query;
/**
* @author kimchy (shay.banon)
*/
public interface QueryParserCache {
Query get(String queryString);
void put(String queryString, Query query);
}

View File

@ -0,0 +1,43 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.elasticsearch.cache.query.parser;
import org.elasticsearch.cache.query.parser.weak.WeakQueryParserCache;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.inject.Scopes;
import org.elasticsearch.common.settings.Settings;
/**
* @author kimchy (shay.banon)
*/
public class QueryParserCacheModule extends AbstractModule {
private final Settings settings;
public QueryParserCacheModule(Settings settings) {
this.settings = settings;
}
@Override protected void configure() {
bind(QueryParserCache.class)
.to(settings.getAsClass("cache.query.parser.type", WeakQueryParserCache.class, "org.elasticsearch.cache.query.parser.", "QueryParserCache"))
.in(Scopes.SINGLETON);
}
}

View File

@ -0,0 +1,40 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.elasticsearch.cache.query.parser.none;
import org.apache.lucene.search.Query;
import org.elasticsearch.cache.query.parser.QueryParserCache;
import org.elasticsearch.common.inject.Inject;
/**
* @author kimchy (shay.banon)
*/
public class NoneQueryParserCache implements QueryParserCache {
@Inject public NoneQueryParserCache() {
}
@Override public Query get(String queryString) {
return null;
}
@Override public void put(String queryString, Query query) {
}
}

View File

@ -0,0 +1,36 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.elasticsearch.cache.query.parser.soft;
import org.apache.lucene.search.Query;
import org.elasticsearch.cache.query.parser.support.AbstractJvmQueryParserCache;
import org.elasticsearch.common.collect.MapMaker;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
/**
* @author kimchy (shay.banon)
*/
public class SoftQueryParserCache extends AbstractJvmQueryParserCache {
@Inject public SoftQueryParserCache(Settings settings) {
super(settings, new MapMaker().softValues().<String, Query>makeMap());
}
}

View File

@ -0,0 +1,48 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.elasticsearch.cache.query.parser.support;
import org.apache.lucene.search.Query;
import org.elasticsearch.cache.query.parser.QueryParserCache;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.settings.Settings;
import java.util.concurrent.ConcurrentMap;
/**
* @author kimchy (shay.banon)
*/
public class AbstractJvmQueryParserCache extends AbstractComponent implements QueryParserCache {
final ConcurrentMap<String, Query> cache;
protected AbstractJvmQueryParserCache(Settings settings, ConcurrentMap<String, Query> cache) {
super(settings);
this.cache = cache;
}
@Override public Query get(String queryString) {
return cache.get(queryString);
}
@Override public void put(String queryString, Query query) {
cache.put(queryString, query);
}
}

View File

@ -0,0 +1,36 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.elasticsearch.cache.query.parser.weak;
import org.apache.lucene.search.Query;
import org.elasticsearch.cache.query.parser.support.AbstractJvmQueryParserCache;
import org.elasticsearch.common.collect.MapMaker;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
/**
* @author kimchy (shay.banon)
*/
public class WeakQueryParserCache extends AbstractJvmQueryParserCache {
@Inject public WeakQueryParserCache(Settings settings) {
super(settings, new MapMaker().weakValues().<String, Query>makeMap());
}
}

View File

@ -19,10 +19,10 @@
package org.elasticsearch.index.query.xcontent;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.queryParser.MapperQueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.queryParser.QueryParserSettings;
import org.apache.lucene.search.Query;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
@ -31,7 +31,6 @@ import org.elasticsearch.index.AbstractIndexComponent;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.analysis.AnalysisService;
import org.elasticsearch.index.query.QueryParsingException;
import org.elasticsearch.index.query.support.MapperQueryParser;
import org.elasticsearch.index.settings.IndexSettings;
import java.io.IOException;
@ -63,17 +62,8 @@ public class FieldQueryParser extends AbstractIndexComponent implements XContent
assert token == XContentParser.Token.FIELD_NAME;
String fieldName = parser.currentName();
String queryString = null;
float boost = 1.0f;
MapperQueryParser.Operator defaultOperator = QueryParser.Operator.OR;
boolean allowLeadingWildcard = true;
boolean lowercaseExpandedTerms = true;
boolean enablePositionIncrements = true;
int phraseSlop = 0;
float fuzzyMinSim = FuzzyQuery.defaultMinSimilarity;
int fuzzyPrefixLength = FuzzyQuery.defaultPrefixLength;
boolean escape = false;
Analyzer analyzer = null;
QueryParserSettings qpSettings = new QueryParserSettings();
qpSettings.defaultField(fieldName);
token = parser.nextToken();
if (token == XContentParser.Token.START_OBJECT) {
String currentFieldName = null;
@ -82,71 +72,64 @@ public class FieldQueryParser extends AbstractIndexComponent implements XContent
currentFieldName = parser.currentName();
} else if (token.isValue()) {
if ("query".equals(currentFieldName)) {
queryString = parser.text();
qpSettings.queryString(parser.text());
} else if ("boost".equals(currentFieldName)) {
boost = parser.floatValue();
qpSettings.boost(parser.floatValue());
} else if ("enable_position_increments".equals(currentFieldName) || "enablePositionIncrements".equals(currentFieldName)) {
enablePositionIncrements = parser.booleanValue();
qpSettings.enablePositionIncrements(parser.booleanValue());
} else if ("allow_leading_wildcard".equals(currentFieldName) || "allowLeadingWildcard".equals(currentFieldName)) {
allowLeadingWildcard = parser.booleanValue();
qpSettings.allowLeadingWildcard(parser.booleanValue());
} else if ("lowercase_expanded_terms".equals(currentFieldName) || "lowercaseExpandedTerms".equals(currentFieldName)) {
lowercaseExpandedTerms = parser.booleanValue();
qpSettings.lowercaseExpandedTerms(parser.booleanValue());
} else if ("phrase_slop".equals(currentFieldName) || "phraseSlop".equals(currentFieldName)) {
phraseSlop = parser.intValue();
qpSettings.phraseSlop(parser.intValue());
} else if ("analyzer".equals(currentFieldName)) {
analyzer = analysisService.analyzer(parser.text());
qpSettings.analyzer(analysisService.analyzer(parser.text()));
} else if ("default_operator".equals(currentFieldName) || "defaultOperator".equals(currentFieldName)) {
String op = parser.text();
if ("or".equalsIgnoreCase(op)) {
defaultOperator = QueryParser.Operator.OR;
qpSettings.defaultOperator(QueryParser.Operator.OR);
} else if ("and".equalsIgnoreCase(op)) {
defaultOperator = QueryParser.Operator.AND;
qpSettings.defaultOperator(QueryParser.Operator.AND);
} else {
throw new QueryParsingException(index, "Query default operator [" + op + "] is not allowed");
}
} else if ("fuzzy_min_sim".equals(currentFieldName) || "fuzzyMinSim".equals(currentFieldName)) {
fuzzyMinSim = parser.floatValue();
qpSettings.fuzzyMinSim(parser.floatValue());
} else if ("fuzzy_prefix_length".equals(currentFieldName) || "fuzzyPrefixLength".equals(currentFieldName)) {
fuzzyPrefixLength = parser.intValue();
qpSettings.fuzzyPrefixLength(parser.intValue());
} else if ("escape".equals(currentFieldName)) {
escape = parser.booleanValue();
qpSettings.escape(parser.booleanValue());
}
}
}
parser.nextToken();
} else {
queryString = parser.text();
qpSettings.queryString(parser.text());
// move to the next token
parser.nextToken();
}
if (analyzer == null) {
analyzer = parseContext.mapperService().searchAnalyzer();
if (qpSettings.analyzer() == null) {
qpSettings.analyzer(parseContext.mapperService().searchAnalyzer());
}
if (queryString == null) {
if (qpSettings.queryString() == null) {
throw new QueryParsingException(index, "No value specified for term query");
}
MapperQueryParser queryParser = new MapperQueryParser(fieldName, analyzer, parseContext);
queryParser.setEnablePositionIncrements(enablePositionIncrements);
queryParser.setAllowLeadingWildcard(allowLeadingWildcard);
queryParser.setLowercaseExpandedTerms(lowercaseExpandedTerms);
queryParser.setPhraseSlop(phraseSlop);
queryParser.setDefaultOperator(defaultOperator);
queryParser.setFuzzyMinSim(fuzzyMinSim);
queryParser.setFuzzyPrefixLength(fuzzyPrefixLength);
if (escape) {
queryString = QueryParser.escape(queryString);
if (qpSettings.escape()) {
qpSettings.queryString(QueryParser.escape(qpSettings.queryString()));
}
MapperQueryParser queryParser = parseContext.queryParser(qpSettings);
try {
Query query = queryParser.parse(queryString);
query.setBoost(boost);
Query query = queryParser.parse(qpSettings.queryString());
query.setBoost(qpSettings.boost());
return optimizeQuery(fixNegativeQueryIfNeeded(query));
} catch (ParseException e) {
throw new QueryParsingException(index, "Failed to parse query [" + queryString + "]", e);
throw new QueryParsingException(index, "Failed to parse query [" + qpSettings.queryString() + "]", e);
}
}
}

View File

@ -19,6 +19,10 @@
package org.elasticsearch.index.query.xcontent;
import org.apache.lucene.queryParser.MapperQueryParser;
import org.apache.lucene.queryParser.MultiFieldMapperQueryParser;
import org.apache.lucene.queryParser.MultiFieldQueryParserSettings;
import org.apache.lucene.queryParser.QueryParserSettings;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Similarity;
@ -60,6 +64,10 @@ public class QueryParseContext {
private final Map<String, Filter> namedFilters = Maps.newHashMap();
private final MapperQueryParser queryParser = new MapperQueryParser(this);
private final MultiFieldMapperQueryParser multiFieldQueryParser = new MultiFieldMapperQueryParser(this);
private XContentParser parser;
public QueryParseContext(Index index, XContentQueryParserRegistry queryParserRegistry,
@ -108,6 +116,16 @@ public class QueryParseContext {
return indexCache;
}
public MapperQueryParser queryParser(QueryParserSettings settings) {
queryParser.reset(settings);
return queryParser;
}
public MultiFieldMapperQueryParser queryParser(MultiFieldQueryParserSettings settings) {
multiFieldQueryParser.reset(settings);
return multiFieldQueryParser;
}
public Filter cacheFilterIfPossible(Filter filter) {
return indexCache.filter().cache(filter);
}

View File

@ -19,10 +19,10 @@
package org.elasticsearch.index.query.xcontent;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.queryParser.MapperQueryParser;
import org.apache.lucene.queryParser.MultiFieldQueryParserSettings;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.Query;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.Lists;
@ -35,12 +35,9 @@ import org.elasticsearch.index.Index;
import org.elasticsearch.index.analysis.AnalysisService;
import org.elasticsearch.index.mapper.AllFieldMapper;
import org.elasticsearch.index.query.QueryParsingException;
import org.elasticsearch.index.query.support.MapperQueryParser;
import org.elasticsearch.index.query.support.MultiFieldMapperQueryParser;
import org.elasticsearch.index.settings.IndexSettings;
import java.io.IOException;
import java.util.List;
import static org.elasticsearch.common.lucene.search.Queries.*;
@ -65,24 +62,8 @@ public class QueryStringQueryParser extends AbstractIndexComponent implements XC
@Override public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
XContentParser parser = parseContext.parser();
// move to the field value
String queryString = null;
String defaultField = AllFieldMapper.NAME; // default to all
MapperQueryParser.Operator defaultOperator = QueryParser.Operator.OR;
boolean allowLeadingWildcard = true;
boolean lowercaseExpandedTerms = true;
boolean enablePositionIncrements = true;
float fuzzyMinSim = FuzzyQuery.defaultMinSimilarity;
int fuzzyPrefixLength = FuzzyQuery.defaultPrefixLength;
int phraseSlop = 0;
float boost = 1.0f;
boolean escape = false;
Analyzer analyzer = null;
List<String> fields = null;
ExtTObjectFloatHashMap<String> boosts = null;
float tieBreaker = 0.0f;
boolean useDisMax = true;
MultiFieldQueryParserSettings qpSettings = new MultiFieldQueryParserSettings();
qpSettings.defaultField(AllFieldMapper.NAME);
String currentFieldName = null;
XContentParser.Token token;
@ -107,95 +88,87 @@ public class QueryStringQueryParser extends AbstractIndexComponent implements XC
if (fField == null) {
fField = parser.text();
}
if (fields == null) {
fields = Lists.newArrayList();
if (qpSettings.fields() == null) {
qpSettings.fields(Lists.<String>newArrayList());
}
fields.add(fField);
qpSettings.fields().add(fField);
if (fBoost != -1) {
if (boosts == null) {
boosts = new ExtTObjectFloatHashMap<String>();
if (qpSettings.boosts() == null) {
qpSettings.boosts(new ExtTObjectFloatHashMap<String>().defaultReturnValue(1.0f));
}
boosts.put(fField, fBoost);
qpSettings.boosts().put(fField, fBoost);
}
}
}
} else if (token.isValue()) {
if ("query".equals(currentFieldName)) {
queryString = parser.text();
qpSettings.queryString(parser.text());
} else if ("default_field".equals(currentFieldName) || "defaultField".equals(currentFieldName)) {
defaultField = parseContext.indexName(parser.text());
qpSettings.defaultField(parseContext.indexName(parser.text()));
} else if ("default_operator".equals(currentFieldName) || "defaultOperator".equals(currentFieldName)) {
String op = parser.text();
if ("or".equalsIgnoreCase(op)) {
defaultOperator = QueryParser.Operator.OR;
qpSettings.defaultOperator(QueryParser.Operator.OR);
} else if ("and".equalsIgnoreCase(op)) {
defaultOperator = QueryParser.Operator.AND;
qpSettings.defaultOperator(QueryParser.Operator.AND);
} else {
throw new QueryParsingException(index, "Query default operator [" + op + "] is not allowed");
}
} else if ("analyzer".equals(currentFieldName)) {
analyzer = analysisService.analyzer(parser.text());
qpSettings.analyzer(analysisService.analyzer(parser.text()));
} else if ("allow_leading_wildcard".equals(currentFieldName) || "allowLeadingWildcard".equals(currentFieldName)) {
allowLeadingWildcard = parser.booleanValue();
qpSettings.allowLeadingWildcard(parser.booleanValue());
} else if ("lowercase_expanded_terms".equals(currentFieldName) || "lowercaseExpandedTerms".equals(currentFieldName)) {
lowercaseExpandedTerms = parser.booleanValue();
qpSettings.lowercaseExpandedTerms(parser.booleanValue());
} else if ("enable_position_increments".equals(currentFieldName) || "enablePositionIncrements".equals(currentFieldName)) {
enablePositionIncrements = parser.booleanValue();
qpSettings.enablePositionIncrements(parser.booleanValue());
} else if ("escape".equals(currentFieldName)) {
escape = parser.booleanValue();
qpSettings.escape(parser.booleanValue());
} else if ("use_dis_max".equals(currentFieldName) || "useDisMax".equals(currentFieldName)) {
useDisMax = parser.booleanValue();
qpSettings.useDisMax(parser.booleanValue());
} else if ("fuzzy_prefix_length".equals(currentFieldName) || "fuzzyPrefixLength".equals(currentFieldName)) {
fuzzyPrefixLength = parser.intValue();
qpSettings.fuzzyPrefixLength(parser.intValue());
} else if ("phrase_slop".equals(currentFieldName) || "phraseSlop".equals(currentFieldName)) {
phraseSlop = parser.intValue();
qpSettings.phraseSlop(parser.intValue());
} else if ("fuzzy_min_sim".equals(currentFieldName) || "fuzzyMinSim".equals(currentFieldName)) {
fuzzyMinSim = parser.floatValue();
qpSettings.fuzzyMinSim(parser.floatValue());
} else if ("boost".equals(currentFieldName)) {
boost = parser.floatValue();
qpSettings.boost(parser.floatValue());
} else if ("tie_breaker".equals(currentFieldName) || "tieBreaker".equals(currentFieldName)) {
tieBreaker = parser.floatValue();
qpSettings.tieBreaker(parser.floatValue());
}
}
}
if (queryString == null) {
if (qpSettings.queryString() == null) {
throw new QueryParsingException(index, "query_string must be provided with a [query]");
}
if (analyzer == null) {
analyzer = parseContext.mapperService().searchAnalyzer();
if (qpSettings.analyzer() == null) {
qpSettings.analyzer(parseContext.mapperService().searchAnalyzer());
}
if (qpSettings.escape()) {
qpSettings.queryString(QueryParser.escape(qpSettings.queryString()));
}
MapperQueryParser queryParser;
if (fields != null) {
if (fields.size() == 1) {
queryParser = new MapperQueryParser(fields.get(0), analyzer, parseContext);
if (qpSettings.fields() != null) {
if (qpSettings.fields().size() == 1) {
qpSettings.defaultField(qpSettings.fields().get(0));
queryParser = parseContext.queryParser(qpSettings);
} else {
MultiFieldMapperQueryParser mQueryParser = new MultiFieldMapperQueryParser(fields, boosts, analyzer, parseContext);
mQueryParser.setTieBreaker(tieBreaker);
mQueryParser.setUseDisMax(useDisMax);
queryParser = mQueryParser;
qpSettings.defaultField(null); // reset defaultField when using multi query parser
queryParser = parseContext.queryParser(qpSettings);
}
} else {
queryParser = new MapperQueryParser(defaultField, analyzer, parseContext);
}
queryParser.setEnablePositionIncrements(enablePositionIncrements);
queryParser.setLowercaseExpandedTerms(lowercaseExpandedTerms);
queryParser.setAllowLeadingWildcard(allowLeadingWildcard);
queryParser.setDefaultOperator(defaultOperator);
queryParser.setFuzzyMinSim(fuzzyMinSim);
queryParser.setFuzzyPrefixLength(fuzzyPrefixLength);
queryParser.setPhraseSlop(phraseSlop);
if (escape) {
queryString = QueryParser.escape(queryString);
queryParser = parseContext.queryParser(qpSettings);
}
try {
Query query = queryParser.parse(queryString);
query.setBoost(boost);
Query query = queryParser.parse(qpSettings.queryString());
query.setBoost(qpSettings.boost());
return optimizeQuery(fixNegativeQueryIfNeeded(query));
} catch (ParseException e) {
throw new QueryParsingException(index, "Failed to parse query [" + queryString + "]", e);
throw new QueryParsingException(index, "Failed to parse query [" + qpSettings.queryString() + "]", e);
}
}
}

View File

@ -19,10 +19,12 @@
package org.elasticsearch.indexer;
import java.io.Serializable;
/**
* @author kimchy (shay.banon)
*/
public class IndexerName {
public class IndexerName implements Serializable {
private final String type;

View File

@ -119,7 +119,7 @@ public final class InternalNode implements Node {
modules.add(new SettingsModule(settings));
modules.add(new NodeModule(this));
modules.add(new NetworkModule());
modules.add(new NodeCacheModule());
modules.add(new NodeCacheModule(settings));
modules.add(new ScriptModule());
modules.add(new JmxModule(settings));
modules.add(new EnvironmentModule(environment));