Java High Level REST Client Tips

This is the article on the 11th day of Elastic Stack (Elasticsearch) Advent Calendar 2019.

Introduction

By using "Java High Level REST Client", you can access Elasticsearch via http from Java application.

Previously "TransportClient" was used but is obsolete in 8.0 For, "Java High Level REST Client Tips" or "[Java Low Level REST Client Tips]" Client](https://www.elastic.co/guide/en/elasticsearch/client/java-rest/master/java-rest-low.html) "is recommended.

This time, I will introduce a usage example focusing on search (Search API).

important point

Example) Elasticsearch(7.0) Java High Level REST(7.0) → OK Elasticsearch(7.0) Java High Level REST(6.8) → NG

Preparation

Elasticsearch environment → ElasticCloud Java8(JDK1.8.0)

Create index "qiita"

PUT /qiita
{
  "mappings": {
    "properties": {
      "user":    { "type": "keyword" },  
      "post_date":  { "type": "date"  }, 
      "active":  { "type": "boolean"  },
      "message":   { "type": "text"  }     
    }
  }
}

POST qiita/_doc
{
    "user" : "qiita",
    "post_date" : "2019-12-11T00:10:30Z",
    "active":"false",
    "message" : "trying out High Level REST Client"
}

GET qiita/_search
...
      {
        "_index" : "qiita",
        "_type" : "_doc",
        "_id" : "yjDo5m4Bj4TzcUq3pmoX",
        "_score" : 1.0,
        "_source" : {
          "user" : "qiita",
          "post_date" : "2019-12-11T00:10:30Z",
          "active" : "false",
          "message" : "trying out High Level REST Client"
        }
      }
...

pon.xml

    <dependencies>
        ...
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.5.0</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
            <version>7.5.0</version>
        </dependency>
        ...
    </dependencies>

Create Clinent for connection

Basically, in the example of Initialization no problem

RestHighLevelClient client = new RestHighLevelClient(
        RestClient.builder(
                new HttpHost("localhost", 9200, "http"),
                new HttpHost("localhost", 9201, "http")));

client.close();

For Elastic Cloud

If you have introduced an authentication function such as Elastic Cloud, you need to make the following settings.

String username = "elastic";
String password = "pass";
String host = "host";
int port = 9243;
int nextPort = 9244;
String protocol = "https";


final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(
                AuthScope.ANY,
                new UsernamePasswordCredentials(username, password));

RestClientBuilder client = RestClient.builder(
                new HttpHost(host, port, protocol),
                new HttpHost(host, nextPort, protocol))
                .setHttpClientConfigCallback((h) -> h.setDefaultCredentialsProvider(credentialsProvider));

RestHighLevelClient client = new RestHighLevelClient(client);

client.close();

Data acquisition

You can get something similar to "GET qiita / _search" by using the client you created earlier.

try (RestHighLevelClient client = new RestHighLevelClient(client)) {

            SearchSourceBuilder searchBuilder = SearchSourceBuilder.searchSource();
            // quite*You can specify a wildcard like
            SearchRequest request = new SearchRequest("qiita").source(searchBuilder);
            //Data acquisition
            SearchHits hits = client.search(request, RequestOptions.DEFAULT).getHits();
            for(SearchHit hit : hits) {
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();

          //Set the value for each record
                String user = (String) sourceAsMap.get("user");
                String post_date = (String) sourceAsMap.get("post_date");
                String message = (String) sourceAsMap.get("message");
    
                System.out.println(String.format("user:%s data:%s message:%s",user , post_date, message));
            }
}catch (IOException io) {}

Reference: Search API

Size setting

Set to "Search Source Builder" The default size is only 10 items

// default 10
SearchSourceBuilder searchBuilder = SearchSourceBuilder.searchSource();
searchBuilder.size(100);
            

sort

Set to "Search Source Builder" Switch between ASC and DESC with Sort Order

SearchSourceBuilder searchBuilder = SearchSourceBuilder.searchSource();
searchBuilder.sort(new FieldSortBuilder("_id").order(SortOrder.DESC));

Search query (filter)

Building Queries is all about Here are some simple ones that can be used (not all have been tried) Basically, set to "SearchSourceBuilder"

Range Query (Specify period)

Obtained from "2019-12-12T00: 10: 30" to "2019-12-13T00: 10: 31" in Japan time

SearchSourceBuilder searchBuilder = SearchSourceBuilder.searchSource();

QueryBuilder query = QueryBuilders
       .rangeQuery("post_date")
       .from("2019-12-12T00:10:30")
       .to("2019-12-13T00:10:31")
       .timeZone("+09:00");

