如何在自己的项目中引入ElasticSearch搜索引擎?

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 在大多数系统中,都需要支持搜索的功能,以简单博客系统为例,虽然说Mysql也可以通过模糊查询匹配到对应的数据,但是效率实在太低。这个时候就需要拿出分布式搜索引擎ElasticSearch了。本博客重点在于ES的集成使用,因此前端采用最简单的方式呈现,大家只需要关注后端逻辑即可。(本博客基于ES7.6.1,和ES6.X版本有较大差异)

听说微信搜索《Java鱼仔》会变更强!


本文收录于JavaStarter ,里面有我完整的Java系列文章,学习或面试都可以看看


(一)介绍


在大多数系统中,都需要支持搜索的功能,以简单博客系统为例,虽然说Mysql也可以通过模糊查询匹配到对应的数据,但是效率实在太低。这个时候就需要拿出分布式搜索引擎ElasticSearch了。本博客重点在于ES的集成使用,因此前端采用最简单的方式呈现,大家只需要关注后端逻辑即可。(本博客基于ES7.6.1,和ES6.X版本有较大差异)


(二)项目搭建


2.1 依赖引入


依赖主要就是web、es以及thymleaf相关:


<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><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version></dependency><!--thymleaf相关--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.thymeleaf</groupId><artifactId>thymeleaf-spring5</artifactId></dependency><dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-java8time</artifactId></dependency>

2.2 编写ES的配置类


编写ES的配置类,编写连接信息,之后直接通过Autowired连接即可:

@ConfigurationpublicclassElasticSearchConfig {
@BeanpublicRestHighLevelClientrestHighLevelClient(){
RestHighLevelClientclient=newRestHighLevelClient(
RestClient.builder(
newHttpHost("192.168.78.128",9200,"http")
                )
        );
returnclient;
    }
}

2.3 编写Blog实体类


编写一个类用来存储要存储的数据,我这里为了演示只在es中插入标题和作者的信息

@Data@AllArgsConstructorpublicclassBlogDO {
privateStringtitle;
privateStringauthor;
}

2.4 准备controller和service


最后新建一个IndexController和IndexService以及IndexServiceImpl,接下来会使用。最终的目录结构如下:


网络异常,图片无法展示
|


(三)数据准备


要做数据的搜索,首先第一步就是数据的导入。在真实的业务场景中,数据的导入有很多方式。一种是当新增数据时在代码逻辑中做增量的导入操作,或者是由数仓团队负责数据的增量导入。我接触到的业务中,后端程序员不需要去关注导入的操作,这个步骤是数仓团队做的。


在我们个人的博客系统中,可以在新增博客后立刻同步数据到ES,也可以先通过消息中间件发送一条消息,消费者定期去读取消息新增数据。


这里演示就直接导入了:


@ControllerpublicclassIndexController {
@AutowiredprivateIndexServiceindexService;
@ResponseBody@GetMapping("/prepareData")
publicStringprepareData(){
Stringresult=indexService.prepareData();
returnresult;
    }
}

具体的service实现如下:

