Elasticsearch 不徹底入門指北系列(三):項目搭建

WechatIMG49.jpeg

今天咱們來實際搭建一個簡單的 spring-boot web 項目來操做一下 Elasticsearch,經過 ES 的 elasticsearch-rest-high-level-client 來調用ES接口。node

1. 項目初始化

首先咱們先建立一個spring-boot web項目,這一步你們能夠自行解決。而後引入 elasticsearch 相關依賴,引入版本能夠根據本身須要調整,通常和安裝的 Elasticsearch 一致便可:git

maven:github

<!-- elasticsearch & rest-high-level-client -->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.12.0</version>
</dependency>
複製代碼

gradle:web

implementation group: 'org.elasticsearch.client', name: 'elasticsearch-rest-high-level-client', version: '7.12.0'
複製代碼

增長以下配置:spring

# elasticsearch 相關配置
elasticsearch:
  cluster-name: elasticsearch
  cluster-nodes: 127.0.0.1:9200
  index:
    number-of-replicas: 2
    number-of-shards: 3
  account:
    username:
    password:
複製代碼

此外,還須要建立一個配置類鏈接 Elasticsearch 客戶端:markdown

@Data
@Builder
@Component
@NoArgsConstructor
@AllArgsConstructor
@ConfigurationProperties(prefix = "elasticsearch")
public class ElasticsearchProperties {
    /**
     * 請求協議
     */
    private String schema = "http";
    /**
     * 集羣名稱
     */
    private String clusterName = "elasticsearch";
    /**
     * 集羣節點
     */
    @NotNull(message = "集羣節點不容許爲空")
    private List<String> clusterNodes = new ArrayList<>();
    /**
     * 鏈接超時時間(毫秒)
     */
    private Integer connectTimeout = 1000;
    /**
     * socket 超時時間
     */
    private Integer socketTimeout = 30000;
    /**
     * 鏈接請求超時時間
     */
    private Integer connectionRequestTimeout = 500;
​
    /**
     * 每一個路由的最大鏈接數量
     */
    private Integer maxConnectPerRoute = 10;
    /**
     * 最大鏈接總數量
     */
    private Integer maxConnectTotal = 30;
    /**
     * 索引配置信息
     */
    private Index index = new Index();
    /**
     * 認證帳戶
     */
    private Account account = new Account();
​
    /**
     * 索引配置信息
     */
    @Data
    public static class Index {
        /**
         * 分片數量
         */
        private Integer numberOfShards = 3;
        /**
         * 副本數量
         */
        private Integer numberOfReplicas = 2;
    }
    /**
     * 認證帳戶
     */
    @Data
    public static class Account {
        /**
         * 認證用戶
         */
        private String username;
        /**
         * 認證密碼
         */
        private String password;
    }
}
複製代碼
@Configuration
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@EnableConfigurationProperties(ElasticsearchProperties.class)
public class ElasticsearchConfiguration {
​
    private final ElasticsearchProperties elasticsearchProperties;
​
    private final List<HttpHost> httpHosts = new ArrayList<>();
​
    @Bean(name = "restHighLevelClient")
    @ConditionalOnMissingBean
    public RestHighLevelClient restHighLevelClient() {
​
        List<String> clusterNodes = elasticsearchProperties.getClusterNodes();
        clusterNodes.forEach(node -> {
            try {
                String[] parts = StringUtils.split(node, ":");
                Assert.notNull(parts, "Must defined");
                Assert.state(parts.length == 2, "Must be defined as 'host:port'");
                httpHosts.add(new HttpHost(parts[0], Integer.parseInt(parts[1]), elasticsearchProperties.getSchema()));
            } catch (Exception e) {
                throw new IllegalStateException("Invalid ES nodes " + "property '" + node + "'", e);
            }
        });
        RestClientBuilder builder = RestClient.builder(httpHosts.toArray(new HttpHost[0]));
​
        return getRestHighLevelClient(builder, elasticsearchProperties);
    }
​
​
    /**
     * get restHistLevelClient
     *
     * @param builder                 RestClientBuilder
     * @param elasticsearchProperties elasticsearch default properties
     * @return {@link RestHighLevelClient}
     * @author fxbin
     */
    private static RestHighLevelClient getRestHighLevelClient(RestClientBuilder builder, ElasticsearchProperties elasticsearchProperties) {
​
        // Callback used the default {@link RequestConfig} being set to the {@link CloseableHttpClient}
        builder.setRequestConfigCallback(requestConfigBuilder -> {
            requestConfigBuilder.setConnectTimeout(elasticsearchProperties.getConnectTimeout());
            requestConfigBuilder.setSocketTimeout(elasticsearchProperties.getSocketTimeout());
            requestConfigBuilder.setConnectionRequestTimeout(elasticsearchProperties.getConnectionRequestTimeout());
​
            requestConfigBuilder.setAuthenticationEnabled(true);
​
            return requestConfigBuilder;
        });
​
        // Callback used the basic credential auth
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        ElasticsearchProperties.Account account = elasticsearchProperties.getAccount();
        if (!StringUtils.isEmpty(account.getUsername()) && !StringUtils.isEmpty(account.getUsername())) {
            credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(account.getUsername(), account.getPassword()));
        }
​
        // Callback used to customize the {@link CloseableHttpClient} instance used by a {@link RestClient} instance.
        builder.setHttpClientConfigCallback(httpClientBuilder -> {
            httpClientBuilder.setMaxConnTotal(elasticsearchProperties.getMaxConnectTotal());
            httpClientBuilder.setMaxConnPerRoute(elasticsearchProperties.getMaxConnectPerRoute());
            httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
            return httpClientBuilder;
        });
​
        return new RestHighLevelClient(builder);
    }
}
複製代碼

