Java High Level REST Client tutorial

Explain

I've written an article about using jest to operate es before, but I feel it's a bit messy. Moreover, when jest operates es, many things are still some of the ES used. It's better to use the official java client directly.

So I studied the high-level-client, which is very useful, and the official documents are very detailed. Recommended.

Let's go to the main topic. Most of the writing is based on official documents. I encapsulated a Criteria class for query, which is convenient for query.

Official document of elasticsearch: https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html 

Official document of Java High Level REST Client https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html Most of the following implementation is based on this document.

es client Google plug-in, convenient for students who can't turn over the wall. ElasticSearch-Head_v0.1.4.crx  https://lanzous.com/iccd9sj

maven reference

        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.6.2</version>
        </dependency>
      <!-- The following non mandatory references are some auxiliary Toolkits -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>

operation

1. There are mainly some operations of template and index.

2. Data operations include insert, bulk insert, delete, update and update according to conditions.

3. For data query, there are = (TermQuery), < = > = (rangequery), in (TermQuery), and not in (mustnot + TermQuery) encapsulated in the Criteria class.

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.Data;
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.*;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.*;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.UpdateByQueryRequest;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * @author: sun
 * @create: 2020-04-27
 **/
public class Main {
    RestHighLevelClient client = null;

    @Before
    public void before() {
        client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("127.0.0.1", 9200, "http")));
    }

    @Test
    public void putTemplate() throws IOException {
        PutIndexTemplateRequest request = new PutIndexTemplateRequest("test_template");
        //Alias, all created according to the template index This alias will be added. When querying, you can query aliases, and you can query multiple names with different names at the same time index,According to this method, the index Logic such as daily or monthly generation.
        request.alias(new Alias("test_index"));
        request.order(10);
        //What to match index. Creating index Will take effect.
        request.patterns(CollUtil.newArrayList("test_index*"));
        request.settings(Settings.builder()
                //How long can the data be found after insertion? The real-time requirements are high and can be reduced
                .put("index.refresh_interval", "10s")
                //Transport log, setting with high requirements for data security request,Default:request
                .put("index.translog.durability", "async")
                .put("index.translog.sync_interval", "120s")
                //Number of slices
                .put("index.number_of_shards", "5")
                //Number of copies
                .put("index.number_of_replicas", "0")
                //The maximum number of data in a single query. The default is 10000. Do not set it too high. If you have export requirements, you can query by batch according to query criteria.
                .put("index.max_result_window", "100000"));
        //Build with official tools json. You can splice one directly json String, you can also use map Nesting.
        XContentBuilder jsonMapping = XContentFactory.jsonBuilder();
        //See official documents for all data types:https://www.elastic.co/guide/en/elasticsearch/reference/7.4/mapping-types.html#_core_datatypes
        jsonMapping.startObject().startObject("properties")
                .startObject("testId").field("type", "long").endObject()
                .startObject("price").field("type", "double").endObject()
                //keyword Type will not be stored word segmentation
                .startObject("name").field("type", "keyword").endObject()
                //Specify word breaker
                .startObject("content").field("type", "text").field("analyzer", "ik_max_word").endObject()
                .startObject("createTime").field("type", "date").field("format", "yyyy-MM-dd HH:mm:ss").endObject()
                .endObject().endObject();
        request.mapping(jsonMapping);
        //Set to true Force creation only, not update index templates. If it already exists, it will fail
        request.create(false);
        AcknowledgedResponse response = client.indices().putTemplate(request, RequestOptions.DEFAULT);
        if (response.isAcknowledged()) {
            Console.log("Template created successfully!");
        } else {
            Console.log("Failed to create template!");
        }
    }

    @Test
    public void getTemplate() throws IOException {
        GetIndexTemplatesRequest getIndexTemplatesRequest = new GetIndexTemplatesRequest("test*");
        GetIndexTemplatesResponse getIndexTemplatesResponse = client.indices().getIndexTemplate(getIndexTemplatesRequest, RequestOptions.DEFAULT);
        List<IndexTemplateMetaData> indexTemplates = getIndexTemplatesResponse.getIndexTemplates();
        indexTemplates.forEach(t -> {
            Console.log(t.name());
        });
    }

    @Test
    public void createIndex() throws IOException {
        CreateIndexRequest request = new CreateIndexRequest("test_index_tmp");
        //It can also be used for index Set separately. However, since we have already set the template, we will not set it here.
        //index In fact, it does not need to be created separately. When inserting data, if all does not exist, the index will be created automatically.
        //request.settings();
        //request.mapping();
        //request.alias()
        CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
        if (createIndexResponse.isAcknowledged()) {
            Console.log("Establish index Success!");
        } else {
            Console.log("Establish index fail!");
        }
    }

    @Test
    public void getIndex() throws IOException {
        GetIndexRequest request = new GetIndexRequest("test_index*");
        GetIndexResponse response = client.indices().get(request, RequestOptions.DEFAULT);
        String[] indices = response.getIndices();
        for (String indexName : indices) {
            Console.log("index name:{}", indexName);
        }
    }

    @Test
    public void delIndex() throws IOException {
        DeleteIndexRequest request = new DeleteIndexRequest("test_index*");
//        DeleteIndexRequest request = new DeleteIndexRequest("test_index_tmp");
        AcknowledgedResponse response = client.indices().delete(request, RequestOptions.DEFAULT);
        if (response.isAcknowledged()) {
            Console.log("delete index Success!");
        } else {
            Console.log("delete index fail!");
        }
    }

    @Test
    public void insertData() throws IOException {
        //Insert data, index If it does not exist, it will be automatically matched according to the template establish. index There is no need to create one every day. If it is for flexible management, it is recommended to create one every month as a minimum yyyyMM. 
        IndexRequest request = new IndexRequest("test_index_" + DateUtil.format(new Date(), "yyyyMM"));
        //It's better not to customize id It will affect the insertion speed.
//        request.id("id");
        TestData testData = new TestData();
        testData.setTestId(RandomUtil.randomLong(9999999999L));
        testData.setPrice(10.0D);
        testData.setName(RandomUtil.randomString(8));
        testData.setContent("");
        testData.setCreateTime(new Date());
        request.source(new JSONObject(testData, new JSONConfig().setDateFormat(DatePattern.NORM_DATETIME_PATTERN)).toString()
                , XContentType.JSON);
        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
        Console.log(response);
    }
    @Test
    public void getById() throws IOException {
        //Note that the query here uses aliases.
        GetRequest request = new GetRequest("test_index", "C-54v3EB_Nn045D7VGjz");
        String[] includes = {"name","price"};
        String[] excludes = Strings.EMPTY_ARRAY;
        FetchSourceContext fetchSourceContext = new FetchSourceContext(true,includes,excludes);
        //Query only specific fields. If all fields need to be queried, this item is not set.
        request.fetchSourceContext(fetchSourceContext);
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        Console.log(response);
        Console.log(JSONUtil.toBean(response.getSourceAsString(),TestData.class));
    }
    
    @Test
    public void delById() throws IOException {
        DeleteRequest request = new DeleteRequest("test_index", "7e5gv3EB_Nn045D7pGdA");
        DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);
        Console.log(response);
    }
    @Test
    public void multiGetById() throws IOException {
        //Multiple basis id query
        MultiGetRequest request = new MultiGetRequest();
        request.add("test_index","D-56v3EB_Nn045D7vmjh");
        //Two ways of writing
        request.add(new MultiGetRequest.Item(
                "test_index",
                "MO57v3EB_Nn045D7aGgU"));
        MultiGetResponse response = client.mget(request, RequestOptions.DEFAULT);
        for (MultiGetItemResponse itemResponse : response) {
            Console.log(itemResponse.getResponse().getSourceAsString());
        }
    }
    
    @Test
    public void batchInsertData() throws IOException {
        //Batch insert data, update and delete the same
        BulkRequest request = new BulkRequest("test_index_" + DateUtil.format(new Date(), "yyyyMM"));
        for (int i = 0; i < 1000; i++) {
            TestData testData = new TestData();
            testData.setTestId(RandomUtil.randomLong(9999999999L));
            testData.setPrice(100.0D);
            testData.setName(RandomUtil.randomString(8));
            testData.setContent("");
            testData.setCreateTime(new Date());
            request.add(new IndexRequest().source(new JSONObject(testData, new JSONConfig().setDateFormat(DatePattern.NORM_DATETIME_PATTERN)).toString()
                    , XContentType.JSON));
        }
        BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);
        Console.log("insert state:{} Number:{} ",response.status(),response.getItems().length);
    }
    @Test
    public void updateByQuery() throws IOException {
        UpdateByQueryRequest request = new UpdateByQueryRequest("test_index");
        //By default, version conflicts are aborted UpdateByQueryRequest Process, but you can use the following command instead
        //Set version conflict to continue
        request.setConflicts("proceed");
        //Set update conditions
        request.setQuery(QueryBuilders.rangeQuery("createTime").gte("2020-04-28 11:30:24").lte("2020-04-28 15:30:24"));
        //Limit number of updates
        request.setMaxDocs(10);
        request.setScript(new Script(ScriptType.INLINE,"painless","ctx._source.testId=999999;", Collections.emptyMap()));
        BulkByScrollResponse response = client.updateByQuery(request, RequestOptions.DEFAULT);
        Console.log(response);
    }
    @Test
    public void query() throws IOException {
        SearchRequest request = new SearchRequest("test_index");
        SearchSourceBuilder builder = Criteria.create().addRangeQuery("createTime", "2020-04-28 11:30:24", "2020-04-28 15:30:24").builder();
        builder.from(0);
        builder.size(11);
        builder.sort("createTime", SortOrder.ASC);
        //Source data is not returned. There's only data like the number.
//        builder.fetchSource(false);
        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        for (SearchHit hit : hits) {
            Console.log(hit.getSourceAsString());
        }
        Console.log("Total:{}",response.getHits().getTotalHits().value);
    }

    @After
    public void after() throws IOException {
        client.close();
    }
}

