/*
* 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.search.query;
import static org.elasticsearch.index.query.QueryBuilders.queryStringQuery;
import static org.elasticsearch.test.StreamsUtils.copyToStringFromClasspath;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoSearchHits;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHits;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
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.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.InternalSettingsPlugin;
import org.junit.Before;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class QueryStringIT extends ESIntegTestCase {
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Arrays.asList(InternalSettingsPlugin.class); // uses index.version.created
}
@Before
public void setup() throws Exception {
String indexBody = copyToStringFromClasspath("/org/elasticsearch/search/query/all-query-index.json");
prepareCreate("test").setSource(indexBody, XContentType.JSON).get();
ensureGreen("test");
}
private QueryStringQueryBuilder lenientQuery(String queryText) {
return queryStringQuery(queryText).lenient(true);
}
public void testBasicAllQuery() throws Exception {
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(queryStringQuery("foo")).get();
assertHitCount(resp, 2L);
assertHits(resp.getHits(), "1", "3");
resp = client().prepareSearch("test").setQuery(queryStringQuery("bar")).get();
assertHitCount(resp, 2L);
assertHits(resp.getHits(), "1", "3");
resp = client().prepareSearch("test").setQuery(queryStringQuery("Bar")).get();
assertHitCount(resp, 3L);
assertHits(resp.getHits(), "1", "2", "3");
resp = client().prepareSearch("test").setQuery(queryStringQuery("foa")).get();
assertHitCount(resp, 1L);
assertHits(resp.getHits(), "3");
}
public void testWithDate() throws Exception {
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(queryStringQuery("foo bar")).get();
assertHits(resp.getHits(), "1", "2");
assertHitCount(resp, 2L);
resp = client().prepareSearch("test").setQuery(queryStringQuery("\"2015/09/02\"")).get();
assertHits(resp.getHits(), "1");
assertHitCount(resp, 1L);
resp = client().prepareSearch("test").setQuery(queryStringQuery("bar \"2015/09/02\"")).get();
assertHits(resp.getHits(), "1", "2");
assertHitCount(resp, 2L);
resp = client().prepareSearch("test").setQuery(queryStringQuery("\"2015/09/02\" \"2015/09/01\"")).get();
assertHits(resp.getHits(), "1", "2");
assertHitCount(resp, 2L);
}
public void testWithLotsOfTypes() throws Exception {
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(queryStringQuery("foo bar")).get();
assertHits(resp.getHits(), "1", "2");
assertHitCount(resp, 2L);
resp = client().prepareSearch("test").setQuery(queryStringQuery("\"2015/09/02\"")).get();
assertHits(resp.getHits(), "1");
assertHitCount(resp, 1L);
resp = client().prepareSearch("test").setQuery(queryStringQuery("127.0.0.2 \"2015/09/02\"")).get();
assertHits(resp.getHits(), "1", "2");
assertHitCount(resp, 2L);
resp = client().prepareSearch("test").setQuery(queryStringQuery("127.0.0.1 1.8")).get();
assertHits(resp.getHits(), "1", "2");
assertHitCount(resp, 2L);
}
public void testDocWithAllTypes() throws Exception {
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, XContentType.JSON));
indexRandom(true, false, reqs);
SearchResponse resp = client().prepareSearch("test").setQuery(queryStringQuery("foo")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(queryStringQuery("Bar")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(queryStringQuery("Baz")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(queryStringQuery("sbaz")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(queryStringQuery("19")).get();
assertHits(resp.getHits(), "1");
// nested doesn't match because it's hidden
resp = client().prepareSearch("test").setQuery(queryStringQuery("1476383971")).get();
assertHits(resp.getHits(), "1");
// bool doesn't match
resp = client().prepareSearch("test").setQuery(queryStringQuery("7")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(queryStringQuery("23")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(queryStringQuery("1293")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(queryStringQuery("42")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(queryStringQuery("1.7")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(queryStringQuery("1.5")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(queryStringQuery("12.23")).get();
assertHits(resp.getHits(), "1");
resp = client().prepareSearch("test").setQuery(queryStringQuery("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
}
public void testKeywordWithWhitespace() throws Exception {
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(queryStringQuery("foo")).get();
assertHits(resp.getHits(), "3");
assertHitCount(resp, 1L);
resp = client().prepareSearch("test").setQuery(queryStringQuery("bar")).get();
assertHits(resp.getHits(), "2", "3");
assertHitCount(resp, 2L);
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, XContentType.JSON).get();
ensureGreen("test2");
List<IndexRequestBuilder> reqs = new ArrayList<>();
reqs.add(client().prepareIndex("test2", "doc", "1").setSource("f1", "foo", "f2", "eggplant"));
indexRandom(true, false, reqs);
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")
public void testPhraseQueryOnFieldWithNoPositions() throws Exception {
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(queryStringQuery("\"eggplant parmesan\"")).get();
assertHits(resp.getHits(), "1");
assertHitCount(resp, 1L);
}
public void testBooleanStrictQuery() throws Exception {
Exception e = expectThrows(Exception.class, () ->
client().prepareSearch("test").setQuery(
queryStringQuery("foo").field("f_bool")).get());
assertThat(ExceptionsHelper.detailedMessage(e),
containsString("Can't parse boolean value [foo], expected [true] or [false]"));
}
public void testAllFieldsWithSpecifiedLeniency() throws IOException {
Exception e = expectThrows(Exception.class, () ->
client().prepareSearch("test").setQuery(
queryStringQuery("f_date:[now-2D TO now]").lenient(false)).get());
assertThat(ExceptionsHelper.detailedMessage(e),
containsString("unit [D] not supported for date math [-2D]"));
}
private void setupIndexWithGraph(String index) throws Exception {
CreateIndexRequestBuilder builder = prepareCreate(index).setSettings(
Settings.builder()
.put(indexSettings())
.put("index.analysis.filter.graphsyns.type", "synonym_graph")
.putArray("index.analysis.filter.graphsyns.synonyms", "wtf, what the fudge", "foo, bar baz")
.put("index.analysis.analyzer.lower_graphsyns.type", "custom")
.put("index.analysis.analyzer.lower_graphsyns.tokenizer", "standard")
.putArray("index.analysis.analyzer.lower_graphsyns.filter", "lowercase", "graphsyns")
);
XContentBuilder mapping = XContentFactory.jsonBuilder().startObject().startObject(index).startObject("properties")
.startObject("field").field("type", "text").endObject().endObject().endObject().endObject();
assertAcked(builder.addMapping(index, mapping));
ensureGreen();
List<IndexRequestBuilder> builders = new ArrayList<>();
builders.add(client().prepareIndex(index, index, "1").setSource("field", "say wtf happened foo"));
builders.add(client().prepareIndex(index, index, "2").setSource("field", "bar baz what the fudge man"));
builders.add(client().prepareIndex(index, index, "3").setSource("field", "wtf"));
builders.add(client().prepareIndex(index, index, "4").setSource("field", "what is the name for fudge"));
builders.add(client().prepareIndex(index, index, "5").setSource("field", "bar two three"));
builders.add(client().prepareIndex(index, index, "6").setSource("field", "bar baz two three"));
indexRandom(true, false, builders);
}
public void testGraphQueries() throws Exception {
String index = "graph_test_index";
setupIndexWithGraph(index);
// phrase
SearchResponse searchResponse = client().prepareSearch(index).setQuery(
QueryBuilders.queryStringQuery("\"foo two three\"")
.defaultField("field")
.analyzer("lower_graphsyns")).get();
assertHitCount(searchResponse, 1L);
assertSearchHits(searchResponse, "6");
// and
searchResponse = client().prepareSearch(index).setQuery(
QueryBuilders.queryStringQuery("say what the fudge")
.defaultField("field")
.splitOnWhitespace(false)
.defaultOperator(Operator.AND)
.analyzer("lower_graphsyns")).get();
assertHitCount(searchResponse, 1L);
assertSearchHits(searchResponse, "1");
// and, split on whitespace means we should not recognize the multi-word synonym
searchResponse = client().prepareSearch(index).setQuery(
QueryBuilders.queryStringQuery("say what the fudge")
.defaultField("field")
.splitOnWhitespace(true)
.defaultOperator(Operator.AND)
.analyzer("lower_graphsyns")).get();
assertNoSearchHits(searchResponse);
// or
searchResponse = client().prepareSearch(index).setQuery(
QueryBuilders.queryStringQuery("three what the fudge foo")
.defaultField("field")
.splitOnWhitespace(false)
.defaultOperator(Operator.OR)
.analyzer("lower_graphsyns")).get();
assertHitCount(searchResponse, 6L);
assertSearchHits(searchResponse, "1", "2", "3", "4", "5", "6");
// min should match
searchResponse = client().prepareSearch(index).setQuery(
QueryBuilders.queryStringQuery("three what the fudge foo")
.defaultField("field")
.splitOnWhitespace(false)
.defaultOperator(Operator.OR)
.analyzer("lower_graphsyns")
.minimumShouldMatch("80%")).get();
assertHitCount(searchResponse, 3L);
assertSearchHits(searchResponse, "1", "2", "6");
}
private void assertHits(SearchHits hits, String... ids) {
assertThat(hits.getTotalHits(), equalTo((long) ids.length));
Set<String> hitIds = new HashSet<>();
for (SearchHit hit : hits.getHits()) {
hitIds.add(hit.getId());
}
assertThat(hitIds, containsInAnyOrder(ids));
}
}