springboot 集成 es--未完结

news2024/9/20 9:33:04

基于es7.10.x版本

一、前提知识

常见的两种方式:spring boot提供的APIES 官方提供的API

  • ES官方:

    RestHighLevelClient
    适用于复杂、更细粒度控制的Elasticsearch 操作

  • spring boot:
    ElasticsearchRestTemplate:比 RestHighLevelClient 抽象更高,更接近于 Spring Data 的风格,当你想利用 Spring Data 的特性(如查询方法、分页等)与 Elasticsearch 交互时,这是一个很好的选择,但有些复杂查询无法完成。
    ElasticsearchRepository:抽象级别最高,隐藏了与 Elasticsearch 交互的底层细节,并提供了基于方法的查询功能,能够快速实现 CRUD 操作。

建议使用RestHighLevelClient
原因:
版本:ElasticsearchRestTemplate本身与spring-boot-starter-data-elasticsearch紧密依赖。如果想升级ElasticsearchRestTemplate,那就必须连带升级项目的Springboot版本,这个风险就比较高了,一般项目的Springboot版本不会轻易升级
灵活度:比较灵活,可以直接使用ES的DSL语法,实现复杂查询,同时没有与其他部件绑定,所以版本可以自由选择。,由于ElasticsearchRestTemplate是spring-boot-starter-data-elasticsearch封装的工具类,虽然使用上稍微方便一些,但是失去了灵活性,出现问题时也不易排查。

二、环境搭建

1、es 官方

RestHighLevelClient 方式

        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>7.10.0</version>
        </dependency>

        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
            <version>7.10.0</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.10.0</version>
        </dependency>
spring:
  elasticsearch:
    uris: http://172.31.97.4:9280
    username: xxxx
    password: xxxx

2、springdata

ElasticsearchRestTemplate+ElasticsearchRepository 方式

首先springdata操作es必须要将版本号和es的版本号对应上,否则会报错(倒不用完全一一对应,但版本号最好不要相差太多)。springdata引入的版本号由springboot的版本号决定,对应关系如下:
在这里插入图片描述

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>
spring:
  elasticsearch:
    uris: http://172.31.97.4:9280
    username: xxxx
    password: xxxx

二、API方法

1、es 官方
工工具类

package com.wang.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
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.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
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.core.CountRequest;
import org.elasticsearch.client.core.CountResponse;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.index.query.AbstractQueryBuilder;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Spider Man
 * @date 2024-05-23 15:15
 */
@Component
@Slf4j
public class ESUtils {
    @Autowired
    RestHighLevelClient esHighLevelClient;

    /**
     * 获取总条数
     *
     * @param indexName
     * @return
     * @throws IOException
     */
    public long getTotalNum(String indexName) throws IOException {
        CountRequest countRequest = new CountRequest(indexName);
        // 如果需要,你可以在这里添加查询条件
        // countRequest.query(QueryBuilders.matchQuery("field_name", "value"));
        CountResponse countResponse = esHighLevelClient.count(countRequest, RequestOptions.DEFAULT);
        return countResponse.getCount();
    }

    /**
     * 获取总页数
     *
     * @param totalNum
     * @param limit
     * @return
     */
    public int getTotalPage(long totalNum, int limit) {
        //总页数
        return (int) Math.ceil((double) totalNum / limit);
    }


