二、springboot整合elasticsearch+hanlp(7.16.2)----附完整测试用例

这篇具有很好参考价值的文章主要介绍了二、springboot整合elasticsearch+hanlp(7.16.2)----附完整测试用例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、实现效果图:

springboot集成hanlp,功能点汇总,elasticsearch,spring boot

二、主要实现以下几点:

1、springboot整合elasticsearch+hanlp分词器 (7.16.2) 。

2、实现基本的增删改查功能、关键字分页搜索、时间排序、关键字高亮等操作 。

建议elastic用7.16.2版本,(即使是用了其他比7.16更高的版本,基本语法是不会改变的,所以降到7.16并不会有非常大的影响)而且插件也只支持到7.16.2。)

三、gitee测试用例(推荐):

链接: https://gitee.com/muyangrenOvo/elastic-boot

四、部分实现代码

1、添加pom依赖

<!--elasticsearch7.16.2依赖包-->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-client</artifactId>
    <version>7.16.2</version>
</dependency>
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
<version>7.16.2</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.3</version>
</dependency>
<dependency>
    <groupId>jakarta.json</groupId>
    <artifactId>jakarta.json-api</artifactId>
    <version>2.0.1</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.12.3</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.12.3</version>
</dependency>

2、配置appllication.yml

#elasticsearch-ip-端口-索引-分词器(如下)-是否需要账号密码
#hanlp: hanlp默认分词
#hanlp_standard: 标准分词
#hanlp_index: 索引分词
#hanlp_n_short: N-最短路分词
#hanlp_dijkstra: 最短路分词
#hanlp_speed: 极速词典分词
elasticsearch:
  ip: 192.168.xxx.xxx:9200       
  index: transfer 
  analyzer: hanlp_index
  isNeedAccount: false	

3、配置ES信息

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 org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author muyangren
 * @Auther: muyangren
 * @Date: 2022/6/30
 * @Description: @Configuration 类似 xml-bean
 * @Version: 1.0
 */
  @Configuration
  public class ElasticSearchClientConfig {
      @Value("${elasticsearch.ip}")
      private String ip;
      @Value("${elasticsearch.isNeedAccount}")
      private boolean isNeedAccount;
      @Bean
      public ElasticsearchClient elasticsearchClient() {
          ElasticsearchClient client;
          //是否需要账号密码
          if (isNeedAccount){
              CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
              credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("elastic", "admin@123456"));
              RestClient restClient = RestClient.builder(this.getElasticSearchHttpHosts()).setHttpClientConfigCallback(httpAsyncClientBuilder -> {
                  httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                  return httpAsyncClientBuilder;
              }).build();
              ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
              client = new ElasticsearchClient(transport);
          }else {
              // Create the low-level client
              RestClient restClient = RestClient.builder(this.getElasticSearchHttpHosts()).build();
              // Create the transport with a Jackson mapper
              ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
              // And create the API client
              client = new ElasticsearchClient(transport);
          }
          return client;
      }
      /**
       * ElasticSearch 连接地址
       * 多个逗号分隔
       * 示例:127.0.0.1:9201,127.0.0.1:9202,127.0.0.1:9203
       */
      private HttpHost[] getElasticSearchHttpHosts() {
          String[] hosts = ip.split(",");
          HttpHost[] httpHosts = new HttpHost[hosts.length];
          for (int i = 0; i < httpHosts.length; i++) {
              String host = hosts[i];
              httpHosts[i] = new HttpHost(host.split(":")[0], Integer.parseInt(host.split(":")[1]));
          }
          return httpHosts;
      }
  }

4、集成工具类ElasticSearchUtils

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.ElasticsearchException;
import co.elastic.clients.elasticsearch._types.Result;
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch._types.mapping.TextProperty;
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem;
import co.elastic.clients.elasticsearch.indices.CreateIndexRequest;
import co.elastic.clients.elasticsearch.indices.CreateIndexResponse;
import co.elastic.clients.elasticsearch.indices.IndexSettings;
import co.elastic.clients.transport.endpoints.BooleanResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.talk.entity.TransEsContent;
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 guangsheng
 * @Date: 2022/7/14
 * @Description: 重构ES方法,解决代码重复问题 方法大致如此,细节需要自己去打磨
 * @Version: 1.0
 */
