项目中使用es(一):使用springboot操作elasticsearch

news2024/11/29 20:46:37

使用springboot操作es

      • 写在前面
      • 搭建项目环境和选择合适版本
      • 具体的代码实现(1)继承ProductInfoRepository
      • 具体的代码实现(2)使用ElasticsearchRestTemplate操作
      • 问题总结
      • 最后放个demo

写在前面

对于elasticsearch的搭建,前面写了一篇文章有简单描述如何搭建es,本次主要介绍如何在项目里使用,主要使用ElasticsearchRepository和ElasticsearchRestTemplate操作es。

搭建项目环境和选择合适版本

首先选择合适的项目组件版本,因为es版本和springboot版本有对应,如果不合适会报错。
这里以es7.6.x版本、springboot2.7.12,java8、maven3.8写出来的demo。
首先引入maven

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.7.12</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

主要还是第一个dependency配置,就是操作es的。

具体的代码实现(1)继承ProductInfoRepository

1.config类,主要用于配置扫描操作es所用的repository

@Configuration
@EnableElasticsearchRepositories(basePackages = "com.es.demo.repository")
public class ElasticsearchConfig {
}

2.对应的实体类ProductInfo

@Data
@Document(indexName = "product-info")
public class ProductInfo implements Serializable {

    @Id
    private Integer id;
    @Field(type = FieldType.Text, searchAnalyzer = "ik_max_word", analyzer = "ik_smart")
    private String productName;
    @Field(type = FieldType.Text, searchAnalyzer = "ik_max_word", analyzer = "ik_smart")
    private String description;
    @Field(type = FieldType.Keyword)
    private Date createTime;
    @Field(type = FieldType.Keyword)
    private BigDecimal price;
    @Field(type = FieldType.Integer)
    private Integer num;

}

3.创建repository包,这里防止所有的es对应的索引操作类。所有类继承org.springframework.data.elasticsearch.repository.ElasticsearchRepository,这里以ProductInfo为例:

@Component
public interface ProductInfoRepository extends ElasticsearchRepository<ProductInfo, Integer> {
}

第一个泛型是操作的索引类,第二个是唯一标识(id)对应的类型,
在这个类里按照一定的规则可以直接写一些方法名,不用写实现,ElasticsearchRepository会自动帮我们实现。具体我没有写,你们可以去网上搜一下怎么写。

4.因为ProductInfoRepository中实现了基本的增删改查,所以在这里可以直接使用
在这里插入图片描述
如何使用:

public class ProductServiceImpl implements ProductService {
    @Autowired
    private ProductInfoRepository productInfoRepository;

    @Override
    public Boolean save(ProductInfo... productInfo) {
        productInfoRepository.saveAll(Arrays.asList(productInfo));
        return true;
    }

    @Override
    public Boolean delete(Integer id) {
        productInfoRepository.deleteById(id);
        return null;
    }

    @Override
    public ProductInfo getById(Integer id) {
        Optional<ProductInfo> byId = productInfoRepository.findById(id);
        return byId.orElse(null);
    }

    @Override
    public List<ProductInfo> getAll() {
        List<ProductInfo> list = new ArrayList<>();
        productInfoRepository.findAll().forEach(list::add);
        return list;
    }

具体的代码实现(2)使用ElasticsearchRestTemplate操作

1.对于一些复杂的查询我是直接使用ElasticsearchRestTemplate这个类来操作的。写了一个公共类,类似mybatisplus的service抽象,具体service接口和实现类可以直接继承。也是看别的开源项目这么写自己总结出来的。
首先是接口层BasicEsService:


public interface BasicEsService<T> {

    /**
     * 保存数据
     *
     * @param indexEnum 索引
     * @param ts        数据
     */
    void save(IndexEnum indexEnum, T... ts);

    /**
     * 删除数据
     *
     * @param indexEnum 索引
     * @param id        id
     */
    void delete(IndexEnum indexEnum, String id);

