Merge remote-tracking branch 'dakrone/sqs-all-field-mode'

This commit is contained in:
Lee Hinman 2016-11-09 13:13:41 -07:00
commit 2674e415c8
8 changed files with 389 additions and 39 deletions

View File

@ -119,7 +119,7 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
private static final ParseField ALL_FIELDS_FIELD = new ParseField("all_fields");
// Mapping types the "all-ish" query can be executed against
private static final Set<String> ALLOWED_QUERY_MAPPER_TYPES;
public static final Set<String> ALLOWED_QUERY_MAPPER_TYPES;
static {
ALLOWED_QUERY_MAPPER_TYPES = new HashSet<>();
@ -908,7 +908,11 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
timeZone == null ? 0 : timeZone.getID(), escape, maxDeterminizedStates, splitOnWhitespace, useAllFields);
}
private Map<String, Float> allQueryableDefaultFields(QueryShardContext context) {
/**
* Given a shard context, return a map of all fields in the mappings that
* can be queried. The map will be field name to a float of 1.0f.
*/
public static Map<String, Float> allQueryableDefaultFields(QueryShardContext context) {
Collection<String> allFields = context.simpleMatchToIndexNames("*");
Map<String, Float> fields = new HashMap<>();
for (String fieldName : allFields) {
@ -943,6 +947,10 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
Map<String, Float> resolvedFields = new TreeMap<>();
if ((useAllFields != null && useAllFields) && (fieldsAndWeights.size() != 0 || this.defaultField != null)) {
throw addValidationError("cannot use [all_fields] parameter in conjunction with [default_field] or [fields]", null);
}
// If explicitly required to use all fields, use all fields, OR:
// Automatically determine the fields (to replace the _all field) if all of the following are true:
// - The _all field is disabled,

View File

@ -270,6 +270,12 @@ public class SimpleQueryParser extends org.apache.lucene.queryparser.simple.Simp
public Settings() {
}
public Settings(Settings other) {
this.lenient = other.lenient;
this.analyzeWildcard = other.analyzeWildcard;
this.quoteFieldSuffix = other.quoteFieldSuffix;
}
/** Specifies whether to use lenient parsing, defaults to false. */
public void lenient(boolean lenient) {
this.lenient = lenient;

View File

@ -106,6 +106,7 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
private static final ParseField QUERY_FIELD = new ParseField("query");
private static final ParseField FIELDS_FIELD = new ParseField("fields");
private static final ParseField QUOTE_FIELD_SUFFIX_FIELD = new ParseField("quote_field_suffix");
private static final ParseField ALL_FIELDS_FIELD = new ParseField("all_fields");
/** Query text to parse. */
private final String queryText;
@ -126,6 +127,8 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
private String minimumShouldMatch;
/** Any search flags to be used, ALL by default. */
private int flags = DEFAULT_FLAGS;
/** Flag specifying whether query should be forced to expand to all searchable fields */
private Boolean useAllFields;
/** Further search settings needed by the ES specific query string parser only. */
private Settings settings = new Settings();
@ -166,6 +169,7 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
minimumShouldMatch = in.readOptionalString();
if (in.getVersion().onOrAfter(V_5_1_0_UNRELEASED)) {
settings.quoteFieldSuffix(in.readOptionalString());
useAllFields = in.readOptionalBoolean();
}
}
@ -191,6 +195,7 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
out.writeOptionalString(minimumShouldMatch);
if (out.getVersion().onOrAfter(V_5_1_0_UNRELEASED)) {
out.writeOptionalString(settings.quoteFieldSuffix());
out.writeOptionalBoolean(useAllFields);
}
}
@ -240,6 +245,15 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
return this.analyzer;
}
public Boolean useAllFields() {
return useAllFields;
}
public SimpleQueryStringBuilder useAllFields(Boolean useAllFields) {
this.useAllFields = useAllFields;
return this;
}
/**
* Specify the default operator for the query. Defaults to "OR" if no
* operator is specified.
@ -341,17 +355,37 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
protected Query doToQuery(QueryShardContext context) throws IOException {
// field names in builder can have wildcards etc, need to resolve them here
Map<String, Float> resolvedFieldsAndWeights = new TreeMap<>();
// Use the default field if no fields specified
if (fieldsAndWeights.isEmpty()) {
resolvedFieldsAndWeights.put(resolveIndexName(context.defaultField(), context), AbstractQueryBuilder.DEFAULT_BOOST);
if ((useAllFields != null && useAllFields) && (fieldsAndWeights.size() != 0)) {
throw addValidationError("cannot use [all_fields] parameter in conjunction with [fields]", null);
}
// If explicitly required to use all fields, use all fields, OR:
// Automatically determine the fields (to replace the _all field) if all of the following are true:
// - The _all field is disabled,
// - and the default_field has not been changed in the settings
// - and no fields are specified in the request
Settings newSettings = new Settings(settings);
if ((this.useAllFields != null && this.useAllFields) ||
(context.getMapperService().allEnabled() == false &&
"_all".equals(context.defaultField()) &&
this.fieldsAndWeights.isEmpty())) {
resolvedFieldsAndWeights = QueryStringQueryBuilder.allQueryableDefaultFields(context);
// Need to use lenient mode when using "all-mode" so exceptions aren't thrown due to mismatched types
newSettings.lenient(true);
} else {
for (Map.Entry<String, Float> fieldEntry : fieldsAndWeights.entrySet()) {
if (Regex.isSimpleMatchPattern(fieldEntry.getKey())) {
for (String fieldName : context.getMapperService().simpleMatchToIndexNames(fieldEntry.getKey())) {
resolvedFieldsAndWeights.put(fieldName, fieldEntry.getValue());
// Use the default field if no fields specified
if (fieldsAndWeights.isEmpty()) {
resolvedFieldsAndWeights.put(resolveIndexName(context.defaultField(), context), AbstractQueryBuilder.DEFAULT_BOOST);
} else {
for (Map.Entry<String, Float> fieldEntry : fieldsAndWeights.entrySet()) {
if (Regex.isSimpleMatchPattern(fieldEntry.getKey())) {
for (String fieldName : context.getMapperService().simpleMatchToIndexNames(fieldEntry.getKey())) {
resolvedFieldsAndWeights.put(fieldName, fieldEntry.getValue());
}
} else {
resolvedFieldsAndWeights.put(resolveIndexName(fieldEntry.getKey(), context), fieldEntry.getValue());
}
} else {
resolvedFieldsAndWeights.put(resolveIndexName(fieldEntry.getKey(), context), fieldEntry.getValue());
}
}
}
@ -369,7 +403,7 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
}
SimpleQueryParser sqp = new SimpleQueryParser(luceneAnalyzer, resolvedFieldsAndWeights, flags, settings, context);
SimpleQueryParser sqp = new SimpleQueryParser(luceneAnalyzer, resolvedFieldsAndWeights, flags, newSettings, context);
sqp.setDefaultOperator(defaultOperator.toBooleanClauseOccur());
Query query = sqp.parse(queryText);
@ -419,6 +453,9 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
if (minimumShouldMatch != null) {
builder.field(MINIMUM_SHOULD_MATCH_FIELD.getPreferredName(), minimumShouldMatch);
}
if (useAllFields != null) {
builder.field(ALL_FIELDS_FIELD.getPreferredName(), useAllFields);
}
printBoostAndQueryName(builder);
builder.endObject();
@ -439,6 +476,7 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
boolean lenient = SimpleQueryStringBuilder.DEFAULT_LENIENT;
boolean analyzeWildcard = SimpleQueryStringBuilder.DEFAULT_ANALYZE_WILDCARD;
String quoteFieldSuffix = null;
Boolean useAllFields = null;
XContentParser.Token token;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
@ -502,6 +540,8 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
minimumShouldMatch = parser.textOrNull();
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, QUOTE_FIELD_SUFFIX_FIELD)) {
quoteFieldSuffix = parser.textOrNull();
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, ALL_FIELDS_FIELD)) {
useAllFields = parser.booleanValue();
} else {
throw new ParsingException(parser.getTokenLocation(), "[" + SimpleQueryStringBuilder.NAME +
"] unsupported field [" + parser.currentName() + "]");
@ -517,10 +557,16 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
throw new ParsingException(parser.getTokenLocation(), "[" + SimpleQueryStringBuilder.NAME + "] query text missing");
}
if ((useAllFields != null && useAllFields) && (fieldsAndWeights.size() != 0)) {
throw new ParsingException(parser.getTokenLocation(),
"cannot use [all_fields] parameter in conjunction with [fields]");
}
SimpleQueryStringBuilder qb = new SimpleQueryStringBuilder(queryBody);
qb.boost(boost).fields(fieldsAndWeights).analyzer(analyzerName).queryName(queryName).minimumShouldMatch(minimumShouldMatch);
qb.flags(flags).defaultOperator(defaultOperator);
qb.lenient(lenient).analyzeWildcard(analyzeWildcard).boost(boost).quoteFieldSuffix(quoteFieldSuffix);
qb.useAllFields(useAllFields);
return Optional.of(qb);
}
@ -531,7 +577,7 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
@Override
protected int doHashCode() {
return Objects.hash(fieldsAndWeights, analyzer, defaultOperator, queryText, minimumShouldMatch, settings, flags);
return Objects.hash(fieldsAndWeights, analyzer, defaultOperator, queryText, minimumShouldMatch, settings, flags, useAllFields);
}
@Override
@ -539,7 +585,8 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
return Objects.equals(fieldsAndWeights, other.fieldsAndWeights) && Objects.equals(analyzer, other.analyzer)
&& Objects.equals(defaultOperator, other.defaultOperator) && Objects.equals(queryText, other.queryText)
&& Objects.equals(minimumShouldMatch, other.minimumShouldMatch)
&& Objects.equals(settings, other.settings) && (flags == other.flags);
&& Objects.equals(settings, other.settings)
&& (flags == other.flags)
&& (useAllFields == other.useAllFields);
}
}

View File

@ -31,6 +31,8 @@ import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.util.TestUtil;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.ParsingException;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.search.internal.SearchContext;
import org.elasticsearch.test.AbstractQueryTestCase;
@ -42,6 +44,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.instanceOf;
@ -252,7 +255,12 @@ public class SimpleQueryStringBuilderTests extends AbstractQueryTestCase<SimpleQ
Map.Entry<String, Float> field = queryBuilder.fields().entrySet().iterator().next();
assertTermOrBoostQuery(query, field.getKey(), queryBuilder.value(), field.getValue());
} else if (queryBuilder.fields().size() == 0) {
assertTermQuery(query, MetaData.ALL, queryBuilder.value());
MapperService ms = context.mapperService();
if (ms.allEnabled()) {
assertTermQuery(query, MetaData.ALL, queryBuilder.value());
} else {
assertThat(query.getClass(), equalTo(MatchNoDocsQuery.class));
}
} else {
fail("Encountered lucene query type we do not have a validation implementation for in our "
+ SimpleQueryStringBuilderTests.class.getSimpleName());
@ -398,4 +406,19 @@ public class SimpleQueryStringBuilderTests extends AbstractQueryTestCase<SimpleQ
expected = new FuzzyQuery(new Term(STRING_FIELD_NAME, "abc"), 1);
assertEquals(expected, query);
}
public void testAllFieldsWithFields() throws IOException {
String json =
"{\n" +
" \"simple_query_string\" : {\n" +
" \"query\" : \"this that thus\",\n" +
" \"fields\" : [\"foo\"],\n" +
" \"all_fields\" : true\n" +
" }\n" +
"}";
ParsingException e = expectThrows(ParsingException.class, () -> parseQuery(json));
assertThat(e.getMessage(),
containsString("cannot use [all_fields] parameter in conjunction with [fields]"));
}
}

View File

@ -20,6 +20,7 @@
package org.elasticsearch.search.query;
import org.apache.lucene.util.LuceneTestCase;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
@ -27,6 +28,7 @@ import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
@ -201,33 +203,36 @@ public class QueryStringIT extends ESIntegTestCase {
assertHits(resp.getHits(), "2", "3");
assertHitCount(resp, 2L);
// Will be fixed once https://github.com/elastic/elasticsearch/pull/20965 is in
// resp = client().prepareSearch("test")
// .setQuery(queryStringQuery("Foo Bar").splitOnWhitespcae(false))
// .get();
// assertHits(resp.getHits(), "1", "2", "3");
// assertHitCount(resp, 3L);
resp = client().prepareSearch("test")
.setQuery(queryStringQuery("Foo Bar").splitOnWhitespace(false))
.get();
assertHits(resp.getHits(), "1", "2", "3");
assertHitCount(resp, 3L);
}
public void testExplicitAllFieldsRequested() throws Exception {
String indexBody = copyToStringFromClasspath("/org/elasticsearch/search/query/all-query-index-with-all.json");
prepareCreate("test2").setSource(indexBody).get();
ensureGreen("test2");
List<IndexRequestBuilder> reqs = new ArrayList<>();
reqs.add(client().prepareIndex("test", "doc", "1").setSource("f1", "foo",
"f_date", "2015/09/02",
"f_float", "1.7",
"f_ip", "127.0.0.1"));
reqs.add(client().prepareIndex("test", "doc", "2").setSource("f1", "bar",
"f_date", "2015/09/01",
"f_float", "1.8",
"f_ip", "127.0.0.2"));
reqs.add(client().prepareIndex("test2", "doc", "1").setSource("f1", "foo", "f2", "eggplant"));
indexRandom(true, false, reqs);
SearchResponse resp = client().prepareSearch("test").setQuery(
queryStringQuery("127.0.0.2 \"2015/09/02\"")
.field("f_ip") // Usually this would mean we wouldn't search "all" fields
.useAllFields(true)) // ... unless explicitly requested
.get();
assertHits(resp.getHits(), "1", "2");
assertHitCount(resp, 2L);
SearchResponse resp = client().prepareSearch("test2").setQuery(
queryStringQuery("foo eggplent").defaultOperator(Operator.AND)).get();
assertHitCount(resp, 0L);
resp = client().prepareSearch("test2").setQuery(
queryStringQuery("foo eggplent").defaultOperator(Operator.AND).useAllFields(true)).get();
assertHits(resp.getHits(), "1");
assertHitCount(resp, 1L);
Exception e = expectThrows(Exception.class, () ->
client().prepareSearch("test2").setQuery(
queryStringQuery("blah").field("f1").useAllFields(true)).get());
assertThat(ExceptionsHelper.detailedMessage(e),
containsString("cannot use [all_fields] parameter in conjunction with [default_field] or [fields]"));
}
@LuceneTestCase.AwaitsFix(bugUrl="currently can't perform phrase queries on fields that don't support positions")

View File

@ -19,23 +19,33 @@
package org.elasticsearch.search.query;
import org.apache.lucene.util.LuceneTestCase;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.SimpleQueryStringFlag;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.test.ESIntegTestCase;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.simpleQueryStringQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.test.StreamsUtils.copyToStringFromClasspath;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertFailures;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertFirstHit;
@ -43,6 +53,8 @@ import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitC
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHits;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.hasId;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
/**
@ -352,4 +364,212 @@ public class SimpleQueryStringIT extends ESIntegTestCase {
assertNoFailures(searchResponse);
assertHitCount(searchResponse, 0L);
}
public void testBasicAllQuery() throws Exception {
String indexBody = copyToStringFromClasspath("/org/elasticsearch/search/query/all-query-index.json");
prepareCreate("test").setSource(indexBody).get();
ensureGreen("test");
List<IndexRequestBuilder> reqs = new ArrayList<>();
reqs.add(client().prepareIndex("test", "doc", "1").setSource("f1", "foo bar baz"));
reqs.add(client().prepareIndex("test", "doc", "2").setSource("f2", "Bar"));
reqs.add(client().prepareIndex("test", "doc", "3").setSource("f3", "foo bar baz"));
indexRandom(true, false, reqs);
SearchResponse resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("foo")).get();
assertHitCount(resp, 2L);
assertHits(resp.getHits(), "1", "3");
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("bar")).get();
assertHitCount(resp, 2L);
assertHits(resp.getHits(), "1", "3");
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("Bar")).get();
assertHitCount(resp, 3L);
assertHits(resp.getHits(), "1", "2", "3");
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("foa")).get();
assertHitCount(resp, 1L);
assertHits(resp.getHits(), "3");
}
public void testWithDate() throws Exception {
String indexBody = copyToStringFromClasspath("/org/elasticsearch/search/query/all-query-index.json");
prepareCreate("test").setSource(indexBody).get();
ensureGreen("test");
List<IndexRequestBuilder> reqs = new ArrayList<>();
reqs.add(client().prepareIndex("test", "doc", "1").setSource("f1", "foo", "f_date", "2015/09/02"));
reqs.add(client().prepareIndex("test", "doc", "2").setSource("f1", "bar", "f_date", "2015/09/01"));
indexRandom(true, false, reqs);
SearchResponse resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("foo bar")).get();
assertHits(resp.getHits(), "1", "2");
assertHitCount(resp, 2L);
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("\"2015/09/02\"")).get();
assertHits(resp.getHits(), "1");
assertHitCount(resp, 1L);
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("bar \"2015/09/02\"")).get();
assertHits(resp.getHits(), "1", "2");
assertHitCount(resp, 2L);
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("\"2015/09/02\" \"2015/09/01\"")).get();
assertHits(resp.getHits(), "1", "2");
assertHitCount(resp, 2L);
}
public void testWithLotsOfTypes() throws Exception {
String indexBody = copyToStringFromClasspath("/org/elasticsearch/search/query/all-query-index.json");
prepareCreate("test").setSource(indexBody).get();
ensureGreen("test");
List<IndexRequestBuilder> reqs = new ArrayList<>();
reqs.add(client().prepareIndex("test", "doc", "1").setSource("f1", "foo",
"f_date", "2015/09/02",
"f_float", "1.7",
"f_ip", "127.0.0.1"));
reqs.add(client().prepareIndex("test", "doc", "2").setSource("f1", "bar",
"f_date", "2015/09/01",
"f_float", "1.8",
"f_ip", "127.0.0.2"));
indexRandom(true, false, reqs);
SearchResponse resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("foo bar")).get();
assertHits(resp.getHits(), "1", "2");
assertHitCount(resp, 2L);
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("\"2015/09/02\"")).get();
assertHits(resp.getHits(), "1");
assertHitCount(resp, 1L);
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("127.0.0.2 \"2015/09/02\"")).get();
assertHits(resp.getHits(), "1", "2");
assertHitCount(resp, 2L);
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("127.0.0.1 1.8")).get();
assertHits(resp.getHits(), "1", "2");
assertHitCount(resp, 2L);
}
public void testDocWithAllTypes() throws Exception {
String indexBody = copyToStringFromClasspath("/org/elasticsearch/search/query/all-query-index.json");
prepareCreate("test").setSource(indexBody).get();
ensureGreen("test");
List<IndexRequestBuilder> reqs = new ArrayList<>();
String docBody = copyToStringFromClasspath("/org/elasticsearch/search/query/all-example-document.json");
reqs.add(client().prepareIndex("test", "doc", "1").setSource(docBody));
indexRandom(true, false, reqs);
SearchResponse resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("foo")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("Bar")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("Baz")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("sbaz")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("19")).get();
assertHits(resp.getHits(), "1");
// nested doesn't match because it's hidden
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("1476383971")).get();
assertHits(resp.getHits(), "1");
// bool doesn't match
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("7")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("23")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("1293")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("42")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("1.7")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("1.5")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("12.23")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("127.0.0.1")).get();
assertHits(resp.getHits(), "1");
// binary doesn't match
// suggest doesn't match
// geo_point doesn't match
// geo_shape doesn't match
resp = client().prepareSearch("test").setQuery(
simpleQueryStringQuery("foo Bar 19 127.0.0.1").defaultOperator(Operator.AND)).get();
assertHits(resp.getHits(), "1");
}
public void testKeywordWithWhitespace() throws Exception {
String indexBody = copyToStringFromClasspath("/org/elasticsearch/search/query/all-query-index.json");
prepareCreate("test").setSource(indexBody).get();
ensureGreen("test");
List<IndexRequestBuilder> reqs = new ArrayList<>();
reqs.add(client().prepareIndex("test", "doc", "1").setSource("f2", "Foo Bar"));
reqs.add(client().prepareIndex("test", "doc", "2").setSource("f1", "bar"));
reqs.add(client().prepareIndex("test", "doc", "3").setSource("f1", "foo bar"));
indexRandom(true, false, reqs);
SearchResponse resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("foo")).get();
assertHits(resp.getHits(), "3");
assertHitCount(resp, 1L);
resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("bar")).get();
assertHits(resp.getHits(), "2", "3");
assertHitCount(resp, 2L);
}
public void testExplicitAllFieldsRequested() throws Exception {
String indexBody = copyToStringFromClasspath("/org/elasticsearch/search/query/all-query-index-with-all.json");
prepareCreate("test").setSource(indexBody).get();
ensureGreen("test");
List<IndexRequestBuilder> reqs = new ArrayList<>();
reqs.add(client().prepareIndex("test", "doc", "1").setSource("f1", "foo", "f2", "eggplant"));
indexRandom(true, false, reqs);
SearchResponse resp = client().prepareSearch("test").setQuery(
simpleQueryStringQuery("foo eggplent").defaultOperator(Operator.AND)).get();
assertHitCount(resp, 0L);
resp = client().prepareSearch("test").setQuery(
simpleQueryStringQuery("foo eggplent").defaultOperator(Operator.AND).useAllFields(true)).get();
assertHits(resp.getHits(), "1");
assertHitCount(resp, 1L);
Exception e = expectThrows(Exception.class, () ->
client().prepareSearch("test").setQuery(
simpleQueryStringQuery("blah").field("f1").useAllFields(true)).get());
assertThat(ExceptionsHelper.detailedMessage(e),
containsString("cannot use [all_fields] parameter in conjunction with [fields]"));
}
@LuceneTestCase.AwaitsFix(bugUrl="currently can't perform phrase queries on fields that don't support positions")
public void testPhraseQueryOnFieldWithNoPositions() throws Exception {
String indexBody = copyToStringFromClasspath("/org/elasticsearch/search/query/all-query-index.json");
prepareCreate("test").setSource(indexBody).get();
ensureGreen("test");
List<IndexRequestBuilder> reqs = new ArrayList<>();
reqs.add(client().prepareIndex("test", "doc", "1").setSource("f1", "foo bar", "f4", "eggplant parmesan"));
reqs.add(client().prepareIndex("test", "doc", "2").setSource("f1", "foo bar", "f4", "chicken parmesan"));
indexRandom(true, false, reqs);
SearchResponse resp = client().prepareSearch("test").setQuery(simpleQueryStringQuery("\"eggplant parmesan\"")).get();
assertHits(resp.getHits(), "1");
assertHitCount(resp, 1L);
}
private void assertHits(SearchHits hits, String... ids) {
assertThat(hits.totalHits(), equalTo((long) ids.length));
Set<String> hitIds = new HashSet<>();
for (SearchHit hit : hits.getHits()) {
hitIds.add(hit.id());
}
assertThat(hitIds, containsInAnyOrder(ids));
}
}

View File

@ -0,0 +1,35 @@
{
"settings": {
"index": {
"number_of_shards": 1,
"number_of_replicas": 0,
"analysis": {
"analyzer": {
"my_ngrams": {
"type": "custom",
"tokenizer": "standard",
"filter": ["my_ngrams"]
}
},
"filter": {
"my_ngrams": {
"type": "ngram",
"min_gram": 2,
"max_gram": 2
}
}
}
}
},
"mappings": {
"doc": {
"_all": {
"enabled": true
},
"properties": {
"f1": {"type": "text"},
"f2": {"type": "text", "analyzer": "my_ngrams"}
}
}
}
}

View File

@ -61,6 +61,10 @@ based just on the prefix of a term. Defaults to `false`.
the query string. This allows to use a field that has a different analysis chain
for exact matching. Look <<mixing-exact-search-with-stemming,here>> for a
comprehensive example.
|`all_fields` | Perform the query on all fields detected in the mapping that can
be queried. Will be used by default when the `_all` field is disabled and no
`default_field` is specified index settings, and no `fields` are specified.
|=======================================================================
[float]
@ -85,8 +89,10 @@ When not explicitly specifying the field to search on in the query
string syntax, the `index.query.default_field` will be used to derive
which field to search on. It defaults to `_all` field.
So, if `_all` field is disabled, it might make sense to change it to set
a different default field.
If the `_all` field is disabled and no `fields` are specified in the request`,
the `simple_query_string` query will automatically attempt to determine the
existing fields in the index's mapping that are queryable, and perform the
search on those fields.
[float]
==== Multi Field