@Data
class TestData {
    private long testId;
    private double price;
    private String name;
    private String content;
    private Date createTime;
}

Criteria class

import cn.hutool.core.util.StrUtil;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;

import java.util.List;

/**
 * Compound query encapsulation
 */
public class Criteria {
    private final BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
    
    public static Criteria create(){
        return new Criteria();
    }
    
    /**
     * After the condition is added, get the object to be operated
     * 
     * @return
     */
    public SearchSourceBuilder builder() {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        return searchSourceBuilder.query(boolQueryBuilder);
    }

    /**
     * Add condition query
     * 
     * @param fieldName
     * @param fieldValue
     */
    public Criteria addTermQuery(String fieldName, String fieldValue) {
        if (StrUtil.isNotBlank(fieldName) && StrUtil.isNotBlank(fieldValue)) {
            boolQueryBuilder.filter(QueryBuilders.termQuery(fieldName, fieldValue));
        }
        return this;
    }
    /**
     * Add condition query
     * It is mainly aimed at the exact match of fieldValue after content segmentation
     * @param fieldName
     * @param fieldValue
     */
    public Criteria addMatchPhraseQuery(String fieldName, String fieldValue) {
        if (StrUtil.isNotBlank(fieldName) && StrUtil.isNotBlank(fieldValue)) {
            boolQueryBuilder.filter(QueryBuilders.matchPhraseQuery(fieldName, fieldValue));
        }
        return this;
    }

