Searching for documents

edit

Indexed documents are available for search in near real-time.

See the Elasticsearch documentation for a full explanation of search requests: search your data, the query DSL, and search APIs.

Simple search query

edit

There are many types of search queries that can be combined. We will start with the simple text match query, searching for bikes in the products index.

The search result has a hits properties that contains the documents that matched the query along with information about the total number of matches that exist in the index.

The total value comes with a relation that indicates if the total is exact (eq — equal) or approximate (gte — greater than or equal).

Each returned document comes with its relevance score and additional information about its location in the index.

String searchText = "bike";

SearchResponse<Product> response = esClient.search(s -> s
    .index("products") 
    .query(q -> q      
        .match(t -> t   
            .field("name")  
            .query(searchText)
        )
    ),
    Product.class      
);

TotalHits total = response.hits().total();
boolean isExactResult = total.relation() == TotalHitsRelation.Eq;

if (isExactResult) {
    logger.info("There are " + total.value() + " results");
} else {
    logger.info("There are more than " + total.value() + " results");
}

List<Hit<Product>> hits = response.hits().hits();
for (Hit<Product> hit: hits) {
    Product product = hit.source();
    logger.info("Found product " + product.getSku() + ", score " + hit.score());
}

Name of the index we want to search.

The query part of the search request (a search request can also have other components like aggregations).

Choose a query variant among the many available. We choose here the match query (full text search).

Configure the match query: we search for a term in the name field.

The target class for the matching documents. We use Product here, just like in get request examples.

Similarly to get operations, you can fetch documents matching your query as raw JSON by using a corresponding target class instead of Product, like JSON-P’s JsonValue or Jackson’s ObjectNode.

Nested search queries

edit

Elasticsearch allows individual queries to be combined to build more complex search requests. In the example below we will search for bikes with a maximum price of 200.

String searchText = "bike";
double maxPrice = 200.0;

// Search by product name
Query byName = MatchQuery.of(m -> m 
    .field("name")
    .query(searchText)
)._toQuery(); 

// Search by max price
Query byMaxPrice = RangeQuery.of(r -> r
    .number(n -> n
    .field("price")
    .gte(maxPrice)) 
)._toQuery();

// Combine name and price queries to search the product index
SearchResponse<Product> response = esClient.search(s -> s
    .index("products")
    .query(q -> q
        .bool(b -> b 
            .must(byName) 
            .must(byMaxPrice)
        )
    ),
    Product.class
);

List<Hit<Product>> hits = response.hits().hits();
for (Hit<Product> hit: hits) {
    Product product = hit.source();
    logger.info("Found product " + product.getSku() + ", score " + hit.score());
}

We’re creating the queries for individual criteria separately.

A MatchQuery is a query variant that we have to turn into the Query union type. See variant types for additional details.

Elasticsearch range query accepts a large range of value types. We create here a JSON representation of the maximum price.

The search query is a boolean query that combines the text search and max price queries.

Both queries are added as must as we want results to match all criteria.

Templated search

edit

A search template is a stored search that you can run with different variables. Search templates let you change your searches without modifying your application code.

Before running a template search, you first have to create the template. This is a stored script that returns the search request body, and is usually defined as a Mustache template. This stored script can be created outside the application, and also with the Java API Client:

// Create a script
esClient.putScript(r -> r
    .id("query-script") 
    .script(s -> s
        .lang("mustache")
        .source("{\"query\":{\"match\":{\"{{field}}\":\"{{value}}\"}}}")
    ));

Identifier of the template script to create.

To use the search template, use the searchTemplate method to refer to the script and provide values for its parameters:

SearchTemplateResponse<Product> response = esClient.searchTemplate(r -> r
        .index("some-index")
        .id("query-script") 
        .params("field", JsonData.of("some-field")) 
        .params("value", JsonData.of("some-data")),
    Product.class
);

List<Hit<Product>> hits = response.hits().hits();
for (Hit<Product> hit: hits) {
    Product product = hit.source();
    logger.info("Found product " + product.getSku() + ", score " + hit.score());
}

Identifier of the template script to use.

Template parameter values.

For more in-depth information, see the Elasticsearch search template documentation.

The source code for the examples above can be found in the Java API Client tests.