    /**
     * 批量插入数据
     *
     * @param indexName
     * @param list
     * @return boolean
     */
    public boolean multiAddDoc(String indexName, List<JSONObject> list) {
        try {
            BulkRequest bulkRequest = new BulkRequest();
            list.forEach(doc -> {
                String source = JSONUtil.toJsonStr(doc);
                IndexRequest indexRequest = new IndexRequest(indexName);
                indexRequest.source(source, XContentType.JSON);
                bulkRequest.add(indexRequest);
            });
            BulkResponse bulkResponse = esHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            if (bulkResponse.hasFailures()){
                log.error("批量插入失败,第一条错误原因为 {}",bulkResponse.getItems()[0].getFailureMessage());
            }else {
                log.info("批量插入成功,向索引 {} 中批量插入 {} 条数据", indexName, list.size());
            }
            return !bulkResponse.hasFailures();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 根据id更新文档,全部字段更新
     *
     * @param indexName
     * @param docId
     * @param jsonObject
     * @return boolean
     */
    public boolean updateDocAllFiled(String indexName, String docId, JSONObject jsonObject) {
        try {
            UpdateRequest updateRequest = new UpdateRequest(indexName, docId).doc(JSONUtil.toJsonStr(jsonObject), XContentType.JSON);
            UpdateResponse updateResponse = esHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
            int total = updateResponse.getShardInfo().getTotal();
            log.info("更新文档的影响数量为{}", total);
            return total > 0;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 局部更新
     *
     * @param indexName
     * @param map    key为文档的id,map为所要更新字段的字段名称和值
     * @return
     * @throws IOException
     */
    public boolean updateDocSomeFiled(String indexName, Map<String,Map<String, Object>> map) throws IOException {
        if (CollUtil.isEmpty(map)) {
            log.info("局部更新数据不能为空");
            return false;
        }
        BulkRequest bulkRequest = new BulkRequest();

        map.forEach((docId, value) -> {
            UpdateRequest updateRequest = new UpdateRequest(indexName, docId);
            updateRequest.doc(value);
            bulkRequest.add(updateRequest);
        });

        if (CollUtil.isNotEmpty(bulkRequest.requests())) {
            BulkResponse bulkResponse = esHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            if (bulkResponse.hasFailures()) {
                log.error("更新失败====》" + bulkResponse.buildFailureMessage());
                return false;
            }
            return true;
        } else {
            return false;
        }
    }


    /**
     * 例如:
     *     TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("ethnic_code.keyword", "汉族");
     *      Map<String, Object> map = esUtils.conditionSearchBySelfQuery(index, 1, 60, "pat_name",
     *      termQueryBuilder, "age_year", SortOrder.ASC, null, true);
     *
     *
     * 条件搜索分页
     *
     * @param indexName  索引库
     * @param pageNum    起始页
     * @param pageSize   每页大小
     * @param highName   高亮字段
     * @param abstractQueryBuilder   搜索条件
     * @param sortName   排序字段
     * @param sortOrder  排序类型
     * @param includes   显示的字段
     * @param isShowDocumentId  是否显示文档id
     * @return
     * @throws IOException
     */
    public Map<String, Object> conditionSearchBySelfQuery(String indexName, Integer pageNum, Integer pageSize, String highName, AbstractQueryBuilder abstractQueryBuilder, String sortName, SortOrder sortOrder, String[] includes, boolean isShowDocumentId) throws IOException {
        SearchRequest searchRequest = new SearchRequest(indexName);
        //构造搜索条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        sourceBuilder.fetchSource(includes, null);
        if (sortName != null && sortOrder != null) {
            sourceBuilder.sort(sortName, sortOrder);
        }
        sourceBuilder.query(abstractQueryBuilder);
        //高亮处理
        if (!StrUtil.isEmpty(highName)) {
            buildHighlight(sourceBuilder, highName);
        }
        //分页处理
        if (pageNum != null && pageSize != null) {
            sourceBuilder.from(pageSize * (pageNum - 1));
            sourceBuilder.size(pageSize);
        }
        //超时设置
        sourceBuilder.timeout(TimeValue.timeValueSeconds(60));
        System.out.println("DSL语句为:\n"+sourceBuilder);
        searchRequest.source(sourceBuilder);

        //执行搜索
        SearchResponse searchResponse = esHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits searchHits = searchResponse.getHits();
        List<JSONObject> resultList = new ArrayList<>();
        for (SearchHit hit : searchHits) {
            //原始查询结果数据
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            if (isShowDocumentId) {
                sourceAsMap.put("_id", hit.getId());
            }
            //高亮处理
            if (!StrUtil.isEmpty(highName)) {
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField highlightField = highlightFields.get(highName);
                if (highlightField != null) {
                    Text[] fragments = highlightField.fragments();
                    StringBuilder value = new StringBuilder();
                    for (Text text : fragments) {
                        value.append(text);
                    }
                    sourceAsMap.put(highName, value.toString());
                }
            }
            JSONObject jsonObject = JSONUtil.parseObj(JSONUtil.toJsonStr(sourceAsMap));
            resultList.add(jsonObject);
        }

        long total = searchHits.getTotalHits().value;

        Map<String, Object> pageMap = new HashMap<>();
        if (pageNum != null && pageSize != null) {
            //当前页
            pageMap.put("pageNum", pageNum);
            //每页显示条数
            pageMap.put("pageSize", pageSize);
            //总页数
            pageMap.put("totalPage", total == 0 ? 0 : (int) (total % pageSize == 0 ? total / pageSize : (total / pageSize) + 1));
        }
        //总条数
        pageMap.put("totalNum", total);
        //数据
        pageMap.put("data", resultList);
        return pageMap;
    }

    /**
     * 构建高亮字段
     *
     * @param sourceBuilder
     * @param highName
     */
    private void buildHighlight(SearchSourceBuilder sourceBuilder, String highName) {
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        //设置高亮字段
        highlightBuilder.field(highName);
        //多个高亮显示
        highlightBuilder.requireFieldMatch(false);
        //高亮标签前缀
        highlightBuilder.preTags("<span style='color:red'>");
        //高亮标签后缀
        highlightBuilder.postTags("</span>");
        sourceBuilder.highlighter(highlightBuilder);
    }


    /**
     * 根据id删除
     *
     * @param indexName
     * @param id
     */
    public void deleteById(String indexName, String id) {
        DeleteRequest deleteRequest = new DeleteRequest(indexName).id(id);
        try {
            DeleteResponse deleteResponse = esHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
            if (deleteResponse.status().getStatus() != RestStatus.OK.getStatus()) {
                log.error(">>>> 删除id={}数据失败,返回状态码={} <<<<", id, deleteResponse.status().getStatus());
            }
        } catch (IOException e) {
            log.error(">>>> 删除数据发生异常,id={},异常信息={} <<<<", id, e.getMessage());
        }
    }

    /**
     * 根据id查询
     *
     * @param indexName
     * @param id
     * @return
     */
    public Map<String, Object> queryById(String indexName, String id) {
        GetRequest getRequest = new GetRequest(indexName).id(id);
        Map<String, Object> map = null;
        try {
            GetResponse getResponse = esHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
            map = getResponse.getSource();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return map;
    }


    /**
     * 判断索引是否存在
     *
     * @param indexName 索引名称
     * @return
     * @throws IOException
     */
    public boolean indexIsExists(String indexName) throws IOException {
        GetIndexRequest getIndexRequest = new GetIndexRequest(indexName);
        return esHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
    }

    public boolean createIndex(String indexName, Map<String, Object> propertyMap) throws IOException {
        boolean flag = false;
        if (!indexIsExists(indexName)) {
            try {
                CreateIndexRequest index = new CreateIndexRequest("index_name");
                Map<String, Object> properties = new HashMap<>();
                Map<String, Object> propertie = new HashMap<>();
                propertie.put("type", "text");
                propertie.put("index", true);
                propertie.put("analyzer", "ik_max_word");
                properties.put("field_name", propertie);

                XContentBuilder builder = JsonXContent.contentBuilder();
                builder.startObject()
                        .startObject("mappings")
                        .startObject("index_name")
                        .field("properties", properties)
                        .endObject()
                        .endObject()
                        .startObject("settings")
                        .field("number_of_shards", 3)
                        .field("number_of_replicas", 1)
                        .endObject()
                        .endObject();
                index.source(builder);
                esHighLevelClient.indices().create(index, RequestOptions.DEFAULT);
                flag = true;
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException("创建索引和映射关系失败");
            }
        }
        return flag;
    }
}


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

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

相关文章

【软件设计师】——8.结构化与数据流图

目录 8.1 结构化分析 8.2 结构化设计 8.3 数据流图DFD 8.4 数据字典 8.1 结构化分析 结构化分析是面向数据流进行需求分析的方法&#xff0c;采用结构化方法进行系统分析时&#xff0c;根据分解与抽象原则&#xff0c;按照系统中数据处理的流程&#xff0c;用&#xff08;数…

211大学计算机专业不考408,新增的交叉专业却考408!南京农业大学计算机考研考情分析!

南京农业大学信息科技学院可追溯至1981年成立的计算中心和1985年筹建的农业图书情报专业。1987年设立了农业图书情报系&#xff0c;1993 年农业图书情报系更名为信息管理系&#xff0c;本科专业名称也于1999年更名为信息管理与信息系统专业。1994年计算中心开始招收计算机应用专…

三十篇:动脉脉搏:企业业务处理系统的生命力

动脉脉搏&#xff1a;企业业务处理系统的生命力 1. 引言 在数字经济的浪潮下&#xff0c;企业之间的竞争已不仅仅是产品和服务的竞争&#xff0c;更是信息处理能力的竞争。业务处理系统&#xff08;Transaction Processing System, TPS&#xff09;是企业信息系统架构的基础&a…

web题解,基础知识巩固(qsnctf)

1.文章管理系统 1&#xff09;打开题目&#xff0c;把它页面翻完了&#xff0c;没看懂它有啥用 2&#xff09;看了看源码&#xff0c;也是一样的&#xff0c;没找到有用的东西 3&#xff09;想着可能还是在隐藏文件里找&#xff0c;那我就直接用dirsearch扫扫看 4&#xff09;…

工业级3D开发引擎HOOPS:创新与效率的融合!

在当今这个技术日新月异的时代&#xff0c;3D技术已成为推动各行各业发展的重要力量。从工程设计到游戏开发&#xff0c;从虚拟现实到增强现实&#xff0c;3D技术的应用无处不在&#xff0c;它极大地丰富了我们的生活和工作。而在这样的背景下&#xff0c;HOOPS作为一个强大的3…

Vue.js - 计算属性与侦听器 【0基础向 Vue 基础学习】

文章目录 计算属性 computedcomputed 的使用方法computed 与 method 的区别计算属性完整写法 watch 侦听器&#xff08;监视器&#xff09;简单写法 → 简单类型数据&#xff0c;直接监视完整写法 → 添加额外配置项 计算属性 computed computed 的使用方法 **概念&#xff1…

【源码+文档+调试讲解】可信捐赠系统的设计与实现

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统可信捐赠系统信息管理难度大&#xff0c;容错率低&#x…

如何使用 Re-Ranking 改进大模型 RAG 检索

基于大型语言模型&#xff08;LLMs&#xff09;的聊天机器人可以通过检索增强生成&#xff08;RAG&#xff09;提供外部知识来改进。 这种外部知识可以减少错误答案&#xff08;幻觉&#xff09;&#xff0c;并且使模型能够访问其训练数据中未包含的信息。 通过RAG&#xff0…

【C++ 】学习问题及补充

一.自定义类型不初始化直接就赋值&#xff0c;比如string类会怎么样 vectr<string>里已经给每个string对象已经分配好空间&#xff0c;为什么不初始化再赋值会报错 在C中&#xff0c;std::string类是一个动态字符串类&#xff0c;它内部管理着一个字符数组&#xff0c;用…

Android network — 进程指定网络发包

Android network — 进程指定网络发包 0. 前言1. 进程绑定网络1.1 App进程绑定网络1.2 Native进程绑定网络 2. 源码原理分析2.1 申请网络requestNetwork2.2 绑定网络 BindProcessToNetwork 3. 总结 0. 前言 在android 中&#xff0c;一个app使用网络&#xff0c;需要在manifest…

力扣刷题--LCR 075. 数组的相对排序【简单】

题目描述 给定两个数组&#xff0c;arr1 和 arr2&#xff0c; arr2 中的元素各不相同 arr2 中的每个元素都出现在 arr1 中 对 arr1 中的元素进行排序&#xff0c;使 arr1 中项的相对顺序和 arr2 中的相对顺序相同。未在 arr2 中出现过的元素需要按照升序放在 arr1 的末尾。 …

Transformer详解(2)-位置编码

位置编码公式 偶数位置用sin,奇数位置用cos. d_model 表示token的维度&#xff1b;pos表示token在序列中的位置&#xff1b;i表示每个token编码的第i个位置&#xff0c;属于[0,d_model)。 torch实现 import math import torch from torch import nn from torch.autograd im…

四川景源畅信:抖音小店新手如何做?

随着短视频平台的兴起&#xff0c;抖音小店成为了许多创业者的新选择。但是&#xff0c;对于新手来说&#xff0c;如何在抖音上开设并经营好自己的小店呢?本文将围绕这一问题展开讨论。 一、明确目标和定位作为抖音小店的新手&#xff0c;首先要明确自己的经营目标和定位。是想…

Windows操作系统基本知识整理

目录 引言 一、Windows操作系统的发展历史 1.1 Windows 1.0到Windows 3.0 1.2 Windows 95到Windows Me 1.3 Windows NT到Windows 2000 1.4 Windows XP到Windows 7 1.5 Windows 8到Windows 10 二、Windows操作系统的核心组件 2.1 内核 2.2 文件系统 2.3 图形用户界面&…

Habicht定理中有关子结式命题3.4.6的证明

个人认为红色区域有问题&#xff0c;因为 deg ⁡ ( ϕ ( S j ) ) r \deg{\left( \phi\left( S_{j} \right) \right) r} deg(ϕ(Sj​))r&#xff0c;当 i ≥ r i \geq r i≥r时&#xff0c; s u b r e s i ( ϕ ( S j 1 ) , ϕ ( S j ) ) subres_{i}\left( \phi(S_{j 1}),\p…

【Java继承】(超级详细!!!)

【Java继承】&#xff08;超级详细&#xff01;&#xff01;&#xff01;&#xff09; 1、 继承的概念2 、继承的语法3、 父类成员访问3.1 子类中访问父类的成员变量3.2 子类中访问父类的成员方法 4、 super关键字5 、子类的构造方法6、 继承关系上的执行顺序7、protected 关键…

vscode在Ubantu键位错乱问题

摘要&#xff1a;抄的vscode键位错乱_有没有在使用vscode时偶尔遇到退格键无法正常删除内容的情况?如果有的话,你是如何-CSDN博客 只是作为记录&#xff0c;查找方便

Python使用MQTT连接新版ONENet

Python MQTT 连接新版ONENet 简介 前几个教程我们使用mqtt.fx连接了新版的ONENet, 只是跑通了MQTT协议&#xff0c;但是在实际操作下还需要实现具体环境、具体设备的MQTT连接&#xff0c;本章教程将以Python MQTT的方式连接 ONENet 参考文档&#xff1a; paho-mqtt PyPI …

左外连接和右外连接的区别?举例说明——以力扣sql 1378. 使用唯一标识码替换员工ID为例

左外连接&#xff08;LEFT JOIN&#xff09;和右外连接&#xff08;RIGHT JOIN&#xff09;的主要区别在于哪个表的所有行会保留在结果集中 1. 左外连接 (LEFT JOIN) 左外连接会返回左表中的所有行以及右表中符合连接条件的行。如果右表中没有匹配的行&#xff0c;结果集中右…

Livox-SDK2 用vs2017编译

Livox-SDK2 Livox-SDK2代码去上面下载&#xff0c;文章中给出的是用vs2019进行编译的&#xff0c;生成项目时用的 > cmake .. -G "Visual Studio 16 2019" -A x64 但如果我想用vs2017进行编译&#xff0c;那么只需要将上面语句改为如下&#xff1a; cmake .. -…