Springboot+elasticsearch基础整合实例

es,当插入数据的时候,可以自动创建索引,但是mapping却都是默认类型,导致搜索时需要key.keyword方式,不科学。

索引也可以手偶刚创建,指定mapping。

当然还有一种优雅的方案使用template,当自动创建索引的时候,我们的字段类型就可控了。

真实业务中,不能用一个固定的index,索引是需要切分的。

es多用于存储过程数据,指标数据,行为数据,历史数据多数情况下毫无价值,会定期清理。

例如:一天升一个索引index-prefix-yyyy-MM-dd

查询数据可以通过index-prefix*

这里有点尴尬,Springboot内部提供了大量template技术模板,es也有对应的ElasticsearchTemplate,但是并不实用。

我们还是采用RestHighClient发送请求来做es相关操作。

记录一个调试常用shell命令

curl -k --user 'username:password' https://10.110.48.77:9200/_cat   #实用单引号是解决密码中特殊符号问题

1、pom引入依赖

        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.13.1</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>7.13.1</version>
            <exclusions>
                <exclusion>
                    <groupId>org.yaml</groupId>
                    <artifactId>snakeyaml</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

2、properties文件配置es数据源

elastic.cluster.server=7.12.235.22:9200,7.12.225.22:9200
elastic.cluster.schema=https
elastic.cluster.user=cssabc
elastic.cluster.password=7ujm*&^(IJN

3、configuration装配bean

这里注意一个核心要适配http和https就要做SSL免证书

package com.wht.test.es;

import lombok.extern.slf4j.Slf4j;
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 org.springframework.context.annotation.Primary;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * es配置类
 *
 * @Author 红尘过客
 * @DateTime 2023-08-02 18:34:28
 */
@Slf4j
@Configuration
public class ElasticsearchConfig {
    @Value("${elastic.cluster.server}")
    private String elasticServers;

    @Value("${elastic.cluster.user}")
    private String username;

    @Value("${elastic.cluster.schema}")
    private String password;

    @Value("${elastic.cluster.https}")
    private String schema;

    @Primary
    @Bean
    public RestHighLevelClient restHighLevelClient() {
        return new RestHighLevelClient(restClientBuilder());
    }

    public RestClientBuilder restClientBuilder() {
        String[] servers = elasticServers.split(",");
        HttpHost[] httpHosts = new HttpHost[servers.length];
        for (int i = 0; i < servers.length; i++) {
            String server = servers[i];
            String host = server.split(":")[0];
            String port = server.split(":")[1];
            httpHosts[i] = new HttpHost(host, Integer.parseInt(port));
        }

        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
        return RestClient.builder(httpHosts)
                .setRequestConfigCallback(restClientBuilder -> restClientBuilder.setConnectTimeout(5 * 1000)
                        .setSocketTimeout(10 * 1000))
                .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setSSLContext(getSslContext())
                        .setSSLHostnameVerifier((hostname, session) -> true)
                        .setDefaultCredentialsProvider(credentialsProvider)
                        .setMaxConnTotal(100)
                        .setMaxConnPerRoute(100));

    }

    private SSLContext getSslContext() {
        SSLContext sslContext = null;
        if ("https".equalsIgnoreCase(schema)) {
            try {
                sslContext = createIgnoreVerifySsl();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (KeyManagementException e) {
                e.printStackTrace();
            }
        }
        return sslContext;
    }

    private SSLContext createIgnoreVerifySsl() throws NoSuchAlgorithmException, KeyManagementException {
        SSLContext sslContext = SSLContext.getInstance("TLS");
        X509TrustManager trustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

            }

            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        };
        sslContext.init(null, new TrustManager[]{trustManager}, null);
        return sslContext;
    }
}

4、通用服务类

ElasticService 很重要,主要包含了常见的索引创建,数据写入和查询,以及数据更新。

package com.wht.test.es;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkProcessor;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.ByteSizeUnit;
import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.TimeUnit;

/**
 * desc
 *
 * @Author 红尘过客
 * @DateTime 2023-08-02 18:52:33
 */
