ElasticSearch7.3.2-RestHighLevelClient实战

1,773 阅读4分钟

一、项目依赖

既然我们server安装7.3.2,那么我们客户端选择同样版本,高版本提供了更高层的api抽象封装。

<!--引入es -->
<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>7.3.2</version>
</dependency>

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

二、项目配置

  • application.properties配置
spring.elasticsearch.nodes=10.143.228.25:9200,10.143.228.26:9200,10.143.228.128:9200
spring.elasticsearch.username=elastic
spring.elasticsearch.password=elastic
  • config bean 配置
import com.google.common.collect.Lists;
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.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Arrays;
import java.util.List;

/**
 * @description: elasticSearch配置
 * @Date : 2020/5/14 上午11:37
 * @Author : 石冬冬-Seig Heil
 */
@Configuration
public class ElasticSearchConfig{
    /**
     * 使用的协议
     */
    final static String schema = "http";
    /**
     * 连接超时时间
     */
    final static int connectTimeOut = 1000;
    /**
     * 连接超时时间
     */
    final static int socketTimeOut = 30000;
    /**
     * 获取连接的超时时间
     */
    final static int connectionRequestTimeOut = 500;
    /**
     * 最大连接数
     */
    final static int maxConnectNum = 100;
    /**
     * 最大路由连接数
     */
    final static int maxConnectPerRoute = 100;

    @Value("${spring.elasticsearch.nodes}")
    String[] nodes;

    @Value("${spring.elasticsearch.username}")
    String username;

    @Value("${spring.elasticsearch.password}")
    String password;


    @Bean(name = "restHighLevelClient")
    public RestHighLevelClient client() {
        RestClientBuilder builder = RestClient.builder(hostList().toArray(new HttpHost[0]));

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

        builder.setHttpClientConfigCallback(httpClientBuilder -> {
            httpClientBuilder.disableAuthCaching();
            return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
        });

        // 异步httpclient连接延时配置
        builder.setRequestConfigCallback(requestConfigBuilder -> {
            requestConfigBuilder.setConnectTimeout(connectTimeOut);
            requestConfigBuilder.setSocketTimeout(socketTimeOut);
            requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeOut);
            return requestConfigBuilder;
        });

        // 异步httpclient连接数配置
        builder.setHttpClientConfigCallback(httpClientBuilder -> {
            httpClientBuilder.setMaxConnTotal(maxConnectNum);
            httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute);
            return httpClientBuilder;
        });
        return new RestHighLevelClient(builder);
    }

    List<HttpHost> hostList(){
        List<HttpHost> nodeList = Lists.newArrayList();
        Arrays.asList(nodes).stream().forEach(each -> {
            String[] array = each.split(":");
            nodeList.add(new HttpHost(array[0],Integer.valueOf(array[1]),schema));
        });
        return nodeList;
    }
}

三、示例介绍

3.1、创建索引

settings是修改分片和副本数的,mappings是修改字段和类型的。

@ApiOperation(value = "createIndex", notes = "createIndex")
@PostMapping("/createIndex/{indexName}")
public Result createIndex(@PathVariable String indexName, @RequestBody Map<String,Map<String,Object>> config) {
    try {
        CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
        createIndexRequest.settings(config.get("settings"));
        createIndexRequest.mapping(config.get("mapping"));
        CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
        return Result.suc(JSONObject.toJSON(createIndexResponse));
    } catch (IOException e) {
        log.error("[createIndex]",e);
        return Result.fail(e);
    }
}

3.2、判断索引是否存在

public boolean exists(String index) {
    boolean exists;
    try {
        GetIndexRequest getIndexRequest = new GetIndexRequest(index);
        getIndexRequest.humanReadable(true);
        exists = client.indices().exists(getIndexRequest, DEFAULT);
    } catch (IOException e) {
        log.error("[ElasticSearch]exists,index={}",index, e);
        throw new RuntimeException("[ElasticSearch]exists异常");
    }
    return exists;
}

3.3、删除索引

public boolean deleteIndex(String... indices) {
    boolean acknowledged;
    try {
        DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indices);
        AcknowledgedResponse delete = client.indices().delete(deleteIndexRequest,DEFAULT);
        acknowledged = delete.isAcknowledged();
    } catch (IOException e) {
        log.error("[ElasticSearch]deleteIndex,indices={}", JSON.toJSONString(indices), e);
        throw new RuntimeException("[ElasticSearch]deleteIndex异常");
    }
    return acknowledged;
}

3.4、插入文档

@ApiOperation(value = "insertRecord", notes = "insertRecord")
@PostMapping("/insertRecord/{indexName}")
public Result insertRecord(@RequestBody Map<String,Object> param, @PathVariable String indexName) {
    IndexRequest indexRequest = new IndexRequest(indexName);
    String userJson = JSONObject.toJSONString(param);
    indexRequest.source(userJson, XContentType.JSON);
    try {
        IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT);
        if (response != null) {
            ReplicationResponse.ShardInfo shardInfo = response.getShardInfo();
            if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
                log.info("shardInfo={}", JSONObject.toJSON(shardInfo));
            }
            // 如果有分片副本失败,可以获得失败原因信息
            if (shardInfo.getFailed() > 0) {
                for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
                    String reason = failure.reason();
                    log.info("副本失败原因,reason={}",reason);
                }
            }
        }
        return Result.suc(JSONObject.toJSON(response));
    } catch (IOException e) {
        log.info("[insertRecord]",e);
        return Result.fail(e);
    }
}

3.5、批量插入文档