searchBuilder.query(query);

It is necessary to be careful if you specify as follows Get from "2019-12-09T 00: 00: 00.000" to "2019-12-13T 23: 59: 59.999"

QueryBuilder query = QueryBuilders
       .rangeQuery("post_date")
       .from("2019-12-12")
       .to("2019-12-13")
       .timeZone("+09:00");

searchBuilder.query(query);

To get the data for 12 days only, it will be as follows

"Include Lower" to include from: true "Include Upper" to include to: true

QueryBuilder query = QueryBuilders
       .rangeQuery("post_date")
       .from("2019-12-12")
       .to("2019-12-13")
    .includeLower(true)
    .includeUpper(false)
       .timeZone("+09:00");

searchBuilder.query(query);

Match Query The query for full-text search is below

SearchSourceBuilder searchBuilder = SearchSourceBuilder.searchSource();

QueryBuilder query = QueryBuilders.matchQuery("message", "REST Level ");
QueryBuilder query = QueryBuilders.matchQuery("message", "Level REST");
QueryBuilder query = QueryBuilders.matchPhraseQuery("message", "REST Level");
//Since it is a phrase search, 0 acquisitions
QueryBuilder query = QueryBuilders.matchPhraseQuery("message", "Level REST");

searchBuilder.query(query);

Term Query The Term query that is searched by exact match is as follows

QueryBuilder query = QueryBuilders.termQuery("user", "qiita");

Bool Query(AND OR NOT)

Elastic Elastic SQL Description
must AND
filter AND Ignore the score
should OR
mustnot NOT

AND Either "must" or "filter" is acceptable

An example of "filter" looks like this

SearchSourceBuilder searchBuilder = SearchSourceBuilder.searchSource();

BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
QueryBuilder query1 = QueryBuilders.matchQuery("message", "JAVA");
QueryBuilder query2 = QueryBuilders.matchQuery("message", "REST");
boolQuery.filter(query1);
boolQuery.filter(query2);

searchBuilder.query(boolQuery);

OR

BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
QueryBuilder query1 = QueryBuilders.matchQuery("message", "JAVA");
QueryBuilder query2 = QueryBuilders.matchQuery("message", "REST");
boolQuery.should(query1);
boolQuery.should(query2);

NOT

BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
QueryBuilder query = QueryBuilders.termQuery("user", "qiita");
boolQuery.mustNot(query);

How to search in JSON format?

You can also get it in JSON format as shown below. Search Template API

SearchTemplateRequest request = new SearchTemplateRequest();
request.setRequest(new SearchRequest("qiita"));

request.setScriptType(ScriptType.INLINE);
request.setScript(
                    "{" +
                            "  \"query\": { \"match\" : { \"{{field}}\" : \"{{value}}\" } }," +
                            "  \"size\" : \"{{size}}\"" +
                            "}");

Map<String, Object> scriptParams = new HashMap<>();
scriptParams.put("field", "message");
scriptParams.put("value", "REST");
scriptParams.put("size", 5);
request.setScriptParams(scriptParams);

SearchTemplateResponse response = client.searchTemplate(request, RequestOptions.DEFAULT);
SearchResponse searchResponse = response.getResponse();
SearchHit[] results = searchResponse.getHits().getHits();

Frozen indices It can be used from "Java High Level REST Client" of 6.8.1 Note that it is not reflected when "Frozen indices" is implemented in Elastic saerch.

How to Search Freeze Index using Java High Level REST Client

SearchRequest request = new SearchRequest("qiita").source(searchBuilder);
request.indicesOptions(IndicesOptions.fromOptions(
                true,
                true,
                true,
                false,
                request.indicesOptions().allowAliasesToMultipleIndices(),
                request.indicesOptions().forbidClosedIndices(),
                request.indicesOptions().ignoreAliases(),
                true //← Set whether frozen index can be searched here true:Searchable
        ));

Reference material

At the end

There are few Japanese articles on "Java High Level REST Client", and I often read English and Chinese articles. Although it is mostly written in the document, after adding new features, it seems that "Java High Level REST Client" does not support it, so you may have to read the source and release notes.

Tomorrow is @ NAO_MK2.

Recommended Posts

Java High Level REST Client Tips
Migrate from Transport Client to Rest High Level Client
Java tips, tips
Java Tips
Java mqtt client
Java tips --StaticUtility class modifier
Java tips --Spring execution Summary
[Java] Server Client Communication 1 (Unfinished)
[Java] Tips for writing source