@Component
public class ElasticSearchUtils {

    private static final Logger logger = LoggerFactory.getLogger(ElasticSearchUtils.class);


    /**
     * 判断索引(index)是否存在
     */
    public static Boolean whetherIndex(ElasticsearchClient esClient,String index){
        BooleanResponse getIndexResponse;
        boolean whetherIndex = false;
        try {
            getIndexResponse = esClient.indices().exists(e -> e.index(index));
            whetherIndex = getIndexResponse.value();
        } catch (IOException e) {
            logger.info("es服务器超时,【{}】索引查询失败,请检查es服务器是否启动,该功能不影响后续代码执行。",index);
        }
        return whetherIndex;
    }

    /**
     * 添加索引
     * 分析器主要有两种情况会被使用:
     * 第一种是插入文档时,将text类型的字段做分词然后插入倒排索引,
     * 第二种就是在查询时,先对要查询的text类型的输入做分词,再去倒排索引搜索
     * analyzer: 分词器
     * searchAnalyzer: 查询分词器
     */
    public static Boolean addIndex(ElasticsearchClient esClient,String index,String analyzer){
        boolean whetherTrue =false;
        try {
            // 配置索引
            Map<String, Property> property = new HashMap<>(1);
            property.put("onlyOneBest", new Property(new TextProperty.Builder()
                    .analyzer(analyzer)
                    .searchAnalyzer(analyzer)
                    .index(true)
                    .store(true)
                    .build()));
            TypeMapping typeMapping = new TypeMapping.Builder()
                    .properties(property)
                    .build();
            IndexSettings indexSettings  = new IndexSettings.Builder()
                    .numberOfShards("5")
                    .build();
            CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder()
                    .index(index)
                    .mappings(typeMapping)
                    .settings(indexSettings)
                    .build();
            CreateIndexResponse createIndexResponse = esClient.indices().create(createIndexRequest);
            whetherTrue = Boolean.TRUE.equals(createIndexResponse.acknowledged());
        } catch (IOException e) {
            logger.info("es服务器超时,请检查es服务器是否启动,该功能不影响后续代码执行");
        } catch (ElasticsearchException e) {
            logger.info("同步服务器--es服务器未启用,或者版本错误导致");
        }
        return whetherTrue;
    }

    /**
     * ES添加方法
     */
    public static void addEsTransfer(ElasticsearchClient esClient, TransEsContent transEsContent , String index) {
        //存储到ES中
        try {
            CreateResponse createResponse = esClient.create(e -> e
                    .index(index)
                    .id(String.valueOf(transEsContent.getId()))
                    .document(transEsContent));
            Result result = createResponse.result();
            if (Func.isNotEmpty(result)) {
                logger.info("【id】:{},es添加数据:{}", transEsContent.getId(), result);
            }
        } catch (IOException e) {
            logger.info("【id】:{}未添加到es服务器,es服务器超时,请检查es服务器是否启动,该功能不影响后续代码执行", transEsContent.getId());
        } catch (ElasticsearchException e) {
            logger.info("添加---es服务器未启用,或者版本错误导致");
        }
    }

