1. 程式人生 > 實用技巧 >JAVA操作ES

JAVA操作ES

1. pom.xml

  <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>7.8.1</version>
        </dependency>

        <dependency>
            <groupId>org.elasticsearch.client</
groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.8.1</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</
artifactId> <version>4.5.12</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.58</version> </dependency
> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.9</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.3</version> </dependency> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.3</version> </dependency>

2.EsConfig

package com.example.demo.es;

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.springframework.context.annotation.Bean;

/**
 * @ProjectName: pet_data
 * @Package: com.example.demo.es
 * @ClassName: EsConfig
 * @Author: Devin.W.Zhang
 * @Description:
 * @Date: 12/21/2020 4:48 PM
 * @Version: 1.0
 */
public class EsConfig {
    /**
     * es restful client builder
     *
     * @return restful client
     */
    @Bean
    public RestClientBuilder restClientBuilder() {
        // 設定IP
        HttpHost esHost = new HttpHost("localhost", 9200);
        RestClientBuilder restClientBuilder = RestClient.builder(esHost);
        // setPassword(restClientBuilder);
        setTimeout(restClientBuilder);
        return restClientBuilder;
    }

    /**
     * 設定超時時間
     */
    private void setTimeout(RestClientBuilder restClientBuilder) {
        restClientBuilder.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
            @Override
            public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder builder) {
                return builder.setConnectTimeout(3000)
                        .setSocketTimeout(50000);
            }
        });
    }

    /**
     * 設定ES密碼
     */
    private void setPassword(RestClientBuilder restClientBuilder) {
        // 設定密碼
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("userName", "password"));


        restClientBuilder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
            @Override
            public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpAsyncClientBuilder) {
                return httpAsyncClientBuilder
                        .setDefaultCredentialsProvider(credentialsProvider)
                        .setDefaultIOReactorConfig(
                                IOReactorConfig.custom()
                                        .setIoThreadCount(4)
                                        .build()
                        );
            }
        });
    }
}

3.EsUtils

package com.example.demo.es;

import com.alibaba.fastjson.JSON;
import org.apache.commons.beanutils.BeanUtils;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
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.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @ProjectName: pet_data
 * @Package: com.example.demo.es
 * @ClassName: EsUtils
 * @Author: Devin.W.Zhang
 * @Description: ES 操作工具類
 * @Date: 12/22/2020 10:58 AM
 * @Version: 1.0
 */
public class EsUtils<T> {

    public static final String INDEX = "product";

    private final RestHighLevelClient restHighLevelClient;

    public EsUtils() {
        EsConfig esConfig = new EsConfig();
        RestClientBuilder restClientBuilder = esConfig.restClientBuilder();
        restHighLevelClient = new RestHighLevelClient(restClientBuilder);
    }

