探索Elasticsearch:文档的CRUD

发布于:2025-03-04 ⋅ 阅读:(10) ⋅ 点赞:(0)

在企业环境中,Elasticsearch对文档操作的支持不仅是实现高效搜索的关键,更是数据驱动决策的重要支柱。它通过强大的索引机制和灵活的查询语言,使企业能够实时处理和分析海量文档数据,迅速获取有价值的洞察,从而加速创新、优化运营并提升客户体验。 Elasticsearch让文档管理从简单的存储检索升级为智能信息发掘,成为现代企业不可或缺的数据处理引擎。


目录

文档的CRUD

基于Kibana控制台操作

新增文档

查询文档

修改文档

全量修改

局部修改

删除文档

基于Java REST Client 实现

准备依赖

准备实体类

初始化RestHighLevelClient

查询文档

删除文档

批处理操作文档


elasticsearch是面向文档(Document)存储的,可以是数据库中的一条商品数据,一个订单信息。文档数据会被序列化为json格式后存储在elasticsearch中。

上文中我们有了索引库,接下来就可以向索引库中添加数据了。

Elasticsearch中的数据其实就是JSON风格的文档。操作文档自然保护等几种常见操作。

文档的CRUD

基于Kibana控制台操作

新增文档

# 新增文档
POST /user/_doc/1
{
    "info": "我们都会找到好工作",
    "email": "zy@itcast.cn",
    "name": {
        "firstName": "云",
        "lastName": "赵"
    }
}

实现效果如下:


查询文档

# 查询文档
GET /user/_doc/1

实现效果如下:


修改文档

全量修改
# 全量修改
PUT /user/_doc/1
{
    "info": "我们都会找到幸福",
    "email": "ZZZ@itcast.cn",
    "name": {
        "firstName": "云",
        "lastName": "赵"
    }
}

实现效果如下:

局部修改
# 局部修改Java
POST /user/_update/1
{
  "doc": {
    "email": "ZhaoYun@itcast.cn"
  }
}

实现效果如下:


删除文档

# 删除文档
DELETE /user/_doc/1

实现效果如下:


基于Java REST Client 实现

准备依赖

上文导入了es的依赖

        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>
        <!-- mybatisPlus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3.1</version>
        </dependency>
        <!--hutool工具包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.14</version>
        </dependency>

准备一个数据库表(毕竟是测试,就建了一张表)

准备实体类

准备普通实体类Item和引库结构对应的实体类ItemDoc

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)

public class Item implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 商品id
     */
    private Long id;

    /**
     * SKU名称
     */
    private String name;

    /**
     * 价格(分)
     */
    private Integer price;

    /**
     * 库存数量
     */
    private Integer stock;

    /**
     * 商品图片
     */
    private String image;

    /**
     * 类目名称
     */
    private String category;

    /**
     * 品牌名称
     */
    private String brand;

    /**
     * 规格
     */
    private String spec;

    /**
     * 销量
     */
    private Integer sold;

    /**
     * 评论数
     */
    private Integer commentCount;

    /**
     * 是否是推广广告,true/false
     */
    @TableField("isAD")
    private Boolean isAD;

    /**
     * 商品状态 1-正常,2-下架,3-删除
     */
    private Integer status;

    /**
     * 创建时间
     */
    private LocalDateTime createTime;

    /**
     * 更新时间
     */
    private LocalDateTime updateTime;

    /**
     * 创建人
     */
    private Long creater;

    /**
     * 修改人
     */
    private Long updater;



}
@Data
public class ItemDoc {

        private String id;


        private String name;


        private Integer price;


        private String image;


        private String category;


        private String brand;


        private Integer sold;


        private Integer commentCount;

        @TableField("isAD")
        private Boolean isAD;


        private LocalDateTime updateTime;

}

准备一个ItemMapper

@Mapper
public interface ItemMapper extends BaseMapper<Item> {

}

创建一个测试类ElasticDocTest