@ServicepublicclassIndexServiceImplimplementsIndexService {
@AutowiredprivateRestHighLevelClientrestHighLevelClient;
@OverridepublicStringprepareData() {
List<BlogDO>blogDOS=newArrayList<>();
blogDOS.add(newBlogDO("ElasticSearch究竟是个什么东西", "Java鱼仔"));
blogDOS.add(newBlogDO("SpringBoot+SpringSecurity实现基于真实数据的授权认证", "Java鱼仔"));
blogDOS.add(newBlogDO("Dubbo两小时快速上手教程(直接代码、Spring、SpringBoot)", "Java鱼仔"));
blogDOS.add(newBlogDO("浅析五种最常用的Java加密算法", "Java鱼仔"));
blogDOS.add(newBlogDO("Java程序员需要知道的操作系统知识汇总", "Java鱼仔"));
blogDOS.add(newBlogDO("一步步教你如何在SpringBoot项目中引入支付功能", "Java鱼仔"));
blogDOS.add(newBlogDO("Zookeeper实现分布式锁的原理是什么?", "Java鱼仔"));
blogDOS.add(newBlogDO("一个成熟的Java项目如何优雅地处理异常", "Java鱼仔"));
blogDOS.add(newBlogDO("基于SpringBoot实现文件的上传下载", "Java鱼仔"));
blogDOS.add(newBlogDO("如何用Java写一个规范的http接口?", "Java鱼仔"));
BulkRequestbulkRequest=newBulkRequest();
bulkRequest.timeout("10s");
blogDOS.stream().forEach(x-> {
bulkRequest.add(newIndexRequest("blog_index").source(JSON.toJSONString(x), XContentType.JSON));
        });
BulkResponseresponses=null;
try {
responses=restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (IOExceptione) {
e.printStackTrace();
        }
returnString.valueOf(responses.status());
    }
}

我选取了自己的几篇博客文章,多执行几次接口,保证ES中有几十条数据供测试使用即可。

网络异常,图片无法展示
|

(四)博客搜索


接下来就是搜索的过程了,搜索的逻辑其实比较简单,具体的代码就按照上一篇博客中的方式来编写,在真实业务场景中,每个公司可能会有自己的封装搜索方法:

IndexController中增加一个方法:


@GetMapping("/search")
publicStringsearch(@RequestParam("keywords")Stringkeywords, @RequestParam("pageNum")StringpageNum, @RequestParam("pageSize")StringpageSize, Modelmodel){
List<Map<String,Object>>list=indexService.searchByKeywords(keywords,pageNum,pageSize);
model.addAttribute("datas",list);
return"search";
}

具体实现类中增加方法:

@OverridepublicList<Map<String, Object>>searchByKeywords(Stringkeywords, StringpageNum, StringpageSize) {
returnthis.searchData(keywords,Integer.parseInt(pageNum),Integer.parseInt(pageSize));
}
publicList<Map<String,Object>>searchData(Stringkeywords, intpageNum, intpageSize){
if (pageNum<1){
pageNum=1;
    }
//生成搜索对象SearchRequestrequest=newSearchRequest("blog_index");
SearchSourceBuildersearchSourceBuilder=newSearchSourceBuilder();
//设置分页参数searchSourceBuilder.from(pageNum);
searchSourceBuilder.size(pageSize);
//设置搜索的字段MatchQueryBuildermatchQueryBuilder=QueryBuilders.matchQuery("title", keywords);
searchSourceBuilder.query(matchQueryBuilder);
searchSourceBuilder.timeout(newTimeValue(10, TimeUnit.SECONDS));
request.source(searchSourceBuilder);
SearchResponsesearch=null;
try {
search=restHighLevelClient.search(request, RequestOptions.DEFAULT);
    } catch (IOExceptione) {
e.printStackTrace();
    }
//将结果返回List<Map<String,Object>>result=newArrayList();
SearchHit[] hits=search.getHits().getHits();
for (SearchHitsearchHit:hits){
result.add(searchHit.getSourceAsMap());
    }
returnresult;
}

简单写一个前端页面

<!DOCTYPE html><htmlxmlns:th="http://www.thymeleaf.org"><!--引入thymeleaf--><head><metacharset="UTF-8"><title>Title</title></head><body><div><divth:each="datas:${datas}"><spanth:text="${datas.author}"/><spanth:utext="${datas.title}"/><hr/></div></div></body></html>

跑起来看一下,访问


http://localhost:8080/search?keywords=Java&pageNum=1&pageSize=10

在链接中,我关键词填了Java,pageNum是1,每页展示10行,可以看到和Java相关的数据就被查出来了。


网络异常,图片无法展示
|


(五)实现高亮查询


在百度搜索Java时,可以看到查询出来的Java被高亮显示了,之前在讲ES语法的时候,我们也知道了ES支持高亮查询,下面就通过代码来实现。


网络异常,图片无法展示
|


稍微修改一下搜索的代码,增加高亮配置,在返回值中用高亮字符串替换原来的字符串。


publicList<Map<String,Object>>searchHighLightData(Stringkeywords, intpageNum, intpageSize){
if (pageNum<1){
pageNum=1;
    }
SearchRequestrequest=newSearchRequest("blog_index");
SearchSourceBuildersearchSourceBuilder=newSearchSourceBuilder();
searchSourceBuilder.from(pageNum);
searchSourceBuilder.size(pageSize);
//高亮构造器HighlightBuilderhighlightBuilder=newHighlightBuilder();
//高亮查询字段highlightBuilder.field("title");
//是否将所有匹配到的字段高亮显示,false表示只显示一个highlightBuilder.requireFieldMatch(false);
//高亮的标签highlightBuilder.preTags("<span style='color:red'>");
highlightBuilder.postTags("</span>");
searchSourceBuilder.highlighter(highlightBuilder);
MatchQueryBuildermatchQueryBuilder=QueryBuilders.matchQuery("title", keywords);
searchSourceBuilder.query(matchQueryBuilder);
searchSourceBuilder.timeout(newTimeValue(10, TimeUnit.SECONDS));
request.source(searchSourceBuilder);
SearchResponsesearch=null;
try {
search=restHighLevelClient.search(request, RequestOptions.DEFAULT);
    } catch (IOExceptione) {
e.printStackTrace();
    }
List<Map<String,Object>>result=newArrayList();
SearchHit[] hits=search.getHits().getHits();
//遍历结果,将高亮返回值title替换到原来的title中for (SearchHitsearchHit:hits){
Map<String, Object>sourceAsMap=searchHit.getSourceAsMap();
Map<String, HighlightField>highlightFields=searchHit.getHighlightFields();
HighlightFieldtitle=highlightFields.get("title");
if (title!=null){
StringBuilderhighLightTitle=newStringBuilder();
Text[] texts=title.fragments();
for(Texttext:texts){
highLightTitle.append(text);
            }
sourceAsMap.put("title",highLightTitle);
        }
result.add(sourceAsMap);
    }
returnresult;
}