    /**
     * 同步所有数据
     * 批量超过一万条会超时,这里使用分页解决,每次插入五百条
     */
    public static void addAllEsTransfer(ElasticsearchClient esClient,List<TransEsContent> transList,String index) {
        BulkRequest.Builder builder = new BulkRequest.Builder();
        for (TransEsContent trans : transList) {
            builder.operations(op -> op
                    .index(idx -> idx
                            .index(index)
                            .id(String.valueOf(trans.getId()))
                            .document(trans)));
        }
        BulkResponse result;
        try {
            result = esClient.bulk(builder.build());
            if (Func.isNotEmpty(result)) {
                logger.info("数据同步到es服务器,数量为:" + result.took());
            }
        } catch (IOException e) {
            logger.info("es服务器超时,请检查es服务器是否启动,该功能不影响后续代码执行");
        } catch (ElasticsearchException e) {
            logger.info("同步服务器--es服务器未启用,或者版本错误导致");
        }
    }
    /**
     * ES更新方法
     */
    public static void updateEsTransfer(TransEsContent transEsContent, ElasticsearchClient esClient, String index) {
        try {
            //先查看是否存在ES服务中
            GetRequest.Builder builder = new GetRequest.Builder();
            GetRequest transfer = builder.index(index).id(String.valueOf(transEsContent.getId())).build();
            GetResponse<TransEsContent> getResponse = esClient.get(transfer, TransEsContent.class);
            TransEsContent source = null;
            if (Func.isNotEmpty(getResponse)) {
                source = getResponse.source();
            }
            //先根据id查询是否存在该数据
            if (Func.isEmpty(source)) {
                CreateResponse createResponse = esClient.create(e -> e
                        .index(index)
                        .id(String.valueOf(transEsContent.getId()))
                        .document(transEsContent));
                Result result = createResponse.result();
                if (Func.isNotEmpty(result)) {
                    logger.info("【id】:{},es添加数据:{}", transEsContent.getId(), result);
                }
            } else {
                //更新到es服务器中
                UpdateResponse<TransEsContent> updateResponse;
                updateResponse = esClient.update(e -> e
                                .index(index)
                                .id(String.valueOf(transEsContent.getId()))
                                .doc(transEsContent)
                        , TransEsContent.class);
                Result result = updateResponse.result();
                if (Func.isNotEmpty(result)) {
                    logger.info("【id】:{},es更新数据:{}", transEsContent.getId(), result);
                }
            }
        } catch (IOException e) {
            logger.info("【id】:{}未更新到es服务器,es服务器超时,请检查es服务器是否启动,该功能不影响后续代码执行", transEsContent.getId());
        } catch (ElasticsearchException e) {
            logger.info("更新---es服务器未启用,或者版本错误导致");
        }
    }

    /**
     * 异步删除ES服务器中的数据
     */
    public static void asyncDeleteEsTrans(List<TransEsContent> list, ElasticsearchClient esClient, String index) {
        new Thread(() -> {
            try {
                ArrayList<BulkOperation> bulkOperations = new ArrayList<>();
                for (TransEsContent trans : list) {
                    bulkOperations.add(new BulkOperation.Builder()
                            .delete(d -> d
                                    .id(String.valueOf(trans.getId()))
                                    .index(index))
                            .build());
                }
                BulkResponse bulkResponse = esClient.bulk(e -> e.index(index).operations(bulkOperations));
                List<BulkResponseItem> items = bulkResponse.items();
                if (Func.isNotEmpty(items)) {
                    logger.info("【id】:{},调用ES批量删除返回数据:{}", list.get(0).getId(), items);
                }
            } catch (IOException e) {
                logger.info("es服务器超时,【id】:{}未同步到es服务器,请检查es服务器是否启动,该功能不影响后续代码执行。", list.get(0).getId());
            } catch (ElasticsearchException e) {
                logger.info("删除---es服务器未启用,或者版本错误导致");
            }
        }).start();
    }
}

5、测试用例

