Browse Source

Adding basic search request documentation for high level client (#25651)

Christoph Büscher 8 years ago
parent
commit
f3e7a1c4a4

+ 136 - 0
client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SearchDocumentationIT.java

@@ -28,20 +28,28 @@ import org.elasticsearch.action.search.ClearScrollResponse;
 import org.elasticsearch.action.search.SearchRequest;
 import org.elasticsearch.action.search.SearchResponse;
 import org.elasticsearch.action.search.SearchScrollRequest;
+import org.elasticsearch.action.search.ShardSearchFailure;
+import org.elasticsearch.action.support.IndicesOptions;
 import org.elasticsearch.action.support.WriteRequest;
 import org.elasticsearch.client.ESRestHighLevelClientTestCase;
 import org.elasticsearch.client.RestHighLevelClient;
 import org.elasticsearch.common.unit.TimeValue;
 import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.index.query.QueryBuilders;
 import org.elasticsearch.rest.RestStatus;
 import org.elasticsearch.search.Scroll;
 import org.elasticsearch.search.SearchHit;
 import org.elasticsearch.search.SearchHits;
 import org.elasticsearch.search.builder.SearchSourceBuilder;
+import org.elasticsearch.search.sort.ScoreSortBuilder;
+import org.elasticsearch.search.sort.SortOrder;
 
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
 import static org.hamcrest.Matchers.greaterThan;
@@ -63,6 +71,134 @@ import static org.hamcrest.Matchers.greaterThan;
  */
 public class SearchDocumentationIT extends ESRestHighLevelClientTestCase {
 
+    @SuppressWarnings({ "unused", "unchecked" })
+    public void testSearch() throws IOException {
+        RestHighLevelClient client = highLevelClient();
+        {
+            BulkRequest request = new BulkRequest();
+            request.add(new IndexRequest("posts", "doc", "1")
+                    .source(XContentType.JSON, "title", "In which order are my Elasticsearch queries executed?", "user",
+                            Arrays.asList("kimchy", "luca"), "innerObject", Collections.singletonMap("key", "value")));
+            request.add(new IndexRequest("posts", "doc", "2")
+                    .source(XContentType.JSON, "title", "Current status and upcoming changes in Elasticsearch", "user",
+                            Arrays.asList("kimchy", "christoph"), "innerObject", Collections.singletonMap("key", "value")));
+            request.add(new IndexRequest("posts", "doc", "3")
+                    .source(XContentType.JSON, "title", "The Future of Federated Search in Elasticsearch", "user",
+                            Arrays.asList("kimchy", "tanguy"), "innerObject", Collections.singletonMap("key", "value")));
+            request.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);
+            BulkResponse bulkResponse = client.bulk(request);
+            assertSame(bulkResponse.status(), RestStatus.OK);
+            assertFalse(bulkResponse.hasFailures());
+        }
+        {
+            // tag::search-request-basic
+            SearchRequest searchRequest = new SearchRequest(); // <1>
+            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); // <2>
+            searchSourceBuilder.query(QueryBuilders.matchAllQuery()); // <3>
+            // end::search-request-basic
+        }
+        {
+            // tag::search-request-indices-types
+            SearchRequest searchRequest = new SearchRequest("posts");
+            searchRequest.types("doc");
+            // end::search-request-indices-types
+            // tag::search-request-routing
+            searchRequest.routing("routing"); // <1>
+            // end::search-request-routing
+            // tag::search-request-indicesOptions
+            searchRequest.indicesOptions(IndicesOptions.lenientExpandOpen()); // <1>
+            // end::search-request-indicesOptions
+            // tag::search-request-preference
+            searchRequest.preference("_local"); // <1>
+            // end::search-request-preference
+            assertNotNull(client.search(searchRequest));
+        }
+        {
+            // tag::search-source-basics
+            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); // <1>
+            sourceBuilder.query(QueryBuilders.termQuery("user", "kimchy")); // <2>
+            sourceBuilder.from(0); // <3>
+            sourceBuilder.size(5); // <4>
+            sourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.ASC));
+            sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS)); // <5>
+            // end::search-source-basics
+
+            // tag::search-source-setter
+            SearchRequest searchRequest = new SearchRequest();
+            searchRequest.source(sourceBuilder);
+            // end::search-source-setter
+
+            // tag::search-execute
+            SearchResponse searchResponse = client.search(searchRequest);
+            // end::search-execute
+
+            // tag::search-execute-async
+            client.searchAsync(searchRequest, new ActionListener<SearchResponse>() {
+                @Override
+                public void onResponse(SearchResponse searchResponse) {
+                    // <1>
+                }
+
+                @Override
+                public void onFailure(Exception e) {
+                    // <2>
+                }
+            });
+            // end::search-execute-async
+
+            // tag::search-response-1
+            RestStatus status = searchResponse.status();
+            TimeValue took = searchResponse.getTook();
+            Boolean terminatedEarly = searchResponse.isTerminatedEarly();
+            boolean timedOut = searchResponse.isTimedOut();
+            // end::search-response-1
+
+            // tag::search-response-2
+            int totalShards = searchResponse.getTotalShards();
+            int successfulShards = searchResponse.getSuccessfulShards();
+            int failedShards = searchResponse.getFailedShards();
+            for (ShardSearchFailure failure : searchResponse.getShardFailures()) {
+                // failures should be handled here
+            }
+            // end::search-response-2
+            assertNotNull(searchResponse);
+
+            // tag::search-hits-get
+            SearchHits hits = searchResponse.getHits();
+            // end::search-hits-get
+            // tag::search-hits-info
+            long totalHits = hits.getTotalHits();
+            float maxScore = hits.getMaxScore();
+            // end::search-hits-info
+            // tag::search-hits-singleHit
+            SearchHit[] searchHits = hits.getHits();
+            for (SearchHit hit : searchHits) {
+                // do something with the SearchHit
+            }
+            // end::search-hits-singleHit
+            for (SearchHit hit : searchHits) {
+                // tag::search-hits-singleHit-properties
+                String index = hit.getIndex();
+                String type = hit.getType();
+                String id = hit.getId();
+                float score = hit.getScore();
+                // end::search-hits-singleHit-properties
+                // tag::search-hits-singleHit-source
+                String sourceAsString = hit.getSourceAsString();
+                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
+                String documentTitle = (String) sourceAsMap.get("title");
+                List<Object> users = (List<Object>) sourceAsMap.get("user");
+                Map<String, Object> innerObject = (Map<String, Object>) sourceAsMap.get("innerObject");
+                // end::search-hits-singleHit-source
+            }
+            assertEquals(3, totalHits);
+            assertNotNull(hits.getHits()[0].getSourceAsString());
+            assertNotNull(hits.getHits()[0].getSourceAsMap().get("title"));
+            assertNotNull(hits.getHits()[0].getSourceAsMap().get("user"));
+            assertNotNull(hits.getHits()[0].getSourceAsMap().get("innerObject"));
+        }
+    }
+
     public void testScroll() throws IOException {
         RestHighLevelClient client = highLevelClient();
         {

+ 1 - 1
core/src/main/java/org/elasticsearch/search/SearchHit.java

@@ -192,7 +192,7 @@ public final class SearchHit implements Streamable, ToXContentObject, Iterable<D
     }
 
     /**
-     * Returns bytes reference, also un compress the source if needed.
+     * Returns bytes reference, also uncompress the source if needed.
      */
     public BytesReference getSourceRef() {
         if (this.source == null) {

+ 177 - 1
docs/java-rest/high-level/apis/search.asciidoc

@@ -1,4 +1,180 @@
 [[java-rest-high-search]]
 === Search API
 
-To be documented.
+[[java-rest-high-document-search-request]]
+==== Search Request
+
+The `SearchRequest` is used for any operation that has to do with searching
+documents, aggregations, suggestions and also offers ways of requesting
+highlighting on the resulting documents.
+
+In its most basic form, a query can be added to the request like this:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SearchDocumentationIT.java[search-request-basic]
+--------------------------------------------------
+
+<1> Creates the `SeachRequest`. Without arguments this runs against all indices.
+<2> Most parameters of the search can be added to the `SearchSourceBuilder`
+which contains everything that
+in the Rest API would be placed in the search request body.
+<3> Add a `match_all` query to the `SearchSourceBuilder`.
+
+==== Optional arguments
+
+Lets first look at some of the optional argument of a `SearchRequest`.
+First of all, the request can be restricted to one or more indices using the
+constructor or to on or more types using a setter:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SearchDocumentationIT.java[search-request-indices-types]
+--------------------------------------------------
+
+There are a couple of other interesting optional parameters:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SearchDocumentationIT.java[search-request-routing]
+--------------------------------------------------
+<1> Set a routing parameter
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SearchDocumentationIT.java[search-request-indicesOptions]
+--------------------------------------------------
+<1> Setting `IndicesOptions` controls how unavailable indices are resolved and
+how wildcard expressions are expanded
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SearchDocumentationIT.java[search-request-preference]
+--------------------------------------------------
+<1> Use the preference parameter e.g. to execute the search to prefer local
+shards. The The default is to randomize across shards.
+
+==== Using the SearchSourceBuilder
+
+Most options controlling the search behavior can be set on the
+`SearchSourceBuilder`,
+which contains more or less the equivalent of the options in the search request
+body of the Rest API.
+
+Here are a few examples of some common options:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SearchDocumentationIT.java[search-source-basics]
+--------------------------------------------------
+<1> Create a `SearchSourceBuilder` with default options.
+<2> Set the query. Can be any type of `QueryBuilder`
+<3> Set the `from` option that determines the result index to start searching
+from. Defaults to 0.
+<4> Set the `size` option that determines the number of search hits to return.
+Defaults to 10.
+<5> Set an optional timeout that controls how long the search is allowed to
+take.
+
+After this, the `SearchSourceBuilder` only needs to be added to the
+`SearchRequest`:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SearchDocumentationIT.java[search-source-setter]
+--------------------------------------------------
+
+
+[[java-rest-high-document-search-sync]]
+==== Synchronous Execution
+
+When executing a `SearchRequest` in the following manner, the client waits
+for the `SearchResponse` to be returned before continuing with code execution:  
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SearchDocumentationIT.java[search-execute]
+--------------------------------------------------
+
+[[java-rest-high-document-search-async]]
+==== Asynchronous Execution
+
+
+Executing a `SearchRequest` can also be done in an asynchronous fashion so that
+the client can return directly. Users need to specify how the response or
+potential failures will be handled by passing in appropriate listeners:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SearchDocumentationIT.java[search-execute-async]
+--------------------------------------------------
+<1> Called when the execution is successfully completed.
+<2> Called when the whole `SearchRequest` fails.
+
+==== SearchResponse
+
+The `SearchResponse` that is returned by executing the search provides details
+about the search execution itself as well as access to the documents returned.
+First, there is useful information about the request execution itself, like the
+HTTP status code, execution time or wether the request terminated early or timed
+out: 
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SearchDocumentationIT.java[search-response-1]
+--------------------------------------------------
+
+Second, the response also provides information about the execution on the
+shard level by offering statistics about the total number of shards that were
+affected by the search, and the successful vs. unsuccessful shards. Possible
+failures can also be handled by iterating over an array off
+`ShardSearchFailures` like in the following example:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SearchDocumentationIT.java[search-response-2]
+--------------------------------------------------
+
+To get access to the returned documents, we need to first get the `SearchHits`
+contained in the response:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SearchDocumentationIT.java[search-hits-get]
+--------------------------------------------------
+
+The `SearchHits` provides global information about all hits, like total number
+of hits or the maximum score:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SearchDocumentationIT.java[search-hits-info]
+--------------------------------------------------
+
+Nested inside the `SearchHits` are the individual search results that can
+be iterated over like this:
+
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SearchDocumentationIT.java[search-hits-singleHit]
+--------------------------------------------------
+
+The `SearchHit` provides access to basic information like index, type, docId and
+score of each search hit:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SearchDocumentationIT.java[search-hits-singleHit-properties]
+--------------------------------------------------
+
+Furthermore, it lets you get back the document source, either as a simple
+JSON-String or as a map of key/value pairs. In this map, regular fields 
+are keyed by the field name and contain the field value. Multi-valued fields are
+returned as lists of objects, nested objects as another key/value map. These
+cases need to be case accordingly:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SearchDocumentationIT.java[search-hits-singleHit-source]
+--------------------------------------------------