使用Java操作Elasticsearch

使用Java对Elasticsearch执行相关操作时,需要保证Java引入的依赖需要与Elasticsearch版本对应。在Elasticsearch7.15版本后,RestHightLevelClient已废弃,需要使用Elasticsearch Java API Client替代。以下操作基于Elasticsearch7.17

一、引入依赖

在引入elasticsearch-java依赖时,需要检查elasticsearch-rest-client依赖版本是否与Elasticsearch版本一致,如果不是,需要排除该依赖,并引入正确的版本,否则会报方法找不到等异常

xml 复制代码
<!-- elasticsearch -->
<dependency>
    <groupId>co.elastic.clients</groupId>
    <artifactId>elasticsearch-java</artifactId>
    <version>7.17.17</version>
    <exclusions>
        <exclusion>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-client</artifactId>
    <version>7.17.17</version>
</dependency>

<dependency>
    <groupId>jakarta.json</groupId>
    <artifactId>jakarta.json-api</artifactId>
    <version>2.0.1</version>
</dependency>


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <version>2.6.3</version>
</dependency>

二、配置Java API Client

在application.yml文件中添加如下配置

yaml 复制代码
elasticsearch:
  host: localhost
  port: 9200

使用Java代码配置Java API Client

java 复制代码
@Data
@Configuration
@ConfigurationProperties(prefix = "elasticsearch")
public class ElasticsearchConfig {
    private String host;
    private int port;

    /**
     * 执行Elasticsearch操作时,以同步的方式等待响应
     * @return
     */
    @Bean
    public ElasticsearchClient elasticsearchClient() {
        RestClient restClient = RestClient.builder(new HttpHost(host, port)).build();
        ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
        return new ElasticsearchClient(transport);
    }

    /**
     * 执行Elasticsearch操作时,以异步的方式等待响应
     * @return
     */
    @Bean
    public ElasticsearchAsyncClient elasticsearchAsyncClient() {
        RestClient restClient = RestClient.builder(new HttpHost(host, port)).build();
        ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
        return new ElasticsearchAsyncClient(transport);
    }
}

三、使用Java API Clent执行Elasticsearch操作

1、索引相关操作

java 复制代码
@Autowired
private ElasticsearchClient elasticsearchClient;

// 创建索引
@Test
void create_index_test() throws IOException {
    CreateIndexRequest request = CreateIndexRequest.of(builder -> builder.index("user"));
    CreateIndexResponse createIndexResponse = elasticsearchClient.indices().create(request);
    log.info("acknowledged: {}", createIndexResponse.acknowledged());
    log.info("index: {}", createIndexResponse.index());
    log.info("shardsAcknowledged: {}", createIndexResponse.shardsAcknowledged());
}

// 获取索引信息
@Test
void get_index_test() throws IOException {
    List<String> indexName = new ArrayList<>();
    indexName.add("user");
    GetIndexRequest request = GetIndexRequest.of(builder -> builder.index(indexName));
    GetIndexResponse getIndexResponse = elasticsearchClient.indices().get(request);
    Map<String, IndexState> result =
            getIndexResponse.result();
    result.entrySet().forEach(entry -> {
        log.info("key: {}, value: {}", entry.getKey(), entry.getValue());
    });
}

// 判断索引是否存在
@Test
void exist_index_test() throws IOException {
    List<String> indexName = new ArrayList<>();
    indexName.add("user");
    ExistsRequest request = ExistsRequest.of(builder -> builder.index(indexName));
    BooleanResponse response = elasticsearchClient.indices().exists(request);
    log.info("exist: {}", response.value());
}

// 删除索引
@Test
void delete_index_test() throws IOException {
    DeleteIndexRequest request = DeleteIndexRequest.of(builder -> builder.index("user"));
    DeleteIndexResponse response = elasticsearchClient.indices().delete(request);
    log.info("delete success: {}", response.acknowledged());
}

2、映射相关操作

java 复制代码
@Autowired
private ElasticsearchClient elasticsearchClient;

// 设置索引映射,前提需要创建该索引
@Test
void mapping_setting_test() throws IOException {
    Map<String, Property> properties = new HashMap<>();
    Property name = Property.of(builder -> builder.text(TextProperty.of(pro -> pro.index(true))));
    Property age = Property.of(builder -> builder.integer(IntegerNumberProperty.of(pro -> pro.index(true))));
    properties.put("name", name);
    properties.put("age", age);
    PutMappingRequest request = PutMappingRequest.of(builder -> builder.index("user").properties(properties));
    PutMappingResponse putMappingResponse = elasticsearchClient.indices().putMapping(request);
    log.info("add mapping success: {}", putMappingResponse.acknowledged());
}

// 获取索引映射配置
@Test
void mapping_get_test() throws IOException {
    GetMappingRequest request = GetMappingRequest.of(builder -> builder.index("user"));
    GetMappingResponse response = elasticsearchClient.indices().getMapping(request);
    Map<String, IndexMappingRecord> result = response.result();
    log.info("user mapping message: {}", result);
}

3、文档相关操作

java 复制代码
@Autowired
private ElasticsearchClient elasticsearchClient;

// 添加文档
@Test
void document_put_test() throws IOException {
    User user = new User();
    user.setName("zhangsang");
    user.setAge(18);
    CreateRequest request = CreateRequest.of(builder -> builder.index("user").id("123456").document(user));
    CreateResponse createResponse = elasticsearchClient.create(request);
    log.info("{}", createResponse.result().jsonValue());
}