    /**
     * 索引是否存在
     *
     * @param indexName 索引名稱
     * @return true/false
     */
    public boolean existIndex(String indexName) {
        GetIndexRequest request = new GetIndexRequest();
        request.indices(indexName);
        try {
            return restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 建立索引,新版ES插入資料時自動建立
     *
     * @param index 索引
     * @return 返回索引建立結果
     * @throws IOException exception
     */
    public CreateIndexResponse createIndex(String index) throws IOException {
        CreateIndexRequest createIndexRequest = new CreateIndexRequest(index);
        return restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
    }

    /**
     * 刪除索引
     *
     * @param index 索引
     * @return 返回刪除結果
     * @throws IOException exception
     */
    public AcknowledgedResponse deleteIndex(String index) throws IOException {
        DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(index);
        return restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
    }

    /**
     * 通過id獲取資料
     *
     * @param id 主鍵
     * @return 返回查詢到的結果
     * @throws IOException exception
     */
    public T get(String id, Class<T> classT) throws Exception {
        System.out.println(String.format("get the data from es, id:%s", id));
        GetRequest request = new GetRequest(INDEX, id);
        GetResponse getResponse = restHighLevelClient.get(request, RequestOptions.DEFAULT);
        Map<String, Object> result = getResponse.getSourceAsMap();
        System.out.println(String.format("the es response:%s", result));
        T t = convertMap2Model(result, classT);
        System.out.println(String.format("change the result to %s: ,the result is :%s", classT, t));
        return t;
    }

    /**
     * 新增/修改資料
     *
     * @param t          資料物件
     * @param primaryKey 主鍵欄位名
     * @return 儲存結果
     * @throws Exception exception
     */
    public IndexResponse save(T t, String primaryKey) throws Exception {
        IndexRequest indexRequest = new IndexRequest(INDEX);
        indexRequest.source(JSON.toJSONString(t), XContentType.JSON);
        indexRequest.id(getId(t, primaryKey));
        return restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
    }

    /**
     * 批量 新增/修改資料
     *
     * @param list       資料list
     * @param primaryKey 主鍵
     * @return 返回儲存結果
     * @throws Exception exception
     */
    public BulkResponse batchSave(List<T> list, String primaryKey) throws Exception {
        BulkRequest bulkRequest = new BulkRequest();
        IndexRequest indexRequest;
        for (T item : list) {
            indexRequest = new IndexRequest(INDEX);
            indexRequest.source(JSON.toJSONString(item), XContentType.JSON);
            indexRequest.id(getId(item, primaryKey));
            bulkRequest.add(indexRequest);
        }
        return restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
    }

    /**
     * 查詢符合查詢條件的所有資料
     *
     * @param queryBuilder queryBuilder
     * @param orders       排序map
     * @param tClass       class
     * @return 返回結果list
     * @throws Exception exception
     */
    public List<T> query(QueryBuilder queryBuilder, Map<String, SortOrder> orders, Class<T> tClass) throws Exception {
        final int currentPage = 1;
        final int pageSize = 100000;
        Object[] obj = pageQuery(currentPage, pageSize, queryBuilder, orders, tClass);
        return (List<T>) obj[1];
    }

    /**
     * 分頁查詢
     * <p>
     * 注意當 (currentPage * pageSize >10000) 該分頁查詢會報錯,
     * 通過postman put方式呼叫 http://127.0.0.1:9200/_all/_settings?preserve_existing=true 設定 {"index.max_result_window" : "1000000"}
     * 設定成功會返回 {"acknowledged": true}
     * </p>
     *
     * @param currentPage  當前頁
     * @param pageSize     每頁條數
     * @param queryBuilder queryBuilder
     * @param orders       排序map
     * @param tClass       class
     * @return 返回 總條數和資料list
     * @throws Exception exception
     */
    public Object[] pageQuery(int currentPage, int pageSize, QueryBuilder queryBuilder, Map<String, SortOrder> orders, Class<T> tClass) throws Exception {
        Object[] result = new Object[2];

        long totalCount;
        List<T> list = new ArrayList<>();

        SearchRequest request = new SearchRequest();
        request.indices(INDEX);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder);
        request.source(searchSourceBuilder);

        //下面的配置為true則如果總條數顯示為實際查詢到的條數,否則最大隻顯示10000
        searchSourceBuilder.trackTotalHits(true);
        //起始
        searchSourceBuilder.from((currentPage - 1) * pageSize);
        //預設最大10000
        searchSourceBuilder.size(pageSize);
        //排序
        if (null != orders) {
            for (Map.Entry<String, SortOrder> order : orders.entrySet()) {
                searchSourceBuilder.sort(order.getKey(), order.getValue());
            }
        }

        SearchResponse res = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        totalCount = res.getHits().getTotalHits().value;
        System.out.println(String.format("totalHits: %s", totalCount));

        if (res.getHits().getHits() != null) {
            SearchHit[] hits = res.getHits().getHits();
            for (SearchHit hit : hits) {
                Map<String, Object> resultOne = hit.getSourceAsMap();
                T t = convertMap2Model(resultOne, tClass);
                list.add(t);
            }
        }
        result[0] = totalCount;
        result[1] = list;
        return result;
    }


    /*下面是一些輔助方法*/

    /**
     * 通過反射獲取主鍵的值
     *
     * @param t          物件
     * @param primaryKey 主鍵欄位名稱
     * @return 返回主鍵的值
     * @throws Exception exception
     */
    private String getId(T t, String primaryKey) throws Exception {
        Class<?> aClass = t.getClass();
        String methodName = "get" + (primaryKey.charAt(0) + "").toUpperCase() + primaryKey.substring(1);
        Method method = aClass.getDeclaredMethod(methodName);
        return (String) method.invoke(t);
    }

    private T convertMap2Model(Map<String, Object> map, Class<T> classT) throws Exception {
        Object o = classT.newInstance();
        BeanUtils.populate(o, map);
        return (T) o;
    }

    /**
     * 關閉連線
     */
    public void close() {
        try {
            if (restHighLevelClient != null) {
                restHighLevelClient.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4.測試資料物件ProductModel

package com.example.demo.es;

import java.math.BigDecimal;
import java.util.Random;
import java.util.UUID;

/**
 * @ProjectName: pet_data
 * @Package: com.example.demo.es
 * @ClassName: ProductModel
 * @Author: Devin.W.Zhang
 * @Description:
 * @Date: 12/22/2020 10:21 AM
 * @Version: 1.0
 */
public class ProductModel {

    public static final String PRIMARY_KEY = "productId";

    private String categoryId;
    private String categoryName;
    private String productId;
    private String productName;
    private String productDesc;
    private BigDecimal productPrice;
    private Integer productCount;
    private long updateTime;

    public ProductModel() {
        this.categoryId = UUID.randomUUID().toString();
        this.productId = UUID.randomUUID().toString();

        Random random = new Random();
        int r = random.nextInt(10000);
        if ((r % 9) == 0) {
            this.categoryName = "貓";
        } else if ((r % 8) == 0) {
            this.categoryName = "狗";
        } else if ((r % 7) == 0) {
            this.categoryName = "寵物主糧";
        } else if (r % 6 == 0) {
            this.categoryName = "醫療保健";
        } else if (r % 5 == 0) {
            this.categoryName = "家居日用";
        } else if (r % 4 == 0) {
            this.categoryName = "寵物玩具";
        } else if (r % 3 == 0) {
            this.categoryName = "寵物出行";
        } else {
            this.categoryName = "寵物洗護";
        }

        int rr = random.nextInt(1000);
        this.productName = this.categoryName + (System.currentTimeMillis() + rr);
        this.productDesc = this.productName + "....";
        this.productPrice = BigDecimal.valueOf(r);
        this.productCount = r;
        this.updateTime = System.currentTimeMillis();
    }

    public String getCategoryId() {
        return categoryId;
    }

    public void setCategoryId(String categoryId) {
        this.categoryId = categoryId;
    }

    public String getCategoryName() {
        return categoryName;
    }

    public void setCategoryName(String categoryName) {
        this.categoryName = categoryName;
    }

    public String getProductId() {
        return productId;
    }

    public void setProductId(String productId) {
        this.productId = productId;
    }

    public String getProductName() {
        return productName;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }

    public String getProductDesc() {
        return productDesc;
    }

    public void setProductDesc(String productDesc) {
        this.productDesc = productDesc;
    }

    public BigDecimal getProductPrice() {
        return productPrice;
    }

    public void setProductPrice(BigDecimal productPrice) {
        this.productPrice = productPrice;
    }

    public Integer getProductCount() {
        return productCount;
    }

    public void setProductCount(Integer productCount) {
        this.productCount = productCount;
    }

    public long getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(long updateTime) {
        this.updateTime = updateTime;
    }

    @Override
    public String toString() {
        return "ProductModel{" +
                "categoryId='" + categoryId + '\'' +
                ", categoryName='" + categoryName + '\'' +
                ", productId='" + productId + '\'' +
                ", productName='" + productName + '\'' +
                ", productDesc='" + productDesc + '\'' +
                ", productPrice=" + productPrice +
                ", productCount=" + productCount +
                ", updateTime=" + updateTime +
                '}';
    }
}

5.測試case

package com.example.demo.es;

import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortOrder;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ProjectName: pet_data
 * @Package: com.example.demo.es
 * @ClassName: EsTestCase
 * @Author: Devin.W.Zhang
 * @Description:
 * @Date: 12/22/2020 10:32 AM
 * @Version: 1.0
 */
public class EsTestCase {


    public static void main(String[] args) throws Exception {
        //儲存單條
        saveOne();
        //批量儲存
        batchSave();
        String remark = "貓";
        BigDecimal productPriceStart = null;
        BigDecimal productPriceEnd = null;
        Integer productCount = 1;
        //查詢所有
        query(remark, productPriceStart, productPriceEnd, productCount);
        //分頁查詢
        int currentPage = 1;
        int pageSize = 20;
        Map<String, SortOrder> orders = new HashMap<>();
        orders.put("updateTime", SortOrder.DESC);
        pageQuery(currentPage, pageSize, orders, remark, productPriceStart, productPriceEnd, productCount);
    }

    /**
     * 儲存單條
     *
     * @throws Exception
     */
    public static void saveOne() throws Exception {
        EsUtils esUtils = new EsUtils<ProductModel>();
        ProductModel productModel = new ProductModel();
        IndexResponse save = esUtils.save(productModel, ProductModel.PRIMARY_KEY);
        String productId = productModel.getProductId();
        getOne(productId);
        esUtils.close();
    }

    /**
     * 查詢單條
     *
     * @param id
     * @throws Exception
     */
    public static void getOne(String id) throws Exception {
        EsUtils esUtils = new EsUtils<ProductModel>();
        ProductModel productModel = (ProductModel) esUtils.get(id, ProductModel.class);
        System.out.println(productModel);
        esUtils.close();
    }

    /**
     * 批量儲存
     *
     * @throws Exception
     */
    private static void batchSave() throws Exception {
        EsUtils esUtils = new EsUtils<ProductModel>();
        List<ProductModel> list = new ArrayList<>();
        for (int i = 0; i < 1000000; i++) {
            ProductModel productModel = new ProductModel();
            list.add(productModel);
            if (list.size() == 10000) {
                BulkResponse bulkItemResponses = esUtils.batchSave(list, ProductModel.PRIMARY_KEY);
                System.out.println(bulkItemResponses);
                list = new ArrayList<>();
            }
        }
        if (list.size() > 0) {
            BulkResponse bulkItemResponses = esUtils.batchSave(list, ProductModel.PRIMARY_KEY);
            System.out.println(bulkItemResponses);
        }
        esUtils.close();
    }


    /**
     * 查詢含有關鍵字 價格在區間內的 ,有貨的商品
     *
     * @param remark            關鍵字 ("categoryName", "productName", "productDesc" 這三個欄位含有remark欄位 )
     * @param productPriceStart productPrice >= price start
     * @param productPriceEnd   productPrice < price end
     * @param productCount      >= 庫存
     */
    public static void query(String remark, BigDecimal productPriceStart, BigDecimal productPriceEnd, Integer productCount) throws Exception {
        QueryBuilder queryBuilder = builderParams(remark, productPriceStart, productPriceEnd, productCount);
        EsUtils esUtils = new EsUtils<ProductModel>();
        List<ProductModel> list = esUtils.query(queryBuilder, null, ProductModel.class);
        System.out.println(String.format("get the result count:%s", list.size()));
        for (ProductModel productModel : list) {
            System.out.println(productModel);
        }
        esUtils.close();
    }

    /**
     * 分頁查詢
     *
     * @param currentPage       當前頁
     * @param pageSize          每頁條數
     * @param orders            排序map
     * @param remark            查詢關鍵字
     * @param productPriceStart 價格過濾開始
     * @param productPriceEnd   價格過濾結束
     * @param productCount      庫存 >=productCount
     * @throws Exception exception
     */
    public static void pageQuery(int currentPage, int pageSize, Map<String, SortOrder> orders, String remark, BigDecimal productPriceStart, BigDecimal productPriceEnd, Integer productCount) throws Exception {
        QueryBuilder queryBuilder = builderParams(remark, productPriceStart, productPriceEnd, productCount);
        EsUtils esUtils = new EsUtils<ProductModel>();
        Object[] objects = esUtils.pageQuery(currentPage, pageSize, queryBuilder, orders, ProductModel.class);
        List<ProductModel> list = (List<ProductModel>) objects[1];
        long totalCount = (long) objects[0];
        System.out.println(String.format("get the total count:%s", totalCount));
        int pageCount = (int) Math.ceil((totalCount / (pageSize * 1.00)));
        System.out.println(String.format("page count :%s", pageCount));
        for (ProductModel productModel : list) {
            System.out.println(productModel);
        }
        esUtils.close();
    }


    /**
     * 構造查詢條件
     *
     * @param remark            關鍵字
     * @param productPriceStart 價格開始
     * @param productPriceEnd   價格結束
     * @param productCount      庫存數量
     * @return 返回構造Query
     * @throws Exception query
     */
    private static QueryBuilder builderParams(String remark, BigDecimal productPriceStart, BigDecimal productPriceEnd, Integer productCount) throws Exception {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        if (StringUtils.isNotEmpty(remark)) {
            boolQueryBuilder.must(QueryBuilders.multiMatchQuery(remark, "categoryName", "productName", "productDesc"));
        }
        if (productPriceStart != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("productPrice").gte(productPriceStart));
        }
        if (productPriceEnd != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("productPrice").lt(productPriceEnd));
        }
        if (productCount != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("productCount").gte(productCount));
        }
        return boolQueryBuilder;
    }


}