In today’s article, we’ll show you how to access Elasticsearch using Java.

First, we must install Elasticsearch on our system. If you don’t already have Elasticsearch installed, please refer to my previous article “How to Install Elasticsearch on Linux, MacOS, and Windows”. Of course, this installation step also requires us to install the corresponding Java.

 

Maven configuration

 

For Java development, we must configure the corresponding Elasticsearch information in pom.xml. Mavev Dependency is defined as follows:

< the dependency > < groupId > org. Elasticsearch < / groupId > < artifactId > elasticsearch < / artifactId > < version > 7.3.1 < / version > </dependency>Copy the code

This is the latest version of Elasticsearch as of now. You can view the latest version of Maven Central hosting at any time using the link provided previously.

 

Complete the database query

 

Build a simple model

package com.javacodegeeks.example; public class Person { private String personId; private String name; private String number; public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } public String getPersonId() { return personId; } public void setPersonId(String personId) { this.personId = personId; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return String.format("Person{personId='%s', name='%s', number='%s}", personId, name, number); }}Copy the code

Here, we define a simple Person Model.

 

Defining connection parameters

We will connect to Elasticsearch using the default connection parameters. By default, ES uses two ports: 9200 and 9201

    private static final String HOST = "localhost";
    private static final int PORT_ONE = 9200;
    private static final int PORT_TWO = 9201;
    private static final String SCHEME = "http";

    private static RestHighLevelClient restHighLevelClient;
    private static ObjectMapper objectMapper = new ObjectMapper();

    private static final String INDEX = "persondata";
    private static final String TYPE = "_doc";
Copy the code

Here we define an index called personData whose type is _doc. In the latest version, only one type is supported per index.

Elasticsearch uses two ports, 9200 and 9201, as described in the arguments above. The first port, 9200, is used by the Elasticsearch query server to query the database directly through the RESTful API. The second port, 9201, is used by the REST server to allow external clients to connect and perform operations.

 

Establish a connection

We will create a method to connect to the Elasticsearch database. When establishing a connection to the database, we must provide two ports, because only then can our application connect to the Elasticsearch server and we will be able to perform database operations. Here is the code to establish the connection.

private static synchronized RestHighLevelClient makeConnection() { if(restHighLevelClient == null) { restHighLevelClient  = new RestHighLevelClient( RestClient.builder( new HttpHost(HOST, PORT_ONE, SCHEME), new HttpHost(HOST, PORT_TWO, SCHEME))); } return restHighLevelClient; }Copy the code

Here, we create an instance of RestHighLevelClient. For details about the parameters, see the official Java High Level REST Client document.

Note that we implement the Singleton Design pattern here, so we don’t create multiple connections for ES, saving a lot of memory.

The connection to Elasticsearch is thread-safe because RestHighLevelClient exists. The best time to initialize this connection is when the application requests it or makes the first request to the client. Once this connection client is initialized, it can be used to execute any supported API.

 

Close a connection

Just like in earlier versions of Elasticsearch, we used TransportClient to close it once the query was complete, and once the database interaction was complete with RestHighLevelClient, we also needed to close the connection. Here’s how to do it:

    private static synchronized void closeConnection() throws IOException {
        restHighLevelClient.close();
        restHighLevelClient = null;
    }
Copy the code

We also assign null to the RestHighLevelClient object so that the Singleton schema can be consistent.

 

Insert a document

We can insert data into the database by converting keys and values into a HashMap. The ES database only accepts values in the form of a HashMap. Let’s look at a snippet of code to achieve this:

   private static Person insertPerson(Person person) {

        person.setPersonId(UUID.randomUUID().toString());
        Map<String, Object> dataMap = new HashMap<String, Object>();
        dataMap.put("name", person.getName());
        dataMap.put("number", person.getNumber());
        IndexRequest indexRequest = new IndexRequest(INDEX)
                .id(person.getPersonId()).source(dataMap);
        try {
            IndexResponse response = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
        } catch(ElasticsearchException e) {
            e.getDetailedMessage();
        } catch (java.io.IOException ex){
            ex.getLocalizedMessage();
        }

        /*
        // The following is another way to do it
        // More information https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.3/java-rest-high-document-index.html
        String id = UUID.randomUUID().toString();
        person.setPersonId(id);
        IndexRequest request = new IndexRequest(INDEX);
        request.id(id);
        String jsonString = "{" +
                "\"name\":" + "\"" + person.getName() + "\"" +
                "}";

        System.out.println("jsonString: " + jsonString);
        request.source(jsonString, XContentType.JSON);
        try {
            IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT);

        } catch(ElasticsearchException e) {
            e.getDetailedMessage();
        } catch (java.io.IOException ex){
            ex.getLocalizedMessage();
        }
         */

        return person;
    }