springboot集成hanlp,功能点汇总,elasticsearch,spring boot

	@Value("${elasticsearch.analyzer}")
	private String analyzer;
	@Value("${elasticsearch.index}")
	private String index;
	@Autowired
	private ElasticsearchClient esClient;


  /**
     * 初始化数据
     * @return
  */
	@Override
	public Boolean initEsData() {
		//1、查询索引是否存在
		Boolean whetherTrue = ElasticSearchUtils.whetherIndex(esClient, index);

		if (!whetherTrue) {
			//2、不存在先添加索引在同步数据
			whetherTrue = ElasticSearchUtils.addIndex(esClient, index, analyzer);
		}
		//3、获取需要添加的总数(select count(1) from table where ... )
		Integer transCount =500;

  	//4、用框架自带的分页方法
		Query query = new Query();
  	//4.1、每次查询500
		query.setSize(500);
		long pages = transCount / query.getSize();
		if (transCount % query.getSize() != 0L) {
			++pages;
		}
		for (int i = 1; i <= pages; i++) {
			query.setCurrent(i);
			List<xxxx> transList = baseMapper.selectPage(Condition.getPage(query));
			if (Func.isNotEmpty(transList)) {
				ElasticSearchUtils.addAllEsTransfer(esClient, esTransList, index);
			}
		}
		return whetherTrue;
	}


    /**
     * 分页(细节方面需要自己打磨,这里只是展示如何使用到hanlp)
     * @param transEsSearchVo
     * @return
     */
	@Override
	public EsTransMap selectEsTransPage(TransEsSearchVo transEsSearchVo) {
		StopWatch sw = new StopWatch();
		sw.start();
		int current;
		if (transEsSearchVo.getPageNo() < 1) {
			transEsSearchVo.setPageNo(1);
		}
		if (transEsSearchVo.getPageSize() < 1) {
			transEsSearchVo.setPageSize(10);
		}
		if (transEsSearchVo.getPageNo() == 1) {
			current = transEsSearchVo.getPageNo() - 1;
		} else {
			current = (transEsSearchVo.getPageNo() - 1) * transEsSearchVo.getPageSize();
		}

		//1、过滤关键字的特殊符号
		String regEx="[\n`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。, 、?]";
		Pattern p = Pattern.compile(regEx);
		Matcher m = p.matcher(transEsSearchVo.getKeyword());
		transEsSearchVo.setKeyword(m.replaceAll("").trim());

    //2、构造过滤请求
		SearchRequest.Builder builder = new SearchRequest.Builder();
		SearchRequest specificContent;

		specificContent = builder
			.index(index)
			.query(q -> q
					.bool(b -> {
						//3、查询关键字(对应字段)
						b.must( t-> t.match(v -> v.field("onlyOneBest").query(FieldValue.of(transEsSearchVo.getKeyword()))));
						return b;
					})
			)
       //4、命中关键字高亮
			.highlight(h ->h.fields("onlyOneBest",f->f.preTags("<font color='red'>").postTags("</font>")))
       //5、排序
			.sort(sort -> sort.field(f->f.field(EsConstant.SORT_FILED_TALK_CREATE_TIME).order(SortOrder.Desc)))
			//从第from开始每次查询size个(第一条数据下标为0)
			.from(current)
			.size(transEsSearchVo.getPageSize())
			.build();

		SearchResponse<TransEsContent> searchResponse;
		EsTransMap esTransMap = new EsTransMap();
		try {
			searchResponse = esClient.search(specificContent, TransEsContent.class);
			List<TransEsContent> transEsList = new ArrayList<>();
            //6、获取高亮部分
			List<Hit<TransEsContent>> hits = searchResponse.hits().hits();

			if (Func.isNotEmpty(hits)) {
				hits.forEach( h -> {
					assert h.source() != null;
      	 //7、处理高亮部分
					transEsList.add(handleContentAndTitle(h.source(),h.highlight()));
				});
			}
			sw.stop();
			esTransMap.setRecords(transEsList);
			esTransMap.setQueryTime(sw.getTotalTimeMillis());
			esTransMap.setTotal(searchResponse.hits().total().value());
		} catch (IOException e) {
			throw new ServiceException("ES服务器未启用,无法使用搜索功能");
		}
		return esTransMap;
	}

以上就是部分代码,如果想更好看实现效果、可以拉下代码到本地跑。

五、拓展内容(部署es服务器)

没有部署es服务器的可以参考下该篇文章 链接: docker-compose部署elasticsearch+hanlp分词器文章来源地址https://www.toymoban.com/news/detail-600508.html