    /**
     * Add interval query
     * 
     * @param fieldName
     * @param gteValue
     * @param lteValue
     */
    public Criteria addRangeQuery(String fieldName, Object gteValue, Object lteValue) {
        if (StrUtil.isNotBlank(fieldName)) {
            boolQueryBuilder.filter(QueryBuilders.rangeQuery(fieldName).gte(gteValue).lte(lteValue).includeLower(true)
                    .includeUpper(true));
        }
        return this;
    }

    /**
     * Add include query, equivalent to in in sql
     * 
     * @param fieldName
     * @param values
     */
    public Criteria addTermsQuery(String fieldName, List<?> values) {
        if (StrUtil.isNotBlank(fieldName) && values != null && values.size() > 0) {
            boolQueryBuilder.filter(QueryBuilders.termsQuery(fieldName, values));
        }
        return this;
    }
    
    /**
     * Add no query, equivalent to not in sql
     * 
     * @param fieldName
     * @param values
     */
    public Criteria addNotTermsQuery(String fieldName, List<?> values) {
        if (StrUtil.isNotBlank(fieldName) && values != null && values.size() > 0) {
            boolQueryBuilder.mustNot(QueryBuilders.termsQuery(fieldName, values));
        }
        return this;
    }
    
}

Tags: Java ElasticSearch JSON Junit

Posted on Thu, 07 May 2020 13:00:35 -0400 by rajan