diff --git a/core/src/main/java/org/apache/lucene/queryparser/classic/ExistsFieldQueryExtension.java b/core/src/main/java/org/apache/lucene/queryparser/classic/ExistsFieldQueryExtension.java index 6cac629796f..ab924770688 100644 --- a/core/src/main/java/org/apache/lucene/queryparser/classic/ExistsFieldQueryExtension.java +++ b/core/src/main/java/org/apache/lucene/queryparser/classic/ExistsFieldQueryExtension.java @@ -21,7 +21,7 @@ package org.apache.lucene.queryparser.classic; import org.apache.lucene.search.ConstantScoreQuery; import org.apache.lucene.search.Query; -import org.elasticsearch.index.query.ExistsQueryParser; +import org.elasticsearch.index.query.ExistsQueryBuilder; import org.elasticsearch.index.query.QueryParseContext; /** @@ -33,6 +33,6 @@ public class ExistsFieldQueryExtension implements FieldQueryExtension { @Override public Query query(QueryParseContext parseContext, String queryText) { - return new ConstantScoreQuery(ExistsQueryParser.newFilter(parseContext, queryText, null)); + return new ConstantScoreQuery(ExistsQueryBuilder.newFilter(parseContext, queryText, null)); } } diff --git a/core/src/main/java/org/elasticsearch/index/query/ExistsQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/ExistsQueryBuilder.java index f59b861a9e6..c6923d1df6c 100644 --- a/core/src/main/java/org/elasticsearch/index/query/ExistsQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/ExistsQueryBuilder.java @@ -19,18 +19,31 @@ package org.elasticsearch.index.query; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.ConstantScoreQuery; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.TermRangeQuery; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.index.mapper.MappedFieldType; +import org.elasticsearch.index.mapper.MapperService; +import org.elasticsearch.index.mapper.internal.FieldNamesFieldMapper; import java.io.IOException; +import java.util.Collection; +import java.util.Objects; /** * Constructs a query that only match on documents that the field has a value in them. */ -public class ExistsQueryBuilder extends QueryBuilder { +public class ExistsQueryBuilder extends QueryBuilder { public static final String NAME = "exists"; - private String name; + private final String name; private String queryName; @@ -40,6 +53,13 @@ public class ExistsQueryBuilder extends QueryBuilder { this.name = name; } + /** + * @return the field name that has to exist for this query to match + */ + public String name() { + return this.name; + } + /** * Sets the query name for the query that can be used when searching for matched_queries per hit. */ @@ -48,6 +68,13 @@ public class ExistsQueryBuilder extends QueryBuilder { return this; } + /** + * @return the query name for the query that can be used when searching for matched_queries per hit. + */ + public String queryName() { + return this.queryName; + } + @Override protected void doXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(NAME); @@ -58,6 +85,91 @@ public class ExistsQueryBuilder extends QueryBuilder { builder.endObject(); } + + @Override + public Query toQuery(QueryParseContext parseContext) throws QueryParsingException, IOException { + return newFilter(parseContext, name, queryName); + } + + public static Query newFilter(QueryParseContext parseContext, String fieldPattern, String queryName) { + final FieldNamesFieldMapper.FieldNamesFieldType fieldNamesFieldType = (FieldNamesFieldMapper.FieldNamesFieldType)parseContext.mapperService().fullName(FieldNamesFieldMapper.NAME); + if (fieldNamesFieldType == null) { + // can only happen when no types exist, so no docs exist either + return Queries.newMatchNoDocsQuery(); + } + + MapperService.SmartNameObjectMapper smartNameObjectMapper = parseContext.smartObjectMapper(fieldPattern); + if (smartNameObjectMapper != null && smartNameObjectMapper.hasMapper()) { + // automatic make the object mapper pattern + fieldPattern = fieldPattern + ".*"; + } + + Collection fields = parseContext.simpleMatchToIndexNames(fieldPattern); + if (fields.isEmpty()) { + // no fields exists, so we should not match anything + return Queries.newMatchNoDocsQuery(); + } + + BooleanQuery boolFilter = new BooleanQuery(); + for (String field : fields) { + MappedFieldType fieldType = parseContext.fieldMapper(field); + Query filter = null; + if (fieldNamesFieldType.isEnabled()) { + final String f; + if (fieldType != null) { + f = fieldType.names().indexName(); + } else { + f = field; + } + filter = fieldNamesFieldType.termQuery(f, parseContext); + } + // if _field_names are not indexed, we need to go the slow way + if (filter == null && fieldType != null) { + filter = fieldType.rangeQuery(null, null, true, true, parseContext); + } + if (filter == null) { + filter = new TermRangeQuery(field, null, null, true, true); + } + boolFilter.add(filter, BooleanClause.Occur.SHOULD); + } + + if (queryName != null) { + parseContext.addNamedQuery(queryName, boolFilter); + } + return new ConstantScoreQuery(boolFilter); + } + + @Override + public int hashCode() { + return Objects.hash(name, queryName); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + ExistsQueryBuilder other = (ExistsQueryBuilder) obj; + return Objects.equals(name, other.name) && + Objects.equals(queryName, other.queryName); + } + + @Override + public ExistsQueryBuilder readFrom(StreamInput in) throws IOException { + ExistsQueryBuilder newQuery = new ExistsQueryBuilder(in.readString()); + newQuery.queryName = in.readOptionalString(); + return newQuery; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeString(name); + out.writeOptionalString(queryName); + } + @Override public String queryId() { return NAME; diff --git a/core/src/main/java/org/elasticsearch/index/query/ExistsQueryParser.java b/core/src/main/java/org/elasticsearch/index/query/ExistsQueryParser.java index c7eda929003..640f9ef25e7 100644 --- a/core/src/main/java/org/elasticsearch/index/query/ExistsQueryParser.java +++ b/core/src/main/java/org/elasticsearch/index/query/ExistsQueryParser.java @@ -19,22 +19,15 @@ package org.elasticsearch.index.query; -import org.apache.lucene.search.*; import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.index.mapper.FieldMapper; -import org.elasticsearch.index.mapper.MappedFieldType; -import org.elasticsearch.index.mapper.MapperService; -import org.elasticsearch.index.mapper.internal.FieldNamesFieldMapper; import java.io.IOException; -import java.util.Collection; /** * */ -public class ExistsQueryParser extends BaseQueryParserTemp { +public class ExistsQueryParser extends BaseQueryParser { @Inject public ExistsQueryParser() { @@ -46,7 +39,7 @@ public class ExistsQueryParser extends BaseQueryParserTemp { } @Override - public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException { + public QueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, QueryParsingException { XContentParser parser = parseContext.parser(); String fieldPattern = null; @@ -72,60 +65,14 @@ public class ExistsQueryParser extends BaseQueryParserTemp { throw new QueryParsingException(parseContext, "exists must be provided with a [field]"); } - return newFilter(parseContext, fieldPattern, queryName); - } - - public static Query newFilter(QueryParseContext parseContext, String fieldPattern, String queryName) { - final FieldNamesFieldMapper.FieldNamesFieldType fieldNamesFieldType = (FieldNamesFieldMapper.FieldNamesFieldType)parseContext.mapperService().fullName(FieldNamesFieldMapper.NAME); - if (fieldNamesFieldType == null) { - // can only happen when no types exist, so no docs exist either - return Queries.newMatchNoDocsQuery(); - } - - MapperService.SmartNameObjectMapper smartNameObjectMapper = parseContext.smartObjectMapper(fieldPattern); - if (smartNameObjectMapper != null && smartNameObjectMapper.hasMapper()) { - // automatic make the object mapper pattern - fieldPattern = fieldPattern + ".*"; - } - - Collection fields = parseContext.simpleMatchToIndexNames(fieldPattern); - if (fields.isEmpty()) { - // no fields exists, so we should not match anything - return Queries.newMatchNoDocsQuery(); - } - - BooleanQuery boolFilter = new BooleanQuery(); - for (String field : fields) { - MappedFieldType fieldType = parseContext.fieldMapper(field); - Query filter = null; - if (fieldNamesFieldType.isEnabled()) { - final String f; - if (fieldType != null) { - f = fieldType.names().indexName(); - } else { - f = field; - } - filter = fieldNamesFieldType.termQuery(f, parseContext); - } - // if _field_names are not indexed, we need to go the slow way - if (filter == null && fieldType != null) { - filter = fieldType.rangeQuery(null, null, true, true, parseContext); - } - if (filter == null) { - filter = new TermRangeQuery(field, null, null, true, true); - } - boolFilter.add(filter, BooleanClause.Occur.SHOULD); - } - - if (queryName != null) { - parseContext.addNamedQuery(queryName, boolFilter); - } - return new ConstantScoreQuery(boolFilter); + ExistsQueryBuilder builder = new ExistsQueryBuilder(fieldPattern); + builder.queryName(queryName); + builder.validate(); + return builder; } @Override public ExistsQueryBuilder getBuilderPrototype() { return ExistsQueryBuilder.PROTOTYPE; } - } diff --git a/core/src/main/java/org/elasticsearch/index/query/GeoShapeQueryParser.java b/core/src/main/java/org/elasticsearch/index/query/GeoShapeQueryParser.java index 60caefa9899..fe44c1f03c7 100644 --- a/core/src/main/java/org/elasticsearch/index/query/GeoShapeQueryParser.java +++ b/core/src/main/java/org/elasticsearch/index/query/GeoShapeQueryParser.java @@ -158,7 +158,7 @@ public class GeoShapeQueryParser extends BaseQueryParserTemp { // this strategy doesn't support disjoint anymore: but it did before, including creating lucene fieldcache (!) // in this case, execute disjoint as exists && !intersects BooleanQuery bool = new BooleanQuery(); - Query exists = ExistsQueryParser.newFilter(parseContext, fieldName, null); + Query exists = ExistsQueryBuilder.newFilter(parseContext, fieldName, null); Filter intersects = strategy.makeFilter(getArgs(shape, ShapeRelation.INTERSECTS)); bool.add(exists, BooleanClause.Occur.MUST); bool.add(intersects, BooleanClause.Occur.MUST_NOT); diff --git a/core/src/test/java/org/elasticsearch/index/query/BaseQueryTestCase.java b/core/src/test/java/org/elasticsearch/index/query/BaseQueryTestCase.java index a6e9269c991..8710af2ff4e 100644 --- a/core/src/test/java/org/elasticsearch/index/query/BaseQueryTestCase.java +++ b/core/src/test/java/org/elasticsearch/index/query/BaseQueryTestCase.java @@ -57,6 +57,7 @@ import org.elasticsearch.script.ScriptModule; import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.test.ElasticsearchTestCase; import org.elasticsearch.test.TestSearchContext; +import org.elasticsearch.test.VersionUtils; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPoolModule; import org.junit.After; @@ -75,11 +76,14 @@ import static org.hamcrest.Matchers.is; @Ignore public abstract class BaseQueryTestCase> extends ElasticsearchTestCase { + protected static final String OBJECT_FIELD_NAME = "object"; protected static final String DATE_FIELD_NAME = "age"; protected static final String INT_FIELD_NAME = "price"; protected static final String STRING_FIELD_NAME = "text"; protected static final String DOUBLE_FIELD_NAME = "double"; protected static final String BOOLEAN_FIELD_NAME = "boolean"; + protected static final String[] mappedFieldNames = new String[] { DATE_FIELD_NAME, INT_FIELD_NAME, STRING_FIELD_NAME, + DOUBLE_FIELD_NAME, BOOLEAN_FIELD_NAME, OBJECT_FIELD_NAME }; private static Injector injector; private static IndexQueryParserService queryParserService; @@ -102,7 +106,8 @@ public abstract class BaseQueryTestCase> extends Ela Settings settings = Settings.settingsBuilder() .put("name", BaseQueryTestCase.class.toString()) .put("path.home", createTempDir()) - .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT) + .put(IndexMetaData.SETTING_VERSION_CREATED, VersionUtils.randomVersionBetween(random(), + Version.V_1_0_0, Version.CURRENT)) .build(); index = new Index("test"); @@ -138,7 +143,10 @@ public abstract class BaseQueryTestCase> extends Ela INT_FIELD_NAME, "type=integer", DOUBLE_FIELD_NAME, "type=double", BOOLEAN_FIELD_NAME, "type=boolean", - STRING_FIELD_NAME, "type=string").string()), false); + STRING_FIELD_NAME, "type=string", + OBJECT_FIELD_NAME, "type=object", + OBJECT_FIELD_NAME+"."+DATE_FIELD_NAME, "type=date", + OBJECT_FIELD_NAME+"."+INT_FIELD_NAME, "type=integer").string()), false); currentTypes[i] = type; } namedWriteableRegistry = injector.getInstance(NamedWriteableRegistry.class); @@ -165,7 +173,7 @@ public abstract class BaseQueryTestCase> extends Ela } } else { if (randomBoolean()) { - types = new String[]{MetaData.ALL}; + types = new String[] { MetaData.ALL }; } else { types = new String[0]; } @@ -192,11 +200,6 @@ public abstract class BaseQueryTestCase> extends Ela */ protected abstract QB createTestQueryBuilder(); - /** - * Creates an empty builder of the type of query under test - */ - protected abstract QB createEmptyQueryBuilder(); - /** * Generic test that creates new query from the test query and checks both for equality * and asserts equality on the two queries. @@ -259,7 +262,8 @@ public abstract class BaseQueryTestCase> extends Ela try (BytesStreamOutput output = new BytesStreamOutput()) { testQuery.writeTo(output); try (StreamInput in = new FilterStreamInput(StreamInput.wrap(output.bytes()), namedWriteableRegistry)) { - QB deserializedQuery = createEmptyQueryBuilder().readFrom(in); + QueryBuilder prototype = queryParserService.queryParser(testQuery.queryId()).getBuilderPrototype(); + QueryBuilder deserializedQuery = prototype.readFrom(in); assertEquals(deserializedQuery, testQuery); assertEquals(deserializedQuery.hashCode(), testQuery.hashCode()); assertNotSame(deserializedQuery, testQuery); diff --git a/core/src/test/java/org/elasticsearch/index/query/BoolQueryBuilderTest.java b/core/src/test/java/org/elasticsearch/index/query/BoolQueryBuilderTest.java index d362a0d783a..b55c822185f 100644 --- a/core/src/test/java/org/elasticsearch/index/query/BoolQueryBuilderTest.java +++ b/core/src/test/java/org/elasticsearch/index/query/BoolQueryBuilderTest.java @@ -83,11 +83,6 @@ public class BoolQueryBuilderTest extends BaseQueryTestCase { return query; } - @Override - protected BoolQueryBuilder createEmptyQueryBuilder() { - return new BoolQueryBuilder(); - } - @Override protected Query createExpectedQuery(BoolQueryBuilder queryBuilder, QueryParseContext context) throws IOException { if (!queryBuilder.hasClauses()) { diff --git a/core/src/test/java/org/elasticsearch/index/query/ExistsQueryBuilderTest.java b/core/src/test/java/org/elasticsearch/index/query/ExistsQueryBuilderTest.java new file mode 100644 index 00000000000..0f292ce5188 --- /dev/null +++ b/core/src/test/java/org/elasticsearch/index/query/ExistsQueryBuilderTest.java @@ -0,0 +1,112 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.index.query; + +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.ConstantScoreQuery; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.TermRangeQuery; +import org.elasticsearch.cluster.metadata.MetaData; +import org.elasticsearch.common.lucene.search.Queries; +import org.elasticsearch.index.mapper.MappedFieldType; +import org.elasticsearch.index.mapper.internal.FieldNamesFieldMapper; + +import java.io.IOException; +import java.util.Collection; + +import static org.hamcrest.Matchers.equalTo; + +public class ExistsQueryBuilderTest extends BaseQueryTestCase { + + private Collection getFieldNamePattern(String fieldName, QueryParseContext context) { + if (getCurrentTypes().length > 0 && fieldName.equals(BaseQueryTestCase.OBJECT_FIELD_NAME)) { + // "object" field has two inner fields (age, price), so if query hits that field, we + // extend field name with wildcard to match both nested fields. This is similar to what + // is done internally in ExistsQueryBuilder.toQuery() + fieldName = fieldName + ".*"; + } + return context.simpleMatchToIndexNames(fieldName); + } + + @Override + protected Query createExpectedQuery(ExistsQueryBuilder queryBuilder, QueryParseContext context) throws IOException { + final FieldNamesFieldMapper.FieldNamesFieldType fieldNamesFieldType = (FieldNamesFieldMapper.FieldNamesFieldType)context.mapperService().fullName(FieldNamesFieldMapper.NAME); + Collection fields = getFieldNamePattern(queryBuilder.name(), context); + + if (fields.isEmpty() || fieldNamesFieldType == null) { + return Queries.newMatchNoDocsQuery(); + } + + BooleanQuery boolFilter = new BooleanQuery(); + for (String field : fields) { + if (fieldNamesFieldType != null && fieldNamesFieldType.isEnabled()) { + boolFilter.add(fieldNamesFieldType.termQuery(field, context), BooleanClause.Occur.SHOULD); + } else { + MappedFieldType fieldType = context.fieldMapper(field); + if (fieldType == null) { + boolFilter.add(new TermRangeQuery(field, null, null, true, true), BooleanClause.Occur.SHOULD); + } else { + boolFilter.add(fieldType.rangeQuery(null, null, true, true, context), BooleanClause.Occur.SHOULD); + } + } + } + return new ConstantScoreQuery(boolFilter); + } + + @Override + protected void assertLuceneQuery(ExistsQueryBuilder queryBuilder, Query query, QueryParseContext context) { + if (queryBuilder.queryName() != null) { + Query namedQuery = context.copyNamedFilters().get(queryBuilder.queryName()); + Collection fields = getFieldNamePattern(queryBuilder.name(), context); + + if (fields.isEmpty()) { + assertNull(namedQuery); + } else { + query = ((ConstantScoreQuery) query).getQuery(); + assertThat(namedQuery, equalTo(query)); + } + } + } + + @Override + protected ExistsQueryBuilder createTestQueryBuilder() { + String fieldPattern; + if (randomBoolean()) { + fieldPattern = randomFrom(mappedFieldNames); + } else { + fieldPattern = randomAsciiOfLengthBetween(1, 10); + } + // also sometimes test wildcard patterns + if (randomBoolean()) { + if (randomBoolean()) { + fieldPattern = fieldPattern + "*"; + } else { + fieldPattern = MetaData.ALL; + } + } + ExistsQueryBuilder query = new ExistsQueryBuilder(fieldPattern); + + if (randomBoolean()) { + query.queryName(randomAsciiOfLengthBetween(1, 10)); + } + return query; + } +} diff --git a/core/src/test/java/org/elasticsearch/index/query/IdsQueryBuilderTest.java b/core/src/test/java/org/elasticsearch/index/query/IdsQueryBuilderTest.java index ec96ef4f21f..bd420fc20e7 100644 --- a/core/src/test/java/org/elasticsearch/index/query/IdsQueryBuilderTest.java +++ b/core/src/test/java/org/elasticsearch/index/query/IdsQueryBuilderTest.java @@ -52,11 +52,6 @@ public class IdsQueryBuilderTest extends BaseQueryTestCase { context.indexQueryParserService().queryParser("ids").fromXContent(context); } - @Override - protected IdsQueryBuilder createEmptyQueryBuilder() { - return new IdsQueryBuilder(); - } - @Override protected Query createExpectedQuery(IdsQueryBuilder queryBuilder, QueryParseContext context) throws IOException { Query expectedQuery; diff --git a/core/src/test/java/org/elasticsearch/index/query/LimitQueryBuilderTest.java b/core/src/test/java/org/elasticsearch/index/query/LimitQueryBuilderTest.java index 985ce210de6..99255ec1cb7 100644 --- a/core/src/test/java/org/elasticsearch/index/query/LimitQueryBuilderTest.java +++ b/core/src/test/java/org/elasticsearch/index/query/LimitQueryBuilderTest.java @@ -30,11 +30,6 @@ public class LimitQueryBuilderTest extends BaseQueryTestCase return Queries.newMatchAllQuery(); } - @Override - protected LimitQueryBuilder createEmptyQueryBuilder() { - return new LimitQueryBuilder(0); - } - /** * @return a LimitQueryBuilder with random limit between 0 and 20 */ diff --git a/core/src/test/java/org/elasticsearch/index/query/MatchAllQueryBuilderTest.java b/core/src/test/java/org/elasticsearch/index/query/MatchAllQueryBuilderTest.java index fd29195f51c..de3734001d8 100644 --- a/core/src/test/java/org/elasticsearch/index/query/MatchAllQueryBuilderTest.java +++ b/core/src/test/java/org/elasticsearch/index/query/MatchAllQueryBuilderTest.java @@ -31,11 +31,6 @@ public class MatchAllQueryBuilderTest extends BaseQueryTestCase query.from(1).to(10).timeZone("UTC"); query.toQuery(createContext()); } - - @Override - protected RangeQueryBuilder createEmptyQueryBuilder() { - return new RangeQueryBuilder(null); - } } diff --git a/core/src/test/java/org/elasticsearch/index/query/SpanTermQueryBuilderTest.java b/core/src/test/java/org/elasticsearch/index/query/SpanTermQueryBuilderTest.java index 7aaa82b8cd2..60bd90bbc71 100644 --- a/core/src/test/java/org/elasticsearch/index/query/SpanTermQueryBuilderTest.java +++ b/core/src/test/java/org/elasticsearch/index/query/SpanTermQueryBuilderTest.java @@ -25,11 +25,6 @@ import org.apache.lucene.search.spans.SpanTermQuery; public class SpanTermQueryBuilderTest extends BaseTermQueryTestCase { - @Override - protected SpanTermQueryBuilder createEmptyQueryBuilder() { - return new SpanTermQueryBuilder(null, null); - } - @Override protected SpanTermQueryBuilder createQueryBuilder(String fieldName, Object value) { return new SpanTermQueryBuilder(fieldName, value); diff --git a/core/src/test/java/org/elasticsearch/index/query/TermQueryBuilderTest.java b/core/src/test/java/org/elasticsearch/index/query/TermQueryBuilderTest.java index ac5aefbb254..62002b6bf6d 100644 --- a/core/src/test/java/org/elasticsearch/index/query/TermQueryBuilderTest.java +++ b/core/src/test/java/org/elasticsearch/index/query/TermQueryBuilderTest.java @@ -25,11 +25,6 @@ import org.apache.lucene.search.TermQuery; public class TermQueryBuilderTest extends BaseTermQueryTestCase { - @Override - protected TermQueryBuilder createEmptyQueryBuilder() { - return new TermQueryBuilder(null, null); - } - /** * @return a TermQuery with random field name and value, optional random boost and queryname */