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

连接

相关文章
相关标签/搜索