/*
* 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.basic;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.search.MultiSearchResponse;
import org.elasticsearch.action.search.SearchPhaseExecutionException;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Requests;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.ScriptScoreFunctionBuilder;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.filter.Filter;
import org.elasticsearch.search.aggregations.bucket.global.Global;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.test.ESIntegTestCase;
import java.io.IOException;
import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;
import static org.elasticsearch.action.search.SearchType.DFS_QUERY_THEN_FETCH;
import static org.elasticsearch.action.search.SearchType.QUERY_THEN_FETCH;
import static org.elasticsearch.client.Requests.createIndexRequest;
import static org.elasticsearch.client.Requests.searchRequest;
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_SHARDS;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
public class TransportTwoNodesSearchIT extends ESIntegTestCase {
@Override
protected int numberOfReplicas() {
return 0;
}
private Set<String> prepareData() throws Exception {
return prepareData(-1);
}
private Set<String> prepareData(int numShards) throws Exception {
Set<String> fullExpectedIds = new TreeSet<>();
Settings.Builder settingsBuilder = Settings.builder()
.put(indexSettings());
if (numShards > 0) {
settingsBuilder.put(SETTING_NUMBER_OF_SHARDS, numShards);
}
client().admin().indices().create(createIndexRequest("test")
.settings(settingsBuilder)
.mapping("type", "foo", "type=geo_point"))
.actionGet();
ensureGreen();
for (int i = 0; i < 100; i++) {
index(Integer.toString(i), "test", i);
fullExpectedIds.add(Integer.toString(i));
}
refresh();
return fullExpectedIds;
}
private void index(String id, String nameValue, int age) throws IOException {
client().index(Requests.indexRequest("test").type("type").id(id).source(source(id, nameValue, age))).actionGet();
}
private XContentBuilder source(String id, String nameValue, int age) throws IOException {
StringBuilder multi = new StringBuilder().append(nameValue);
for (int i = 0; i < age; i++) {
multi.append(" ").append(nameValue);
}
return jsonBuilder().startObject()
.field("id", id)
.field("nid", Integer.parseInt(id))
.field("name", nameValue + id)
.field("age", age)
.field("multi", multi.toString())
.endObject();
}
public void testDfsQueryThenFetch() throws Exception {
Settings.Builder settingsBuilder = Settings.builder()
.put(indexSettings());
client().admin().indices().create(createIndexRequest("test")
.settings(settingsBuilder))
.actionGet();
ensureGreen();
// we need to have age (ie number of repeats of "test" term) high enough
// to produce the same 8-bit norm for all docs here, so that
// the tf is basically the entire score (assuming idf is fixed, which
// it should be if dfs is working correctly)
for (int i = 1024; i < 1124; i++) {
index(Integer.toString(i - 1024), "test", i);
}
refresh();
int total = 0;
SearchResponse searchResponse = client().prepareSearch("test").setSearchType(DFS_QUERY_THEN_FETCH).setQuery(termQuery("multi", "test")).setSize(60).setExplain(true).setScroll(TimeValue.timeValueSeconds(30)).get();
while (true) {
assertNoFailures(searchResponse);
assertThat(searchResponse.getHits().getTotalHits(), equalTo(100L));
SearchHit[] hits = searchResponse.getHits().getHits();
if (hits.length == 0) {
break; // finished
}
for (int i = 0; i < hits.length; ++i) {
SearchHit hit = hits[i];
assertThat(hit.getExplanation(), notNullValue());
assertThat(hit.getExplanation().getDetails().length, equalTo(1));
assertThat(hit.getExplanation().getDetails()[0].getDetails().length, equalTo(2));
assertThat(hit.getExplanation().getDetails()[0].getDetails()[0].getDetails().length, equalTo(2));
assertThat(hit.getExplanation().getDetails()[0].getDetails()[0].getDetails()[0].getDescription(),
equalTo("docFreq"));
assertThat(hit.getExplanation().getDetails()[0].getDetails()[0].getDetails()[0].getValue(),
equalTo(100.0f));
assertThat(hit.getExplanation().getDetails()[0].getDetails()[0].getDetails()[1].getDescription(),
equalTo("docCount"));
assertThat(hit.getExplanation().getDetails()[0].getDetails()[0].getDetails()[1].getValue(),
equalTo(100.0f));
assertThat("id[" + hit.getId() + "] -> " + hit.getExplanation().toString(), hit.getId(), equalTo(Integer.toString(100 - total - i - 1)));
}
total += hits.length;
searchResponse = client().prepareSearchScroll(searchResponse.getScrollId()).setScroll(TimeValue.timeValueSeconds(30)).get();
}
clearScroll(searchResponse.getScrollId());
assertEquals(100, total);
}
public void testDfsQueryThenFetchWithSort() throws Exception {
prepareData();
int total = 0;
SearchResponse searchResponse = client().prepareSearch("test").setSearchType(DFS_QUERY_THEN_FETCH).setQuery(termQuery("multi", "test")).setSize(60).setExplain(true).addSort("age", SortOrder.ASC).setScroll(TimeValue.timeValueSeconds(30)).get();
while (true) {
assertNoFailures(searchResponse);
assertThat(searchResponse.getHits().getTotalHits(), equalTo(100L));
SearchHit[] hits = searchResponse.getHits().getHits();
if (hits.length == 0) {
break; // finished
}
for (int i = 0; i < hits.length; ++i) {
SearchHit hit = hits[i];
assertThat(hit.getExplanation(), notNullValue());
assertThat(hit.getExplanation().getDetails().length, equalTo(1));
assertThat(hit.getExplanation().getDetails()[0].getDetails().length, equalTo(2));
assertThat(hit.getExplanation().getDetails()[0].getDetails()[0].getDetails().length, equalTo(2));
assertThat(hit.getExplanation().getDetails()[0].getDetails()[0].getDetails()[0].getDescription(),
equalTo("docFreq"));
assertThat(hit.getExplanation().getDetails()[0].getDetails()[0].getDetails()[0].getValue(),
equalTo(100.0f));
assertThat(hit.getExplanation().getDetails()[0].getDetails()[0].getDetails()[1].getDescription(),
equalTo("docCount"));
assertThat(hit.getExplanation().getDetails()[0].getDetails()[0].getDetails()[1].getValue(),
equalTo(100.0f));
assertThat("id[" + hit.getId() + "]", hit.getId(), equalTo(Integer.toString(total + i)));
}
total += hits.length;
searchResponse = client().prepareSearchScroll(searchResponse.getScrollId()).setScroll(TimeValue.timeValueSeconds(30)).get();
}
clearScroll(searchResponse.getScrollId());
assertEquals(100, total);
}
public void testQueryThenFetch() throws Exception {
prepareData();
int total = 0;
SearchResponse searchResponse = client().prepareSearch("test").setSearchType(QUERY_THEN_FETCH).setQuery(termQuery("multi", "test")).setSize(60).setExplain(true).addSort("nid", SortOrder.DESC).setScroll(TimeValue.timeValueSeconds(30)).get();
while (true) {
assertNoFailures(searchResponse);
assertThat(searchResponse.getHits().getTotalHits(), equalTo(100L));
SearchHit[] hits = searchResponse.getHits().getHits();
if (hits.length == 0) {
break; // finished
}
for (int i = 0; i < hits.length; ++i) {
SearchHit hit = hits[i];
assertThat(hit.getExplanation(), notNullValue());
assertThat("id[" + hit.getId() + "]", hit.getId(), equalTo(Integer.toString(100 - total - i - 1)));
}
total += hits.length;
searchResponse = client().prepareSearchScroll(searchResponse.getScrollId()).setScroll(TimeValue.timeValueSeconds(30)).get();
}
clearScroll(searchResponse.getScrollId());
assertEquals(100, total);
}
public void testQueryThenFetchWithFrom() throws Exception {
Set<String> fullExpectedIds = prepareData();
SearchSourceBuilder source = searchSource()
.query(matchAllQuery())
.explain(true);
Set<String> collectedIds = new TreeSet<>();
SearchResponse searchResponse = client().search(searchRequest("test").source(source.from(0).size(60)).searchType(QUERY_THEN_FETCH)).actionGet();
assertNoFailures(searchResponse);
assertThat(searchResponse.getHits().getTotalHits(), equalTo(100L));
assertThat(searchResponse.getHits().getHits().length, equalTo(60));
for (int i = 0; i < 60; i++) {
SearchHit hit = searchResponse.getHits().getHits()[i];
collectedIds.add(hit.getId());
}
searchResponse = client().search(searchRequest("test").source(source.from(60).size(60)).searchType(QUERY_THEN_FETCH)).actionGet();
assertNoFailures(searchResponse);
assertThat(searchResponse.getHits().getTotalHits(), equalTo(100L));
assertThat(searchResponse.getHits().getHits().length, equalTo(40));
for (int i = 0; i < 40; i++) {
SearchHit hit = searchResponse.getHits().getHits()[i];
collectedIds.add(hit.getId());
}
assertThat(collectedIds, equalTo(fullExpectedIds));
}
public void testQueryThenFetchWithSort() throws Exception {
prepareData();
int total = 0;
SearchResponse searchResponse = client().prepareSearch("test").setQuery(termQuery("multi", "test")).setSize(60).setExplain(true).addSort("age", SortOrder.ASC).setScroll(TimeValue.timeValueSeconds(30)).get();
while (true) {
assertNoFailures(searchResponse);
assertThat(searchResponse.getHits().getTotalHits(), equalTo(100L));
SearchHit[] hits = searchResponse.getHits().getHits();
if (hits.length == 0) {
break; // finished
}
for (int i = 0; i < hits.length; ++i) {
SearchHit hit = hits[i];
assertThat(hit.getExplanation(), notNullValue());
assertThat("id[" + hit.getId() + "]", hit.getId(), equalTo(Integer.toString(total + i)));
}
total += hits.length;
searchResponse = client().prepareSearchScroll(searchResponse.getScrollId()).setScroll(TimeValue.timeValueSeconds(30)).get();
}
clearScroll(searchResponse.getScrollId());
assertEquals(100, total);
}
public void testSimpleFacets() throws Exception {
prepareData();
SearchSourceBuilder sourceBuilder = searchSource()
.query(termQuery("multi", "test"))
.from(0).size(20).explain(true)
.aggregation(AggregationBuilders.global("global").subAggregation(
AggregationBuilders.filter("all", termQuery("multi", "test"))))
.aggregation(AggregationBuilders.filter("test1", termQuery("name", "test1")));
SearchResponse searchResponse = client().search(searchRequest("test").source(sourceBuilder)).actionGet();
assertNoFailures(searchResponse);
assertThat(searchResponse.getHits().getTotalHits(), equalTo(100L));
Global global = searchResponse.getAggregations().get("global");
Filter all = global.getAggregations().get("all");
Filter test1 = searchResponse.getAggregations().get("test1");
assertThat(test1.getDocCount(), equalTo(1L));
assertThat(all.getDocCount(), equalTo(100L));
}
public void testFailedSearchWithWrongQuery() throws Exception {
prepareData();
NumShards test = getNumShards("test");
logger.info("Start Testing failed search with wrong query");
try {
SearchResponse searchResponse = client().search(
searchRequest("test").source(new SearchSourceBuilder().query(new MatchQueryBuilder("foo", "biz")))).actionGet();
assertThat(searchResponse.getTotalShards(), equalTo(test.numPrimaries));
assertThat(searchResponse.getSuccessfulShards(), equalTo(0));
assertThat(searchResponse.getFailedShards(), equalTo(test.numPrimaries));
fail("search should fail");
} catch (ElasticsearchException e) {
assertThat(e.unwrapCause(), instanceOf(SearchPhaseExecutionException.class));
// all is well
}
logger.info("Done Testing failed search");
}
public void testFailedSearchWithWrongFrom() throws Exception {
prepareData();
NumShards test = getNumShards("test");
logger.info("Start Testing failed search with wrong from");
SearchSourceBuilder source = searchSource()
.query(termQuery("multi", "test"))
.from(1000).size(20).explain(true);
SearchResponse response = client().search(searchRequest("test").searchType(DFS_QUERY_THEN_FETCH).source(source)).actionGet();
assertThat(response.getHits().getHits().length, equalTo(0));
assertThat(response.getTotalShards(), equalTo(test.numPrimaries));
assertThat(response.getSuccessfulShards(), equalTo(test.numPrimaries));
assertThat(response.getFailedShards(), equalTo(0));
response = client().search(searchRequest("test").searchType(QUERY_THEN_FETCH).source(source)).actionGet();
assertNoFailures(response);
assertThat(response.getHits().getHits().length, equalTo(0));
response = client().search(searchRequest("test").searchType(DFS_QUERY_THEN_FETCH).source(source)).actionGet();
assertNoFailures(response);
assertThat(response.getHits().getHits().length, equalTo(0));
response = client().search(searchRequest("test").searchType(DFS_QUERY_THEN_FETCH).source(source)).actionGet();
assertNoFailures(response);
assertThat(response.getHits().getHits().length, equalTo(0));
logger.info("Done Testing failed search");
}
public void testFailedMultiSearchWithWrongQuery() throws Exception {
prepareData();
logger.info("Start Testing failed multi search with a wrong query");
MultiSearchResponse response = client().prepareMultiSearch()
.add(client().prepareSearch("test").setQuery(new MatchQueryBuilder("foo", "biz")))
.add(client().prepareSearch("test").setQuery(QueryBuilders.termQuery("nid", 2)))
.add(client().prepareSearch("test").setQuery(QueryBuilders.matchAllQuery()))
.execute().actionGet();
assertThat(response.getResponses().length, equalTo(3));
assertThat(response.getResponses()[0].getFailureMessage(), notNullValue());
assertThat(response.getResponses()[1].getFailureMessage(), nullValue());
assertThat(response.getResponses()[1].getResponse().getHits().getHits().length, equalTo(1));
assertThat(response.getResponses()[2].getFailureMessage(), nullValue());
assertThat(response.getResponses()[2].getResponse().getHits().getHits().length, equalTo(10));
logger.info("Done Testing failed search");
}
public void testFailedMultiSearchWithWrongQueryWithFunctionScore() throws Exception {
prepareData();
logger.info("Start Testing failed multi search with a wrong query");
MultiSearchResponse response = client().prepareMultiSearch()
// Add custom score query with bogus script
.add(client().prepareSearch("test").setQuery(QueryBuilders.functionScoreQuery(QueryBuilders.termQuery("nid", 1), new ScriptScoreFunctionBuilder(new Script(ScriptType.INLINE, "bar", "foo", Collections.emptyMap())))))
.add(client().prepareSearch("test").setQuery(QueryBuilders.termQuery("nid", 2)))
.add(client().prepareSearch("test").setQuery(QueryBuilders.matchAllQuery()))
.execute().actionGet();
assertThat(response.getResponses().length, equalTo(3));
assertThat(response.getResponses()[0].getFailureMessage(), notNullValue());
assertThat(response.getResponses()[1].getFailureMessage(), nullValue());
assertThat(response.getResponses()[1].getResponse().getHits().getHits().length, equalTo(1));
assertThat(response.getResponses()[2].getFailureMessage(), nullValue());
assertThat(response.getResponses()[2].getResponse().getHits().getHits().length, equalTo(10));
logger.info("Done Testing failed search");
}
}