到了这里,关于二、springboot整合elasticsearch+hanlp(7.16.2)----附完整测试用例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot开启测试用例

    1、Springboot初学者 2、小厂职场小白 我最近发现一些刚刚参加工作的测试是软件质量保证的最佳办法,也是程序交付的最终环节,测试是一门学科,关于测试的方法有很多,在理论层面有黑河测试、白盒测试,在操作指导方面有边界值测试等等相关方法。相关的文章和书籍汗

    2023年04月09日
    浏览(33)
  • SpringBoot整合RestTemplate用法讲解(完整详细)

    前言:本篇主要介绍了RestTemplate中的GET,POST,PUT,DELETE、文件上传和文件下载6大常用的功能,每一个方法和每一行代码都进行了详细的讲解,代码都是亲自测试过的,整篇博客写完以后自己也是受益匪浅,于是在这做个技术分享! 目录 一、RestTemplate简介 二、基础配置 2.1、

    2024年02月12日
    浏览(37)
  • Springboot整合mqtt最新教程,完整教程,最佳实践

    前言:   关于整合mqtt网上的教程很多,但大部分都是cv来cv去,中间的监听代码也没有讲清楚。教程也是很久之前的。所以决定自己来写一个教程。废话不多说直接开始教程。 本文只有教程,没有其他废话,如果需要请留言,后续更新下一版(包括主题消息的订阅方式改变

    2024年04月26日
    浏览(32)
  • idea生成springboot单元测试用例

    1、找到需要生成单元测试的类型,右键Go To - Test  2、选择JUnit4 和勾选需要测试的方法  3、查看自动生成的文件 4、添加测试代码 注意:@RunWith(SpringRunner.class)            @SpringBootTest 这两行让项目跑起来后运行测试用例,必须加上 方法二:通过继承applicationTest,

    2024年02月13日
    浏览(35)
  • vue3 整合 springboot 打完整jar包

    .env.developmen .env.production axios 配置 package.json vite.config.js pom.xml

    2024年02月09日
    浏览(34)
  • springboot整合Minio + vue 实现文件分片上传(完整代码)

    网上关于minio分片上传的资料不太详细,缺斤少两,所以我基于他们的代码做了一些修改,demo能够正常运行起来,但是偶尔也会发生一些小bug,不过这些都无伤大雅,最终目的是理解代码背后的逻辑和流程 流程: 前端获取生成文件MD5,发送至后台判断是否有该文件缓存,有

    2024年02月02日
    浏览(54)
  • Docker安装ElasticSearch,并进行ik和hanlp分词

    我按装的目标 : 利用ElastiSearch存储数据,ik和hanlp分词插件 对 搜索词 进行分词,在ES存储的库中找到与 搜索词 相近的内容。 安装感受 : 原始环境安装老版本的ES,BUG不断,ES相关解答博客对新手有点不友好,完整的解释不多,😭 也许是我比较菜。 ElasticSearch 是什么? 答:

    2024年02月08日
    浏览(42)
  • Elasticsearch基础,SpringBoot整合Elasticsearch

    Elasticsearch,简称为es,es是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别(大数据时代)的数据。es也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通

    2024年01月19日
    浏览(46)
  • springboot整合xxl-job项目使用(含完整代码)

    前言:在之前的文章中,我写过springboot集成quartz框架在实际项目中的应用。但是由于quartz框架的一些缺点,而xxl-job能完美克服这些缺点,也是当前市面上使用相对较多的定时任务框架。xxl-job提供了调度中心控制台页面,对所有的定时任务进行统一配置管理。在我之前的文章

    2024年02月11日
    浏览(37)
  • 【ElasticSearch系列-05】SpringBoot整合elasticSearch

    ElasticSearch系列整体栏目 内容 链接地址 【一】ElasticSearch下载和安装 https://zhenghuisheng.blog.csdn.net/article/details/129260827 【二】ElasticSearch概念和基本操作 https://blog.csdn.net/zhenghuishengq/article/details/134121631 【三】ElasticSearch的高级查询Query DSL https://blog.csdn.net/zhenghuishengq/article/details/1

    2024年02月06日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包