@Service
@Slf4j
public class ElasticService {
    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.ROOT);

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    private String currentIndex = "test_es_index";

    public boolean existsIndex(String index) {
        GetIndexRequest request = new GetIndexRequest(index);
        boolean exists = false;
        try {
            exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
        return exists;
    }

    public BulkProcessor bulkInit() {
        BulkProcessor.Listener listener = new ElasticListener();
        return BulkProcessor.builder((request, bulkListener) -> restHighLevelClient.bulkAsync(request, RequestOptions.DEFAULT, bulkListener), listener)
                .setBulkActions(900)
                .setBulkSize(new ByteSizeValue(5, ByteSizeUnit.MB))
                .setFlushInterval(TimeValue.timeValueSeconds(5))
                .setConcurrentRequests(2)
                .build();
    }

    public BulkProcessor writeEs(String index, JSONObject jsonObject) {
        try (BulkProcessor bulkProcessor = bulkInit()) {
            IndexRequest request = new IndexRequest(index);
            request.source(jsonObject, XContentType.JSON);
            bulkProcessor.add(request);
            return bulkProcessor;
        } catch (Exception exception) {
            log.error("");
        }
        return null;
    }

    public SearchHits findEs(String key, String value, String orderKey, String index) throws IOException {
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.timeout(new TimeValue(2, TimeUnit.SECONDS));
        boolQueryBuilder.must(QueryBuilders.termQuery(key, value));
        sourceBuilder.query(boolQueryBuilder);
        sourceBuilder.sort(new FieldSortBuilder(orderKey).order(SortOrder.DESC));
        SearchRequest searchRequest = new SearchRequest(index);
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        return searchResponse.getHits();

    }

    public UpdateResponse updateEs(String id, String index, JSONObject jsonObject) {
        UpdateRequest updateRequest = new UpdateRequest(index, id);
        updateRequest.retryOnConflict(3);
        updateRequest.doc(jsonObject.toJSONString(), XContentType.JSON);
        UpdateResponse updateResponse = null;
        log.info(">>>>>>>>>>>>>");
        try {
            updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return updateResponse;
    }

    public String initCurrentIndex(String index) {
        synchronized (this) {
            String todayIndex = index + "-" + dateFormat.format(new Date());
            if (todayIndex.equals(currentIndex)) {
                return currentIndex;
            }

            currentIndex = todayIndex;
            try {
                if (!existsIndex(currentIndex)) {
                    CreateIndexRequest createIndexRequest = new CreateIndexRequest(currentIndex);
                    createIndexRequest.settings(Settings.builder().put("index.number_of_shards", 3).
                            put("index.number_of_replicas", 2));

                    XContentBuilder builder = XContentFactory.jsonBuilder();
                    builder.startObject();
                    {
                        builder.startObject("properties");
                        {
                            builder.startObject("testName").field("type", "keyword").endObject();
                            builder.startObject("log").field("type", "text").endObject();
                        }
                        builder.endObject();
                    }
                    builder.endObject();
                    createIndexRequest.mapping(builder);
                    restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);

                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return currentIndex;
    }
    
}
package com.wht.test.es;

import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkProcessor;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;

/**
 * desc
 *
 * @Author 红尘过客
 * @DateTime 2023-08-02 18:58:16
 */
@Slf4j
public class ElasticListener implements BulkProcessor.Listener {
    @Override
    public void beforeBulk(long l, BulkRequest bulkRequest) {
        log.info(">>>>>>>>>>>>>>>");
    }

    @Override
    public void afterBulk(long l, BulkRequest bulkRequest, BulkResponse bulkResponse) {
        boolean hasFailures = bulkResponse.hasFailures();
        if (hasFailures) {
            String buildFailureMessage = bulkResponse.buildFailureMessage();
            log.error("--try insert {} no error --", bulkRequest.numberOfActions());
            log.error("-- error message --{}", buildFailureMessage);
        }
    }

    @Override
    public void afterBulk(long l, BulkRequest bulkRequest, Throwable throwable) {
        log.error("--try insert {} no error --", throwable);
    }
}

5、验证示例--client

package com.wht.test.es;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Map;

/**
 * desc
 *
 * @Author 红尘过客
 * @DateTime 2023-08-02 16:27:05
 */
@Slf4j
@Component
public class ElasticsearchClient {

    private static final String TEST_INDEX = "test_es_index";

    @Autowired
    private ElasticService elasticService;

    @Scheduled(cron = "*/10 * * * * * ")
    public void bizHandler() {
        JSONObject jsonObject = new JSONObject();
        long time = System.currentTimeMillis();
        String testName = "test_name_" + time;
        jsonObject.put("testName", testName);
        jsonObject.put("time", time);
        jsonObject.put("log", time + "-样例日志。。。。。。。。。。。。。。。。。。。。。。。。。");
        String initIndex = elasticService.initCurrentIndex(TEST_INDEX);
        elasticService.writeEs(initIndex, jsonObject);

        try {
            Thread.sleep(1000);
            SearchHits hits = elasticService.findEs("testName", testName, "time", initIndex);
            if (hits.getTotalHits().value > 0) {
                for (SearchHit hit : hits.getHits()) {
                    Map<String, Object> result = hit.getSourceAsMap();
                    Object logString = result.get("log");
                    if (logString != null) {
                        log.info(">>>>>>>>>>>>>>{}", logString.toString());
                    }
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
    }
}
posted @ 2023-08-02 19:37  红尘过客2022  阅读(39)  评论(0编辑  收藏  举报