初始化RestHighLevelClient

 private RestHighLevelClient client;

    @Autowired
    private ItemMapper itemMapper;

    /**
     * 初始化ES客户端
     */
    @BeforeEach
    void setUp() {
        client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://自己的虚拟机地址:9200")
        ));
    }

    /**
     * 关闭ES客户端
     * @throws IOException
     */
    @AfterEach
    void tearDown() throws IOException {
        if (client != null) {
            client.close();
        }
    }

    /**
     * 测试连接
     */
    @Test
    void testConnection() {
        System.out.println("client = " + client);
    }

测试连接

连接ES客户端成功


新增文档

    /**
     * 新增文档
     * @throws IOException
     */
    @Test
    void testIndexDoc() throws IOException {
        // 1.根据id查询商品数据
        Item item = itemMapper.selectById(11);
        // 2.转换为文档类型
        ItemDoc itemDoc = BeanUtil.copyProperties(item, ItemDoc.class); // 修改类名
        // 3.将ItemDTO转json
        String doc = JSONUtil.toJsonStr(itemDoc);

        // 1.准备Request对象
        IndexRequest request = new IndexRequest("items").id(itemDoc.getId());
        // 2.准备Json文档
        request.source(doc, XContentType.JSON);
        // 3.发送请求
        client.index(request, RequestOptions.DEFAULT);
    }

查询文档

 /**
     * 根据id查询文档
     * @throws IOException
     */
    @Test
    void testGetDocumentById() throws IOException {
        // 1.准备Request对象
        GetRequest request = new GetRequest("items").id("11");
        // 2.发送请求
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        // 3.获取响应结果中的source
        String json = response.getSourceAsString();

        ItemDoc itemDoc = JSONUtil.toBean(json, ItemDoc.class);
        System.out.println("itemDoc= " + itemDoc);
    }

实现效果如下:

验证:新增文档和查询文档的成功了

修改文档

    /**
     * 根据id更新文档
     * @throws IOException
     */
    @Test
    void testUpdateDocument() throws IOException {
        // 1.准备Request
        UpdateRequest request = new UpdateRequest("items", "11");
        // 2.准备请求参数
        request.doc(
                "price", 66666,
                "commentCount", 1
        );
        // 3.发送请求
        client.update(request, RequestOptions.DEFAULT);
    }

实现效果如下:(重新查询后与上图对比)


删除文档

   /**
     * 根据id删除文档
     * @throws IOException
     */
    @Test
    void testDeleteDocument() throws IOException {
        // 1.准备Request,两个参数,第一个是索引库名,第二个是文档id
        DeleteRequest request = new DeleteRequest("items", "11");
        // 2.发送请求
        client.delete(request, RequestOptions.DEFAULT);
    }

实现效果如下:(重新查询后与上图对比)


批处理操作文档

在之前的测试中,我们都是操作单个文档。而数据库中的商品数据实际会达到数十万条,某些项目中可能达到数百万条。

我们如果要将这些数据导入索引库,肯定不能逐条导入,而是采用批处理方案。

演示批量导入

@Test
    void testLoadItemDoc() throws IOException {
        // 分页查询商品数据
        int pageNo = 1;
        int size = 100;

        while (true) {
            // 查询当前页数据
            Page<Item> page = itemService.lambdaQuery()
                    .eq(Item::getStatus, 1)
                    .page(new Page<>(pageNo, size));

            // 获取当前页记录
            List<Item> items = page.getRecords();

            // 如果当前页没有数据,退出循环
            if (CollUtil.isEmpty(items)) {
                log.info("所有数据已加载完成");
                break;
            }

            log.info("加载第{}页数据,共{}条", pageNo, items.size());

            // 创建批量请求
            BulkRequest request = new BulkRequest("items");

            // 遍历当前页数据,添加到批量请求中
            for (Item item : items) {
                ItemDoc itemDoc = BeanUtil.copyProperties(item, ItemDoc.class);
                request.add(new IndexRequest()
                        .id(itemDoc.getId())
                        .source(JSONUtil.toJsonStr(itemDoc), XContentType.JSON));
            }

            // 发送批量请求
            client.bulk(request, RequestOptions.DEFAULT);

            // 如果没有下一页数据,退出循环
            if (!page.hasNext()) {
                log.info("没有更多数据了");
                break;
            }

            // 翻页
            pageNo++;
        }
    }

实现效果如下:(主要我就准备了15条)