而後,先啓動 Elasticsearch 客戶端,再啓動項目便可。訪問健康檢查接口 /actuator/health,能夠看到 elasticsearch 的鏈接狀況:socket

{
    "status":"UP",
    "components":{
        "elasticsearchRest":{
            "status":"UP",
            "details":{
                "cluster_name":"elasticsearch",
                "status":"yellow",
                "timed_out":false,
                "number_of_nodes":1,
                "number_of_data_nodes":1,
                "active_primary_shards":40,
                "active_shards":40,
                "relocating_shards":0,
                "initializing_shards":0,
                "unassigned_shards":79,
                "delayed_unassigned_shards":0,
                "number_of_pending_tasks":0,
                "number_of_in_flight_fetch":0,
                "task_max_waiting_in_queue_millis":0,
                "active_shards_percent_as_number":33.61344537815126
            }
        },
        "ping":{
            "status":"UP"
        }
    }
}
複製代碼

2. 建立/刪除索引

關於 Elasticsearch 的索引,咱們經常使用的幾個操做即是檢查索引是否存在、建立索引、以及刪除索引。對於索引的操做,咱們須要使用 client.indices() 方法來獲取 IndicesClient 實例,進而對索引進行相關操做。elasticsearch

   
    @Autowired
    @Qualifier(value = "restHighLevelClient")
    protected RestHighLevelClient client;
​
    protected static final RequestOptions COMMON_OPTIONS;
​
    private void checkIndexExist(String index) {
        try {
            GetIndexRequest indexRequest = new GetIndexRequest(index);
            boolean exists = client.indices().exists(indexRequest, COMMON_OPTIONS);
            if (!exists) {
                createIndexRequest(index);
            }
        } catch (IOException e) {
            log.error("Failed to check index. {}", index, e);
        }
    }
複製代碼
   /**
     * create elasticsearch index (asyc)
     *
     * @param index elasticsearch index
     */
    protected void createIndexRequest(String index) {
        try {
            CreateIndexRequest request = new CreateIndexRequest(index);
            // Settings for this index
            request.settings(Settings.builder()
                    .put("index.number_of_shards", elasticsearchProperties.getIndex().getNumberOfShards())
                    .put("index.number_of_replicas", elasticsearchProperties.getIndex().getNumberOfReplicas()));
​
            CreateIndexResponse createIndexResponse = client.indices().create(request, COMMON_OPTIONS);
​
            log.info(" whether all of the nodes have acknowledged the request : {}", createIndexResponse.isAcknowledged());
            log.info(" Indicates whether the requisite number of shard copies were started for each shard in the index before timing out :{}", createIndexResponse.isShardsAcknowledged());
        } catch (IOException e) {
            log.error("failed to create index. ", e);
            throw new ElasticsearchException("建立索引 {" + index + "} 失敗");
        }
    }
複製代碼
   /**
     * delete elasticsearch index
     *
     * @param index elasticsearch index name
     */
    protected void deleteIndexRequest(String index) {
        DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(index);
        try {
            client.indices().delete(deleteIndexRequest, COMMON_OPTIONS);
        } catch (IOException e) {
            log.error("failed to delete index. ", e);
            throw new ElasticsearchException("刪除索引 {" + index + "} 失敗");
        }
    }
複製代碼

3. 操做 Elasticsearch 文檔(_doc

說完索引,就是對文檔的操做,一樣的,對於 Elasticsearch 的文檔(_doc),咱們也有 CRUD 基礎的四種操做。分別對應四個Request 對象:maven

// 新增/建立一個文檔
IndexRequest request = new IndexRequest(index)
  // 文檔ID
  .id(id)
  // 文檔源數據
  .source(JSONUtil.toJsonStr(object), XContentType.JSON);
// client 建立文檔
client.index(request, COMMON_OPTIONS);
複製代碼
// 讀取某個ID的文檔
GetRequest getRequest = new GetRequest(EsConstant.INDEX_NAME) // 索引名稱
  // id
  .id(String.valueOf(id));
GetResponse response = client.get(getRequest, COMMON_OPTIONS);
複製代碼
// 更新一個文檔
UpdateRequest updateRequest = new UpdateRequest(index, id)
  .doc(BeanUtil.beanToMap(object), XContentType.JSON);
// client 更新文檔
client.update(updateRequest, COMMON_OPTIONS);
複製代碼
// 刪除某個ID的文檔
// 參數爲 索引名稱以及ID
DeleteRequest deleteRequest = new DeleteRequest(index, id);
// client 刪除文檔
client.delete(deleteRequest, COMMON_OPTIONS);
複製代碼

總結

本篇文章主要給你們簡單介紹並演示了一下如何初始化咱們的測試項目,你們能夠本身試着搭建一個出來。後續咱們會詳細介紹 Elasticsearch 搜索場景的各類實現。ide

連接

相關文章
相關標籤/搜索