使用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对象作为输入参

相关推荐
hengzhepa5 小时前
ElasticSearch备考 -- Async search
大数据·学习·elasticsearch·搜索引擎·es
bubble小拾13 小时前
ElasticSearch高级功能详解与读写性能调优
大数据·elasticsearch·搜索引擎
不能放弃治疗14 小时前
重生之我们在ES顶端相遇第 18 章 - Script 使用(进阶)
elasticsearch
hengzhepa14 小时前
ElasticSearch备考 -- Search across cluster
学习·elasticsearch·搜索引擎·全文检索·es
Elastic 中国社区官方博客16 小时前
Elasticsearch:使用 LLM 实现传统搜索自动化
大数据·人工智能·elasticsearch·搜索引擎·ai·自动化·全文检索
慕雪华年17 小时前
【WSL】wsl中ubuntu无法通过useradd添加用户
linux·ubuntu·elasticsearch
Elastic 中国社区官方博客19 小时前
使用 Vertex AI Gemini 模型和 Elasticsearch Playground 快速创建 RAG 应用程序
大数据·人工智能·elasticsearch·搜索引擎·全文检索
alfiy20 小时前
Elasticsearch学习笔记(四) Elasticsearch集群安全配置一
笔记·学习·elasticsearch
alfiy21 小时前
Elasticsearch学习笔记(五)Elastic stack安全配置二
笔记·学习·elasticsearch
丶21362 天前
【大数据】Elasticsearch 实战应用总结
大数据·elasticsearch·搜索引擎