// 获取文档
@Test
void document_get_test() throws IOException {
    GetRequest request = GetRequest.of(builder -> builder.index("user").id("123456"));
    GetResponse<User> userGetResponse = elasticsearchClient.get(request, User.class);
    User user = userGetResponse.source();
    log.info("query result: {}", user);
}

// 更新文档
@Test
void document_update_test() throws IOException {
    User user = new User();
    user.setAge(20);
    UpdateRequest<Object, Object> request = UpdateRequest.of(builder ->
            builder.index("user").id("123456").doc(user));
    UpdateResponse<Object> response = elasticsearchClient.update(request, User.class);
    log.info("update result: {}", response);
}

// 删除文档
@Test
void document_delete_test() throws IOException {
    DeleteRequest request = DeleteRequest.of(builder -> builder.index("user").id("123456"));
    DeleteResponse response = elasticsearchClient.delete(request);
    log.info("delete result: {}", response);
}

// 判断文档是否存在
@Test
void document_exist_test() throws IOException {
    ExistsRequest request = ExistsRequest.of(builder -> builder.index("user").id("123456"));
    BooleanResponse response = elasticsearchClient.exists(request);
    log.info("exist result: {}", response.value());
}

// 通过索引中的name字段获取文档
@Test
void document_query_byName_test() throws IOException {
    SearchRequest request = SearchRequest.of(builder ->
            builder.index("user")
                    .query(query -> query.match(match ->
                            match.field("name").query("zhansang"))));
    SearchResponse<User> response = elasticsearchClient.search(request, User.class);
    log.info("search result: {}", response);
}

四、Elasticsearch Java Client分析

使用Elasticsearch Java Client执行一些数据操作时,需要使用ElasticsearchClientElasticsearchAsyncClient发送Http请求,如果熟悉使用Http请求执行Elasticsearch数据操作,那么很容易上手

上图为ElasticsearchClient的部分方法,观察以上方法,基本每一个同名的方法都会有两种参数,分别是xxxRequest和Function两种类型。

xxxRequest都是继承RequestBase类,如果需要查看有多少种请求类型,可以查看RquestBase的子类。以CreateRequest类为例简单分析使用ElasticsearchClient执行数据操作的基本思路。

在CreateRequest类中,只用一个构建方法。

java 复制代码
private CreateRequest(CreateRequest.Builder<TDocument> builder) {
    this.id = (String)ApiTypeHelper.requireNonNull(builder.id, this, "id");
    this.index = (String)ApiTypeHelper.requireNonNull(builder.index, this, "index");
    this.pipeline = builder.pipeline;
    this.refresh = builder.refresh;
    this.routing = builder.routing;
    this.timeout = builder.timeout;
    this.type = builder.type;
    this.version = builder.version;
    this.versionType = builder.versionType;
    this.waitForActiveShards = builder.waitForActiveShards;
    this.document = ApiTypeHelper.requireNonNull(builder.document, this, "document");
    this.tDocumentSerializer = builder.tDocumentSerializer;
}

但是该构建方法为私有方法,不能使用该私有方法构造对象。通过仔细查找后,发现该类有一个静态方法可以构建该类对象,入参为 Function<CreateRequest.Builder<TDocument>, ObjectBuilder<CreateRequest<TDocument>>> 类型,也就可以说传入一个CreateRequest.Builder<TDocument>类型并输出ObjectBuilder<CreateRequest<TDocument>>>类型的lambda表达式

java 复制代码
public static <TDocument> CreateRequest<TDocument> of(Function<CreateRequest.Builder<TDocument>, ObjectBuilder<CreateRequest<TDocument>>> fn) {
    return (CreateRequest)((ObjectBuilder)fn.apply(new CreateRequest.Builder())).build();
}

观察lambda表达式的输入参数CreateRequest.Builder<TDocument>,发现该类型是ObjectBuilder<CreateRequest<TDocument>>>类的子类,并且该类型的一些方法返回值的类型都为CreateRequest.Builder<TDocument>类型,因此lambda表达式的输出部分可以使用类似builder -> builder.a().b()链式方法调用方式

分析完CreateRequest.of方法后,发现该方法的入参和调用ElasticsearchClient 的create方法中的Function参数类型一致,因此调用ElasticsearchClient的方法时,可以执行传xxxRequest对象,也可以直接传xxxRequest.of方法的参数

总结: 调用ElasticsearchClient执行数据操作时,需要结合使用Http请求方式的请求url及参数,构建xxxRquest对象作为输入参

相关推荐
forestsea2 小时前
【Elasticsearch】分片与副本机制:优化数据存储与查询性能
大数据·elasticsearch·搜索引擎
运维&陈同学3 小时前
【Beats01】企业级日志分析系统ELK之Metricbeat与Heartbeat 监控
运维·elk·elasticsearch·云原生·kibana·heartbeat·metricbeat
INFINI Labs3 小时前
Elasticsearch filter context 的使用原理
大数据·elasticsearch·jenkins·filter·querycache
chengpei1473 小时前
Elasticsearch介绍及安装部署
elasticsearch·搜索引擎
it噩梦13 小时前
es 中 terms set 使用
大数据·elasticsearch
喝醉酒的小白16 小时前
Elasticsearch 配置文件
大数据·elasticsearch·搜索引擎
missay_nine20 小时前
Elasticsearch
大数据·elasticsearch·搜索引擎
it噩梦21 小时前
深度分析 es multi_match 中most_fields、best_fields、cross_fields区别
java·elasticsearch
喝醉酒的小白1 天前
ES 集群 A 和 ES 集群 B 数据流通
大数据·elasticsearch·搜索引擎
炭烤玛卡巴卡1 天前
初学elasticsearch
大数据·学习·elasticsearch·搜索引擎