Copy the code

As noted in the code above. That part of the annotated code is another approach. See the link for more information.

Above, we used Java’s UUID class to create a unique identifier for an object. In this way, we can control how object identifiers are made. We could have fixed an ID as well. If so, running multiple times only updates the previous data, and Version automatically increases by 1 after each run.

 

Request the document stored above

After inserting the data into the database, we can confirm the action by issuing a GET request to the Elasticsearch database server. Let’s look at a snippet of how to do this:

 

private static Person getPersonById(String id){ GetRequest getPersonRequest = new GetRequest(INDEX, id); GetResponse getResponse = null; try { getResponse = restHighLevelClient.get(getPersonRequest, RequestOptions.DEFAULT); } catch (java.io.IOException e){ e.getLocalizedMessage(); } return getResponse ! = null ? objectMapper.convertValue(getResponse.getSourceAsMap(), Person.class) : null; }Copy the code

In this case, we query and return data based on the id returned above.

In this query, we provide only the main information about the object that identifies it, the index, and its unique identifier ID. Furthermore, what we get is actually a mapping of values.

 

Update the document

You can easily make update requests to Elasticsearch by first identifying the resource with its index, type, and unique identifier. We can then use the new HashMap Object to update any number of values in the Object. Here is an example code snippet:

 

   private static Person updatePersonById(String id, Person person){
        UpdateRequest updateRequest = new UpdateRequest(INDEX, id)
                .fetchSource(true);    // Fetch Object after its update
        try {
            String personJson = objectMapper.writeValueAsString(person);
            updateRequest.doc(personJson, XContentType.JSON);
            UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
            return objectMapper.convertValue(updateResponse.getGetResult().sourceAsMap(), Person.class);
        }catch (JsonProcessingException e){
            e.getMessage();
        } catch (java.io.IOException e){
            e.getLocalizedMessage();
        }
        System.out.println("Unable to update person");
        return null;
    }
Copy the code

Delete the document

Finally, we can remove data by simply identifying the resource with its index, type, and unique identifier. Let’s look at a snippet of how to do this

private static void deletePersonById(String id) { DeleteRequest deleteRequest = new DeleteRequest(INDEX, TYPE, id); try { DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT); } catch (java.io.IOException e) { e.getLocalizedMessage(); }}Copy the code

We delete the corresponding document based on the passed ID. Of course, we can also do query delete.

 

Run our application

 

Let’s try out our application by doing all of the above. Since this is a normal Java application, we will call each of these methods and print the result of the operation:

public static void main(String[] args) throws IOException { makeConnection(); Person person = new Person(); Person. Elegantly-named setName (" zhang "); System.out.println("Inserting a new Person with name " + person.getName()); person.setNumber("111111"); person = insertPerson(person); System.out.println("Person inserted --> " + person); person = new Person(); Person. Elegantly-named setName (" yao "); System.out.println("Inserting a new Person with name " + person.getName()); person.setNumber("222222"); person = insertPerson(person); System.out.println("Person inserted --> " + person); Person. Elegantly-named setName (" li si "); System.out.println("Changing name to " + person.getName()); updatePersonById(person.getPersonId(), person); System.out.println("Person updated --> " + person); System.out.println("Searching for all documents"); SearchResponse response = searchAll(); System.out.println(response); System.out.println("Searching for a term"); response = searchTerm(); System.out.println(response); System.out.println("Match a query"); response = matchQuery(); System.out.println(response); System. The out. Println (" Getting li si "); Person personFromDB = getPersonById(person.getPersonId()); System.out.println("Person from DB --> " + personFromDB); System.out.println("Deleting " + person.getName()); deletePersonById(personFromDB.getPersonId()); System.out.println("Person " + person.getName() + " deleted!" ); closeConnection(); }Copy the code