    /**
     * 查询单个数据
     *
     * @param indexEnum
     * @param id
     * @param clazz
     * @return
     */
    T getById(IndexEnum indexEnum, String id, T clazz);

    /**
     * 查询所有数据,es限制最多返回10000条
     *
     * @param indexEnum
     * @param clazz
     * @return
     */
    List<T> getAllData(IndexEnum indexEnum, T clazz);

    /**
     * 动态sql查询
     *
     * @param sql
     * @param clazz
     * @return
     */
    List<Map<String, Object>> query(String sql, T clazz);

    /**
     * 范围查询
     *
     * @param pageNo
     * @param pageSize
     * @param indexEnum
     * @param order
     * @param rangeParam
     * @return
     */
    Page<T> rangeQuery(Integer pageNo, Integer pageSize, IndexEnum indexEnum, Map<String, String> order, Map<String, Object[]> rangeParam, T clazz);

    /**
     * 分页查询,默认十条,支持多字段模糊匹配,多字段排序
     *
     * @param pageNo   从0开始
     * @param pageSize 每页记录数
     * @param keyword  关键词
     * @param clazz    转换的对象
     * @param order    排序集合
     * @param fields   搜索的列
     * @return
     */
    Page<T> pageList(Integer pageNo, Integer pageSize, String keyword, T clazz, Map<String, String> order, String... fields);

然后是实现类BasicEsServiceImpl


@Service
public class BasicEsServiceImpl<T> implements BasicEsService<T> {

    @Autowired
    protected ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Override
    public void save(IndexEnum indexEnum, T... ts) {
        T[] save = elasticsearchRestTemplate.save(ts, IndexCoordinates.of(indexEnum.getIndex()));
        return;
    }
    @Override
    public void delete(IndexEnum indexEnum, String id) {
        String delete = elasticsearchRestTemplate.delete(id, IndexCoordinates.of(indexEnum.getIndex()));
    }
    @Override
    public T getById(IndexEnum indexEnum, String id, T clazz) {
        elasticsearchRestTemplate.get(id, clazz.getClass(), IndexCoordinates.of(indexEnum.getIndex()));
        return null;
    }
    @Override
    public List<T> getAllData(IndexEnum indexEnum, T clazz) {
        Query query = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.matchAllQuery()).build();
        SearchHits<T> searchHits = (SearchHits<T>) elasticsearchRestTemplate.search(query, clazz.getClass(), IndexCoordinates.of(indexEnum.getIndex()));
        return searchHits.get().map(SearchHit::getContent).collect(Collectors.toList());
    }
    @Override
    public List<Map<String, Object>> query(String sql, T clazz) {
        throw new AbstractMethodError();
    }
    @Override
    public Page<T> rangeQuery(Integer pageNo, Integer pageSize, IndexEnum indexEnum, Map<String, String> order, Map<String, Object[]> rangeParam, T clazz) {
        //范围查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        rangeParam.keySet().forEach(field -> {
            boolQueryBuilder.must(new RangeQueryBuilder(field).gt(rangeParam.get(field)[0]).lt(rangeParam.get(field)[1]));
        });
        PageRequest of = PageRequest.of(pageNo, pageSize);
        List<FieldSortBuilder> sortBuilderList = order.keySet().stream()
                .map(field -> SortBuilders.fieldSort(field).order(SortOrder.valueOf(order.get(field))))
                .collect(Collectors.toList());
        Query searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQueryBuilder)
                .withPageable(of)
                .withSorts((SortBuilder<?>) sortBuilderList)
                .build();
        SearchHits<T> searchHits = (SearchHits<T>) elasticsearchRestTemplate.search(searchQuery, clazz.getClass());
        SearchPage<T> searchHits1 = SearchHitSupport.searchPageFor(searchHits, searchQuery.getPageable());
        return new PageImpl<>(searchHits.get().map(SearchHit::getContent).collect(Collectors.toList()), searchHits1.getPageable(), searchHits1.getTotalElements());
    }
    @Override
    public Page<T> pageList(Integer pageNo, Integer pageSize, String keyword, T clazz, Map<String, String> order, String... fields) {
        //分页,页码从0开始
        PageRequest of = PageRequest.of(pageNo, pageSize);
        List<FieldSortBuilder> collect = order.keySet().stream()
                .map(field -> SortBuilders.fieldSort(field).order(SortOrder.valueOf(order.get(field))))
                .collect(Collectors.toList());

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        Arrays.asList(fields).forEach(e -> boolQueryBuilder.should(QueryBuilders.fuzzyQuery(e, keyword)));
        Query searchQuery = new NativeSearchQueryBuilder()
                //条件
                .withQuery(boolQueryBuilder)
                //分页
                .withPageable(of)
                //排序
                .withSorts((SortBuilder<?>) collect)
                .build();
        SearchHits<T> searchHits = (SearchHits<T>) elasticsearchRestTemplate.search(searchQuery, clazz.getClass());
        SearchPage<T> searchHits1 = SearchHitSupport.searchPageFor(searchHits, searchQuery.getPageable());
        return new PageImpl<>(searchHits.get().map(SearchHit::getContent).collect(Collectors.toList()), searchHits1.getPageable(), searchHits1.getTotalElements());
    }
}