继续访问


http://localhost:8080/search?keywords=Java&pageNum=1&pageSize=10,


通过断点可以看到,搜索的关键词已经被我们设置的span标签包住了。


网络异常,图片无法展示
|

在前端thymeaf中,我是用了th:utext,这个标签可以将Html解析,最终的高亮显示如下:


网络异常,图片无法展示
|


(六)总结


ES的应用到这里就结束了,ES可以很方便地嵌入到真实的项目中,对于应用来讲,了解到这一步已经足够,对于想要提高的人来说,还远远不够。作为最流行的分布式搜索引擎,ES还有许多值得学的地方,任重而道远。我是鱼仔,我们下期再见!



相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
3月前
|
自然语言处理 搜索推荐 数据库
高性能分布式搜索引擎Elasticsearch详解
高性能分布式搜索引擎Elasticsearch详解
99 4
高性能分布式搜索引擎Elasticsearch详解
|
2月前
|
自然语言处理 搜索推荐 关系型数据库
elasticsearch学习六:学习 全文搜索引擎 elasticsearch的语法,使用kibana进行模拟测试(持续更新学习)
这篇文章是关于Elasticsearch全文搜索引擎的学习指南,涵盖了基本概念、命令风格、索引操作、分词器使用,以及数据的增加、修改、删除和查询等操作。
37 0
elasticsearch学习六:学习 全文搜索引擎 elasticsearch的语法,使用kibana进行模拟测试(持续更新学习)
|
3月前
|
网络协议 Java Maven
多模块项目使用ElasticSearch报错
多模块项目使用ElasticSearch报错
67 6
|
2月前
|
开发框架 监控 搜索推荐
GoFly快速开发框架集成ZincSearch全文搜索引擎 - Elasticsearch轻量级替代为ZincSearch全文搜索引擎
本文介绍了在项目开发中使用ZincSearch作为全文搜索引擎的优势,包括其轻量级、易于安装和使用、资源占用低等特点,以及如何在GoFly快速开发框架中集成和使用ZincSearch,提供了详细的开发文档和实例代码,帮助开发者高效地实现搜索功能。
203 0
|
2月前
|
自然语言处理 搜索推荐 Java
SpringBoot 搜索引擎 海量数据 Elasticsearch-7 es上手指南 毫秒级查询 包括 版本选型、操作内容、结果截图(一)
SpringBoot 搜索引擎 海量数据 Elasticsearch-7 es上手指南 毫秒级查询 包括 版本选型、操作内容、结果截图
64 0
|
2月前
|
存储 自然语言处理 搜索推荐
SpringBoot 搜索引擎 海量数据 Elasticsearch-7 es上手指南 毫秒级查询 包括 版本选型、操作内容、结果截图(二)
SpringBoot 搜索引擎 海量数据 Elasticsearch-7 es上手指南 毫秒级查询 包括 版本选型、操作内容、结果截图(二)
45 0
|
3月前
|
JSON 自然语言处理 算法
ElasticSearch基础2——DSL查询文档,黑马旅游项目查询功能
DSL查询文档、RestClient查询文档、全文检索查询、精准查询、复合查询、地理坐标查询、分页、排序、高亮、黑马旅游案例
|
7月前
|
存储 自然语言处理 搜索推荐
分布式搜索引擎ElasticSearch
Elasticsearch是一款强大的开源搜索引擎,用于快速搜索和数据分析。它在GitHub、电商搜索、百度搜索等场景中广泛应用。Elasticsearch是ELK(Elasticsearch、Logstash、Kibana)技术栈的核心,用于存储、搜索和分析数据。它基于Apache Lucene构建,提供分布式搜索能力。相比其他搜索引擎,如Solr,Elasticsearch更受欢迎。倒排索引是其高效搜索的关键,通过将词条与文档ID关联,实现快速模糊搜索,避免全表扫描。
289 13
|
6月前
|
XML 搜索推荐 Java
Elasticsearch集成到Spring Boot项目
将Elasticsearch集成到Spring Boot项目中,可以方便地实现数据的搜索、分析等功能。
273 2
|
6月前
|
存储 搜索推荐 关系型数据库
【搜索引擎】elastic search核心概念
【搜索引擎】elastic search核心概念
58 0