@ApiOperation(value = "bulkInsertRecord", notes = "bulkInsertRecord")
@PostMapping("/bulkInsertRecord/{indexName}")
public Result bulkInsertRecord(@RequestBody List<Map<String,Object>> batch, @PathVariable String indexName) {
    BulkRequest bulkRequest = new BulkRequest();
    batch.forEach(each -> {
        IndexRequest indexRequest = new IndexRequest(indexName).source(each, XContentType.JSON);
        bulkRequest.add(indexRequest);
    });
    //同步
    try {
        BulkResponse response = client.bulk(bulkRequest,RequestOptions.DEFAULT);
        return Result.suc(JSONObject.toJSON(response));
    } catch (IOException e) {
        log.info("[updateRecord]",e);
        return Result.fail(e);
    }
}

3.6、更新文档

@ApiOperation(value = "updateRecord", notes = "updateRecord")
@PostMapping("/updateRecord/{indexName}")
public Result updateRecord(@PathVariable String indexName, @RequestParam String id,@RequestBody Map<String,Object> param) {
    UpdateRequest updateRequest = new UpdateRequest(indexName,id);
    updateRequest.doc(param);
    try {
        UpdateResponse response = client.update(updateRequest, RequestOptions.DEFAULT);
        return Result.suc(JSONObject.toJSON(response));
    } catch (IOException e) {
        log.info("[updateRecord]",e);
        return Result.fail(e);
    }
}

3.7、删除文档

@ApiOperation(value = "deleteRecord", notes = "deleteRecord")
@GetMapping("deleteRecord/{indexName}")
public Result deleteRecord(@RequestParam String id, @PathVariable String indexName) {
    DeleteRequest deleteRequest = new DeleteRequest(indexName);
    deleteRequest.id(id);
    try {
        DeleteResponse response = client.delete(deleteRequest, RequestOptions.DEFAULT);
        return Result.suc(JSONObject.toJSON(response));
    } catch (IOException e) {
        log.info("[updateRecord]",e);
        return Result.fail(e);
    }
}

3.8、查询文档

ApiOperation(value = "queryRecord", notes = "queryRecord")
@GetMapping("/queryRecord/{indexName}")
public Result queryRecord(@PathVariable String indexName) {
    SearchRequest searchRequest = new SearchRequest(indexName);
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    //如果用name直接查询,其实是匹配name分词过后的索引查到的记录(倒排索引);如果用name.keyword查询则是不分词的查询,正常查询到的记录
    RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("birthday").from("1991-01-01").to("2010-10-10").format("yyyy-MM-dd");//范围查询
//        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name.keyword", name);//精准查询
    PrefixQueryBuilder prefixQueryBuilder = QueryBuilders.prefixQuery("name.keyword", "张");//前缀查询
//        WildcardQueryBuilder wildcardQueryBuilder = QueryBuilders.wildcardQuery("name.keyword", "*三");//通配符查询
//        FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery("name", "三");//模糊查询
    FieldSortBuilder fieldSortBuilder = SortBuilders.fieldSort("age");//按照年龄排序
    fieldSortBuilder.sortMode(SortMode.MIN);//从小到大排序

    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
    boolQueryBuilder.must(rangeQueryBuilder).should(prefixQueryBuilder);//and or  查询

    sourceBuilder.query(boolQueryBuilder).sort(fieldSortBuilder);//多条件查询
    sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
    searchRequest.source(sourceBuilder);
    try {
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        JSONArray jsonArray = new JSONArray();
        for (SearchHit hit : hits) {
            String sourceAsString = hit.getSourceAsString();
            JSONObject jsonObject = JSON.parseObject(sourceAsString);
            jsonArray.add(jsonObject);
        }
        return Result.suc();
    } catch (IOException e) {
        e.printStackTrace();
        return Result.suc();
    }
}

3.9、查询文档

通过封装QueryForm对象实现查询

@ApiOperation(value = "queryCondition", notes = "queryCondition")
@PostMapping("/queryCondition/{indexName}")
public Result queryCondition(@PathVariable String indexName,@RequestBody QueryForm form) {
    try {
        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.source(form.searchSourceBuilder());
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        JSONArray jsonArray = new JSONArray();
        for (SearchHit hit : hits) {
            String sourceAsString = hit.getSourceAsString();
            JSONObject jsonObject = JSON.parseObject(sourceAsString);
            jsonArray.add(jsonObject);
        }
        return Result.suc(jsonArray);
    } catch (IOException e) {
        return Result.suc();
    }
}


@Data
static class QueryForm {

    private Integer id;

    private String age;

    private String name;

    private String address;

    private String birthday;

    private String birthdayRange;

    private String ageRange;


    SearchSourceBuilder searchSourceBuilder(){
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        if(id != null){
            sourceBuilder.query(QueryBuilders.termQuery("id", id));
        }
        if(name != null){
            sourceBuilder.query(QueryBuilders.termQuery("name", id));
        }
        if(age != null){
            sourceBuilder.query(QueryBuilders.termQuery("age", id));
        }
        if(address != null){
            sourceBuilder.query(QueryBuilders.termQuery("address", id));
        }
        if(birthday != null){
            sourceBuilder.query(QueryBuilders.termQuery("birthday", id));
        }
        if(birthdayRange != null){
            String[] array = birthdayRange.split("-");
            sourceBuilder.query(QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("birthday").from(array[0]).to(array[1]).format("yyyy-MM-dd")));
        }
        if(ageRange != null){
            String[] array = ageRange.split("-");
            sourceBuilder.query(QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("age").from(array[0]).to(array[1])));
        }
        return sourceBuilder;
    }
}

3.10、源码

源码地址:

https://gitee.com/suze/springBoot/blob/master/src/main/java/org/suze/springboot/elasticsearch/controller/ElasticSearchController.java

源码下载:

git clone https://gitee.com/suze/springBoot

下面的是我的公众号二维码图片,欢迎关注。

秋夜无霜