当前位置: 代码网 > it编程>编程语言>Java > springboot 集成 es--未完结

springboot 集成 es--未完结

2024年07月28日 Java 我要评论
一、前提知识常见的两种方式:spring boot提供的API 和 ES 官方提供的APIES官方:RestHighLevelClient:适用于复杂、更细粒度控制的Elasticsearch 操作spring boot:ElasticsearchRestTemplate:比 RestHighLevelClient 抽象更高,更接近于 Spring Data 的风格,当你想利用 Spring Data 的特性(如查询方法、分页等)与 Elasticsearch 交互时,这是一个很好的选择

基于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;
    }
}


(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com