Hibernate Search - Elasticsearch with JSON manipulation

Elasticsearch with JSON manipulation


Elasticsearch ships with many features. It is possible that at some point, one feature you need will not be exposed by the Search DSL.

To work around such limitations, Hibernate Search provides ways to:

Transform the HTTP request sent to Elasticsearch for search queries.

Read the raw JSON of the HTTP response received from Elasticsearch for search queries.

Direct changes to the HTTP request may conflict with Hibernate Search features and be supported differently by different versions of Elasticsearch.

Similarly, the content of the HTTP response may change depending on the version of Elasticsearch, depending on which Hibernate Search features are used, and even depending on how Hibernate Search features are implemented.

Thus, features relying on direct access to HTTP requests or responses cannot be guaranteed to continue to work when upgrading Hibernate Search, even for micro upgrades (x.y.z to x.y.(z+1)).

Use this at your own risk.

Most simple use cases will only need to change the HTTP request slightly, as shown below.


Transforming the Elasticsearch request manually in a search query

List<Book> hits = searchSession.search( Book.class )
        .extension( ElasticsearchExtension.get() ) 
        .where( f -> f.match()
                .field( "title" )
                .matching( "robot" ) )
        .requestTransformer( context -> { 
            Map<String, String> parameters = context.getParametersMap(); 
            parameters.put( "search_type", "dfs_query_then_fetch" );

            JsonObject body = context.getBody(); 
            body.addProperty( "min_score", 0.5f );
        } )
        .fetchHits( 20 ); 

Build the query as usual, but using the Elasticsearch extension so that Elasticsearch-specific options are available.
Add a request transformer to the query. Its transform method will be called whenever a request is about to be sent to Elasticsearch.
Inside the transform method, alter the HTTP query parameters.
It is also possible to alter the request’s JSON body as shown here, or even the request’s path (not shown in this example).
Retrieve the result as usual.
For more complicated use cases, it is possible to access the raw JSON of the HTTP response, as shown below.

Accessing the Elasticsearch response body manually in a search query

ElasticsearchSearchResult<Book> result = searchSession.search( Book.class )
        .extension( ElasticsearchExtension.get() ) 
        .where( f -> f.match()
                .field( "title" )
                .matching( "robt" ) )
        .requestTransformer( context -> { 
            JsonObject body = context.getBody();
            body.add( "suggest", jsonObject( suggest -> { 
                suggest.add( "my-suggest", jsonObject( mySuggest -> {
                    mySuggest.addProperty( "text", "robt" );
                    mySuggest.add( "term", jsonObject( term -> {
                        term.addProperty( "field", "title" );
                    } ) );
                } ) );
            } ) );
        } )
        .fetch( 20 ); 

JsonObject responseBody = result.getResponseBody(); 
JsonArray mySuggestResults = responseBody.getAsJsonObject( "suggest" ) 
        .getAsJsonArray( "my-suggest" );

Build the query as usual, but using the Elasticsearch extension so that Elasticsearch-specific options are available.
Add a request transformer to the query.
Add content to the request body, so that Elasticsearch will return more data in the response. Here we’re asking Elasticsearch to apply a suggester.
Retrieve the result as usual. Since we used the Elasticsearch extension when building the query, the result will have an Elasticsearch-specific type: ElasticsearchSearchResult.
Get the response body as a JsonObject.
Extract useful information from the response body. Here we’re extracting the result of the suggester we configured above.
Gson’s API for building JSON objects is quite verbose, so the example above relies on a small, custom helper method to make the code more readable:

private static JsonObject jsonObject(Consumer<JsonObject> instructions) {
    JsonObject object = new JsonObject();
    instructions.accept( object );
    return object;
}

Comments

Popular posts from this blog

Today Walkin 14th-Sept

Spring Elasticsearch Operations