The results are as follows:

Inserting a new Person with name three Person INSERTED --> Person{personId=' 33f4162E-0a68-4e66-8717-85151627 2185', insert A new Person with name three Person INSERTED --> Person{personId=' 33f4162E-0a68-4e66-8717-85151627 2185', Name = 'zhang SAN, Number ='111111} Inserting a new Person with name Yao Person INSERTED --> Person{personId='9b477529-6e79-42e8-a50a-21b2d8bc4c13', name=' yao ', Changing name to Person{personId='9b477529- 6e79-42E8 - a50A-21b2d8bc4c13 ', Name = 'bill', number='222222} Searching for all documents {"took":0,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":4,"rela Tion ":" eq "}, "max_score" : 1.0, "hits" : [{" _index ":" persondata ", "_type" : "_doc", "_id" : "52425 a44 - dc06-49 ca - b3df - 26 a8b341391c"," _score ": 1.0," _source ": {" number" : "111111", "name" : "* *"}}, {" _index ":" persondata ", "_type" : "_doc", "_id" : "c76b8670 - ed00-4212 - b 47 b - 46 bc85d588b6 _score ", "" : 1.0," _source ": {" number" : "111111", "name" : "* *"}}, {" _index ":" persondata ", "_type" : "_doc", "_id" : "b 8 bf0466 ea5-43 e0-8188-0 c0712812fb9a ", "_score" : 1.0, "_source" : {" number ":" 111111 ", "name" : "* *"}}, {" _index ":" persondata ", "_ty PE _doc ":" ", "_id" : "468 dabe4-8 - a165 f50-4667-9 ce6e015cb76", "_score" : 1.0, "_source" : {" number ":" 222222 ", "name" : "bill", "personId" :"468dabe4-8f50-4667-a165-9ce6e015cb76"}}]}} Searching for a term {"took":0,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":3,"rela Tion ":" eq "}, "max_score" : 0.9444616, "hits" : [{" _index ":" persondata ", "_type" : "_doc", "_id" : "52425 a44 - dc06-49 ca - a8b3413 b3df - 26 91 c ", "_score" : 0.9444616, "_source" : {" number ":" 111111 ", "name" : "* *"}}, {" _index ":" persondata ", "_type" : "_doc", "_id" : "c76b8670 - ed00-4212-46 bc85d588b6 b47b - ", "_score" : 0.9444616, "_source" : {" number ":" 111111 ", "name" : "* *"}}, {" _index ":" persondata ", "_typ E _doc ":" ", "_id" : "b8bf0466 ea5-43 e0-8188-0 c0712812fb9a", "_score" : 0.9444616, "_source" : {" number ":" 111111 ", "name" : "* *"}}}}] Match a query {"took":0,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":3,"rela Tion ":" eq "}, "max_score" : 1.8889232, "hits" : [{" _index ":" persondata ", "_type" : "_doc", "_id" : "52425 a44 - dc06-49 ca - a8b3413 b3df - 26 91 c ", "_score" : 1.8889232, "_source" : {" number ":" 111111 ", "name" : "* *"}}, {" _index ":" persondata ", "_type" : "_doc", "_id" : "c76b8670 - ed00-4212-46 bc85d588b6 b47b - ", "_score" : 1.8889232, "_source" : {" number ":" 111111 ", "name" : "* *"}}, {" _index ":" persondata ", "_typ E _doc ":" ", "_id" : "b8bf0466 ea5-43 e0-8188-0 c0712812fb9a", "_score" : 1.8889232, "_source" : {" number ":" 111111 ", "name" : "* *"}}}}] Person{personId=' 9b477529-6e79-42E8-a50a-21b2d8bc4c13 ', name=' 9b477529-6e79-42E8-a50a-21b2d8bc4c13 ', number='222222}Copy the code

The source code for the entire project can be found at github.com/liu-xiao-gu…

More information:

[1] A single index is slow when RestHighLevelClient is used