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
    .field("price")
    .gte(JsonData.of(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.

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