因为ElasticsearchRestTemplate这个操作需要传入具体的索引名称,所以我创建了一个公共枚举类存放es索引名称
IndexEnum

@Getter
@AllArgsConstructor
public enum IndexEnum {

    PRODUCT_INFO("product-info", "_doc");

    private String index;
    private String type;
}

使用的话就直接继承就行了
接口层

public interface ProductService extends BasicEsService<ProductInfo>{
}

实现层

@Service
@Slf4j
public class ProductServiceImpl extends BasicEsServiceImpl<ProductInfo> implements ProductService {
}

后面如果有公共的方法也可以抽出来放在公共类里。

问题总结

1.问题1:启动报错org.elasticsearch.client.ResponseException: method [PUT], host [http://10.0.180.100:9200], URI [/productInfo], status line [HTTP/1.1 406 Not Acceptable]

org.elasticsearch.client.ResponseException: method [PUT], host [http://10.0.180.100:9200], URI [/productInfo], status line [HTTP/1.1 406 Not Acceptable]

这是因为springboot和es版本不对应导致的,我最开始用的是springboot3和es7.6,后来把springboot版本降到了2.7.x。

问题2:“type”:“invalid_index_name_exception”

org.elasticsearch.client.ResponseException: method [PUT], host [http://10.0.180.100:9200], URI [/productInfo?master_timeout=30s&timeout=30s], status line [HTTP/1.1 400 Bad Request]
{"error":{"root_cause":[{"type":"invalid_index_name_exception","reason":"Invalid index name [productInfo], must be lowercase","index_uuid":"_na_","index":"productInfo"}],"type":"invalid_index_name_exception","reason":"Invalid index name [productInfo], must be lowercase","index_uuid":"_na_","index":"productInfo"},"status":400}

这是因为我索引名称用了大写字母,而es规定索引名称不能使用大写,所以修改配置
@Document(indexName = “productInfo”),替换成了@Document(indexName = “product-info”)

最后放个demo

最后在放一个我写的demo地址,有兴趣可以看下
https://gitee.com/wdvc/es-demo.git
唉,就这样吧,如果有问题请指出来我马上修改

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/589818.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Top10】天津高性价比Web前端培训机构(Web前端需要掌握什么技能)

Web前端开发已经成为了一门备受瞩目的技能&#xff0c;对于一些初学者或者转行的人来说&#xff0c;也是非常友好的&#xff0c;当然越火也越会存在争议&#xff0c;大部分没有经验的人会选择参加培训来学习Web前端技术&#xff0c;也有不少人对于参加Web前端培训的必要性存在疑…

项目管理系统的设计与实现(ASP.NET,SQL)

开发环境&#xff1a;Microsoft Visual Studio 数据库&#xff1a;Microsoft SQL Server 程序语言&#xff1a;asp.NET(C#)语言本系统的开发使各大公司所的项目管理更加方便快捷&#xff0c;同时也促使项目的管理变的更加系统化、有序化。系统界面较友好&#xff0c;易于操作。…

AIGC下的低代码赛道,你我皆是拓荒人

今年年初&#xff0c;ChatGPT的现象级爆发&#xff0c;让其底层技术AIGC的承载方OpenAI备受关注。几重buff叠加&#xff0c;打工人的命运可以说是跌宕起伏&#xff0c;命途多舛了。在国内&#xff0c;AIGC的长期价值已逐渐被挖掘&#xff0c;正在重构人们的办公、娱乐乃至生活方…

启真医学大模型

启真医学大模型 QiZhenGPT: An Open Source Chinese Medical Large Language Model 本项目利用启真医学知识库构建的中文医学指令数据集&#xff0c;并基于此在LLaMA-7B模型上进行指令精调&#xff0c;大幅提高了模型在中文医疗场景下效果&#xff0c;首先针对药品知识问答发…

事务隔离级别-浅析

事务隔离级别是指在并发操作下&#xff0c;不同的事务之间互相隔离的程度。常见的事务隔离级别有以下四种&#xff1a; 读未提交&#xff08;Read Uncommitted&#xff09;&#xff1a;一个事务可以读取另一个未提交事务的数据。这样可能会导致脏读、不可重复读和幻读等问题。…

是德KEYSIGHT N9918A、N9917A 手持式射频和微波组合分析仪

是德&#xff08;KEYSIGHT) N9917A,N9918A 手持式射频和微波组合分析仪 Keysight N9918A FieldFox 组合分析仪能够处理日常维护、深度故障排除以及介于两者之间的任何事情。Keysight N9918A (Agilent) FieldFox 可随时随地为您提供高质量测量。将 FieldFox N9918A 添加到您的故…

面试官:你来说一下分布式锁的设计与实现

今天跟大家探讨一下分布式锁的设计与实现。希望对大家有帮助&#xff0c;如果有不正确的地方&#xff0c;欢迎指出&#xff0c;一起学习&#xff0c;一起进步哈~ 分布式锁概述 数据库分布式锁 Redis分布式锁 Zookeeper分布式锁 三种分布式锁对比 1. 分布式锁概述 我们的…

低代码制造ERP管理系统:降低开发成本,提高生产效率

随着制造业的快速发展&#xff0c;ERP管理系统成为了现代制造业中不可或缺的一部分。ERP管理系统可以帮助企业更好地管理生产流程、库存和供应链等方面&#xff0c;从而提高企业的生产效率和竞争力。然而&#xff0c;传统的ERP管理系统往往需要大量的编程工作和长周期的开发过程…

Kali渗透Windows服务器

这个实验主要让我们学习漏洞扫描技术基本原理&#xff0c;了解其在网络攻防中的作用&#xff0c;掌握使用Kali中的Metasploit对目标主机渗透&#xff0c;并根据报告做出相应的防护措施。 本次实战环境&#xff1a;Kali渗透Windows服务器 实战步骤一 本实验通过利用kali进行漏…

【springcloud微服务】Spring Cloud Alibaba 整合dubbo与openfeign

一、前言 dubbo与springcloud都可以单独作为微服务治理框架在生产中进行使用&#xff0c;但使用过springcloud的同学大概了解到&#xff0c;springcloud生态的相关组件这些年已经逐步停更&#xff0c;这就导致在服务架构演进过程中的迭代断层&#xff0c;以至于一些新的技术组…

LabVIEWCompactRIO 开发指南第六章43

LabVIEWCompactRIO 开发指南第六章43 复用 模块中较昂贵的组件之一是ADC。通过使用多路复用器&#xff08;也称为多路复用器&#xff09;通过单个ADC路由多个通道&#xff0c;多路复用模块以比同步模块更低的每通道价格提供更高的通道数。 在学习如何对这些模块进行编程之前…

前端学习Flutter笔记(第一章:安装软件,配置环境变量等)

学习背景 人都是有惰性的&#xff0c;如果没有外界压力&#xff0c;基本不会取主动学习&#xff0c;有那个学习的时间宁愿多刷点小视频。。。。 公司有项目使用Flutter写的&#xff0c;想让我接手&#xff0c;可是咱不会啊&#xff0c;没接触过。就浅浅的在b站着了几个视频。 第…

什么是腾讯云轻量应用服务器?轻量与云服务器对比区别有哪些?

什么是腾讯云轻量应用服务器&#xff1f;轻量应用服务器是腾讯云推出的开箱即用轻量级云服务器&#xff0c;适合个人开发者或中小企业使用&#xff0c;腾讯云轻量服务器和云服务器有什么区别&#xff1f;为什么轻量应用服务器成本更低&#xff1f;是因为轻量服务器CPU内存性能比…

Transformer-《Attention Is All You Need》

目录 0.Transformer介绍 1.self-attention 和Multi-heads self-attention 1.1 self-attention&#xff08;自注意力机制&#xff09; 1.2 Multi-heads self-attention&#xff08;多头自注意力机制&#xff09; 2.网络结构 2.1 encoder&#xff08;编码器&#xff09; 2…

【尔嵘】感恩四周年,感谢支持

前言 注意&#xff1a;为感谢各位铁粉支持&#xff0c;【尔嵘】将随机一个号码赠送一本vue.js书籍&#xff0c;欢迎评论区留言&#xff01; 在当前互联网领域中&#xff0c;CSDN是一个非常知名的技术社区&#xff0c;在这里你可以接触到很多高质量的技术文章和技术交流。对于技…

九年测试老鸟,写给1~5年的测试工程师的几点建议,满满硬货指导

从15年毕业到现在也从业八年了&#xff0c;普通本科毕业&#xff0c;现在一家互联网公司担任测试部门总监&#xff0c;摸爬打滚&#xff0c;坑坑洼洼也经历了不少。思绪很久决定还是写下这篇&#xff0c;希望对后进的小伙子少走一点弯路。 很多人把职场想得太美好&#xff0c;其…

七人拼团系统开发模式详解

七人拼团是最近兴起的一个模式&#xff0c;它通过更人性化的奖励机制&#xff0c;将产品利润最大化让利给参与拼团的用户&#xff0c;达到促进用户主动积极裂变和团队平台引流提升销量的效果&#xff0c;下面就来详细说一下这个模式。 七人拼团最大的特点&#xff0c;就是结合了…

JVM之栈和堆运行时内存深度剖析

运行时内存篇 程序计数器 也是线程私有的,不共享,因为cpu时间片轮换的缘故,所以需要记录上次未执行完的线程执行到那条字节码指令了,所以每个线程需要记录当前执行的命令的内存指针,以方便线程再次得到执行的时候按照正确的顺序执行 JVM之栈(虚拟机栈) 基础知识 会gc吗 不…

pinpoint安装部署(相关博客合集)

pinpoint安装部署 说明一、PinPoint介绍及工作原理1.1 确定部署的组件及服务 二、相关组件版本兼容情况2.1 确定版本 三、部署3.1 HBASE3.2 agent 说明 本博客写在搭建PinPoint之前&#xff0c;主要是用来记录查阅的相关博客资料&#xff0c;等到动手搭建完再更新实际部署操作…

医学可视化应用简介

VolView VolView是一款为临床专业人员开发的开源放射学查看器。使用VolView&#xff0c;可以通过交互式电影体积渲染对数据有更深入的视觉理解&#xff0c;并轻松地以3D形式可视化DICOM数据。由于VolView在浏览器中运行&#xff0c;不需要安装软件&#xff0c;数据也可以安全地…