Elasticsearch-Java高级API的简单使用

使用Elasticsearch进行索引操作与查询测试
这是一个关于Elasticsearch的测试用例,涵盖了创建、删除索引,以及添加、更新和删除文档的操作。此外,还展示了如何查询文档和执行自定义查询,查询条件包括匹配关键字、资源类型等字段。
package com.corecmd.webapp.tiansjportal;

import com.alibaba.fastjson.JSON;
import com.corecmd.webapp.tiansjportal.common.enums.ResourceTypeEnum;
import com.corecmd.webapp.tiansjportal.common.utils.DateUtil;
import com.corecmd.webapp.tiansjportal.elasticsearch.domain.ResUserSearchVO;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
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.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Date;


@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class ElasticsearchTests {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * 判断索引是否存在
     */
    @Test
    public void getIndex() {
        try {
            String indexName = "logstash-system-localhost-2021.10.31";
            GetIndexRequest re = new GetIndexRequest(indexName);
            boolean isExist = restHighLevelClient.indices().exists(re, RequestOptions.DEFAULT);
            log.info("索引:{}是否存在:{}", indexName, isExist);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void createIndex() {
        try {
            String indexName = "tiansjportal-user-file-search";
            log.info("创建索引:" + indexName);
            CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
            CreateIndexResponse response = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
            log.info("创建索引结果:" + response.isAcknowledged());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void deleteIndex() {
        try {
            String indexName = "tim_user_search_his";
            log.info("删除索引:" + indexName);
            DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName);
            AcknowledgedResponse delete = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
            log.info("删除索引结果:" + delete.isAcknowledged());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建文档
     * 批量插入文档时,需要建立BulkRequest,并向BulkRequest中add IndexRequest
     * 最后:restHighLevelClient.bulk()发生请求
     */
    @Test
    public void createDoc() {
        try {
            String indexName = "tiansjportal-user-video-search";
            log.info("向索引:{}中添加文档", indexName);
            ResUserSearchVO userSearchVO = new ResUserSearchVO();
            userSearchVO.setUserId(7);
            userSearchVO.setKeyWord("杨");
            userSearchVO.setResourceType(ResourceTypeEnum.ALBUM.getTypeEn());
            userSearchVO.setSearchTime(DateUtil.getDateStr(new Date(), DateUtil.DATE_TIME_FORMAT));
            String jsonType = JSON.toJSONString(userSearchVO);
            log.info("文档数据:{}", jsonType);
            IndexRequest indexRequest = new IndexRequest(indexName);
            indexRequest.source(jsonType, XContentType.JSON);
            IndexResponse response = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
            log.info("文档创建结果:" + DocWriteResponse.Result.CREATED.equals(response.getResult()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //更新文档
    @Test
    public void updateDoc() {
        try {
            String indexName = "tiansjportal-user-album-search";
            log.info("在索引:{}中更新文档", indexName);
            ResUserSearchVO userSearchVO = new ResUserSearchVO();
            userSearchVO.setUserId(7);
            userSearchVO.setKeyWord("祖国风景");
            userSearchVO.setResourceType(ResourceTypeEnum.ALBUM.getTypeEn());
            userSearchVO.setSearchTime(DateUtil.getDateStr(new Date(), DateUtil.DATE_TIME_FORMAT));
            String jsonType = JSON.toJSONString(userSearchVO);
            log.info("文档数据:{}", jsonType);
            UpdateRequest updateRequest = new UpdateRequest(indexName, "peRS1HwBv8L2V11VN_8F");
            updateRequest.doc(jsonType, XContentType.JSON);
            //获取修改后的结果
            updateRequest.fetchSource(true);
            UpdateResponse response = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
            log.info("文档更新结果:" + DocWriteResponse.Result.UPDATED.equals(response.getResult()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //删除文档
    @Test
    public void deleteDoc() {
        try {
            String indexName = "tiansjportal-user-album-search";
            log.info("在索引:{}中删除文档", indexName);
            DeleteRequest deleteRequest = new DeleteRequest(indexName, "peRS1HwBv8L2V11VN_8F");
            DeleteResponse response = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
            log.info("文档更新结果:" + DocWriteResponse.Result.DELETED.equals(response.getResult()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //查询文档,根据文档id查询
    @Test
    public void searchDoc() {
        try {
            String indexName = "tiansjportal-user-album-search";
            log.info("在索引:{}中查询文档", indexName);
            GetRequest getRequest = new GetRequest(indexName, "oORN1HwBv8L2V11VQP9L");
            GetResponse response = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
            if (response.isExists()) {
                log.info("文档查询结果:" + response.toString());
            } else {
                log.info("文档不存在");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 自定义查询,指定查询字段
     */
    @Test
    public void customSearch() {
        try {
            String indexName = "tiansjportal-user-album-search";
            log.info("在索引:{}中查询文档", indexName);
            SearchRequest searchRequest = new SearchRequest(indexName);
            //构建查询参数
            MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("keyWord", "杨");
            TermQueryBuilder resourceType = QueryBuilders.termQuery("resourceType", ResourceTypeEnum.ALBUM.getTypeEn());
            TermQueryBuilder author = QueryBuilders.termQuery("userId", "8");
            //查询参数构造器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            //向构造器添加参数
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            boolQueryBuilder.filter(matchQueryBuilder);
            boolQueryBuilder.filter(resourceType);
            boolQueryBuilder.filter(author);
            searchSourceBuilder.query(boolQueryBuilder);
            //设置请求查询擦书
            searchRequest.source(searchSourceBuilder);
            SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            //可能有多条结果
            if (response.getHits().getTotalHits().value > 0) {
                for (SearchHit searchHit : response.getHits().getHits()) {
                    log.info("查询结果:" + searchHit.getSourceAsString());
                }
            } else {
                log.info("没有查询到数据");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}

<think> 我们使用Elasticsearch Java客户端(elasticsearch-java)时,通常使用`co.elastic.clients:elasticsearch-java`库。在将ES文档映射到Java实体Bean时,字段名称映射可以通过以下方式实现: ### 1. 使用`@JsonProperty`注解(Jackson注解) Elasticsearch Java客户端底层使用Jackson进行序列化和反序列化。因此,我们可以通过在Java实体类的字段上使用Jackson的`@JsonProperty`注解来指定ES文档中的字段名。 ```java import com.fasterxml.jackson.annotation.JsonProperty; public class Product { // 使用@JsonProperty将Java字段名映射到ES文档中的字段名 @JsonProperty("product_name") private String productName; @JsonProperty("price_in_cents") private long priceInCents; // 必须有无参构造函数 public Product() { } // getter和setter public String getProductName() { return productName; } public void setProductName(String productName) { this.productName = productName; } public long getPriceInCents() { return priceInCents; } public void setPriceInCents(long priceInCents) { this.priceInCents = priceInCents; } } ``` ### 2. 配置Jackson的`PropertyNamingStrategy` 如果你希望全局采用某种命名策略(如蛇形命名),可以在创建Elasticsearch客户端时配置ObjectMapper。 ```java import co.elastic.clients.elasticsearch.ElasticsearchClient; import co.elastic.clients.json.jackson.JacksonJsonpMapper; import co.elastic.clients.transport.ElasticsearchTransport; import co.elastic.clients.transport.rest_client.RestClientTransport; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; // 创建Elasticsearch客户端 RestClient restClient = RestClient.builder( new HttpHost("localhost", 9200) ).build(); // 创建ObjectMapper并设置命名策略为蛇形命名 ObjectMapper objectMapper = new ObjectMapper() .setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); // 使用配置了ObjectMapper的JacksonJsonpMapper JacksonJsonpMapper jsonpMapper = new JacksonJsonpMapper(objectMapper); ElasticsearchTransport transport = new RestClientTransport( restClient, jsonpMapper ); ElasticsearchClient client = new ElasticsearchClient(transport); ``` 这样,在Java实体类中就可以直接使用驼峰命名的字段,而无需为每个字段添加`@JsonProperty`注解。 ### 3. 使用`@JsonAlias`注解 如果ES文档中的字段可能有多个别名,可以使用`@JsonAlias`注解。 ```java public class Product { // 表示ES文档中可以使用"product_name"或"name"来映射到productName字段 @JsonProperty("product_name") @JsonAlias({"name", "productName"}) private String productName; // ... } ``` ### 4. 自定义序列化/反序列化器(高级) 对于更复杂的映射,可以自定义Jackson的序列化和反序列化器,并通过`@JsonSerialize`和`@JsonDeserialize`注解应用到字段上。 ```java public class Product { @JsonDeserialize(using = CustomPriceDeserializer.class) private long priceInCents; // ... } ``` ### 注意事项 - 必须为Java实体类提供**无参构造函数**。 - 需要提供字段的**getter和setter**方法(或者使用public字段,但不推荐)。 - 如果使用Lombok,确保生成的代码符合上述要求。 ### 示例:使用Elasticsearch客户端进行查询 ```java // 查询文档 GetResponse<Product> response = client.get(g -> g .index("products") .id("123"), Product.class ); Product product = response.source(); System.out.println(product.getProductName()); ``` ### 总结 | 方法 | 适用场景 | 优点 | 缺点 | |------|----------|------|------| | `@JsonProperty` | 单个字段特殊命名 | 精确控制每个字段 | 每个字段都要加注解 | | 全局命名策略 | 整个项目统一命名规则 | 减少注解使用 | 不适用于特殊命名字段 | | `@JsonAlias` | 多别名映射 | 灵活处理不同来源数据 | 需要Jackson 2.9+ | | 自定义序列化器 | 复杂字段转换 | 处理复杂逻辑 | 实现复杂 | §§相关问题§§ 1. 如何在Elasticsearch Java客户端中配置日期格式映射? 2. 如何忽略Java实体类中不需要映射到ES文档的字段? 3. Elasticsearch Java客户端如何处理嵌套对象? 4. 如何自定义Jackson的ObjectMapper以支持更多特性? </think>### Elasticsearch Java API 实现字段映射的方法 在 Elasticsearch Java 客户端(`elasticsearch-java` API)中,实现 ES 字段与 Java Bean 字段名称映射主要有以下三种方式: --- #### 1. 使用 **`@JsonProperty` 注解**(推荐) 通过 Jackson 注解指定字段映射关系: ```java import com.fasterxml.jackson.annotation.JsonProperty; public class Product { // 映射ES字段"product_name" @JsonProperty("product_name") private String productName; // 映射ES字段"price_in_cents" @JsonProperty("price_in_cents") private long price; // 必须有无参构造器 public Product() {} // Getter/Setter省略... } ``` --- #### 2. 配置 **全局命名策略** 在创建 Elasticsearch 客户端时指定命名策略: ```java import co.elastic.clients.elasticsearch.ElasticsearchClient; import co.elastic.clients.json.jackson.JacksonJsonpMapper; import co.elastic.clients.transport.ElasticsearchTransport; import com.fasterxml.jackson.databind.PropertyNamingStrategies; // 创建ObjectMapper配置蛇形命名策略 ObjectMapper mapper = new ObjectMapper() .setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); // 应用命名策略到客户端 ElasticsearchTransport transport = new RestClientTransport( restClient, new JacksonJsonpMapper(mapper) // 关键配置 ); ElasticsearchClient client = new ElasticsearchClient(transport); ``` 此时 Java 字段 `productName` 会自动映射到 ES 字段 `product_name`[^1] --- #### 3. 自定义 **字段映射器**(高级) 实现字段级别的自定义转换: ```java import co.elastic.clients.json.JsonpMapper; import co.elastic.clients.json.JsonpDeserializer; import co.elastic.clients.json.JsonpSerializable; import jakarta.json.stream.JsonGenerator; public class CustomMapper implements JsonpSerializable { private String productName; // 自定义序列化/反序列化逻辑 @Override public void serialize(JsonGenerator generator, JsonpMapper mapper) { generator.write("product_name", productName); } public static JsonpDeserializer<CustomMapper> parser() { return JsonpDeserializer.of( (parser, mapper) -> new CustomMapper(parser.getString()) ); } } ``` --- ### 完整使用示例 ```java // 创建客户端(使用蛇形命名策略) ElasticsearchClient client = ... // 配置见方法2 // 插入文档 Product product = new Product("Laptop", 99900); client.index(i -> i .index("products") .id("001") .document(product) ); // 查询文档 Product result = client.get(g -> g .index("products") .id("001"), Product.class ).source(); System.out.println(result.getProductName()); // 输出 "Laptop" ``` --- ### 映射规则对比 | 方法 | 适用场景 | 优点 | 缺点 | |--------------------|-------------------------|-------------------------|--------------------| | `@JsonProperty` | 个别字段特殊映射 | 精确控制单个字段 | 需修改实体类 | | 全局命名策略 | 统一命名规范 | 批量配置,减少注解 | 无法处理例外情况 | | 自定义映射器 | 复杂转换逻辑 | 完全控制序列化过程 | 实现复杂度高 | > ⚠️ **重要注意事项** > 1. Java 类必须有无参构造器 > 2. 需要完整的 Getter/Setter 方法 > 3. 使用 `@JsonIgnoreProperties(ignoreUnknown = true)` 忽略多余字段[^1] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值