ElasticSearch 7.8.1教程(from b站狂神)+JD商城仿站

tech2022-07-06  217

ElasticSearch

安装elasticsearch

官网:elastic.co

https://www.elastic.co/cn/downloads/elasticsearch

官网下载巨慢,翻墙下载

目录

启动,访问9200:

访问9200接口:

安装elasticsearch-head:

git clone git://github.com/mobz/elasticsearch-head.git

cd elasticsearch-head

npm install

npm run start

open http://localhost:9100/

存在一个9200和9100的跨域问题!

点击链接,报跨域的错!

修改elasticsearch中config下的yaml配置文件,修改:

重启,连接成功:

把索引当做一个数据库!可以建立索引(库),文档(库中的数据!)

后面所有的查询,查询功能在Kibana中做!

了解ELK

安装Kibana

好处:ELK基本上都是拆箱即用

启动测试:点bin下的kibana

默认的kibana端口为5601

PS:注意elasticsearch和kibana的版本必须一致 否则出错!

开发工具:(Post curl head 谷歌浏览器插件测试)

汉化,修改kibana yaml中配置 重启,

ES核心概念

索引字段类型(mapping)文档(documents)

概述:

集群、节点、索引、类型、文档、分片、映射是什么?

elasticsearch是面向文档,关系型数据库和elasticsearch 客观的对比如下,一切都是JSON!

类型示例:

IK分词器

安装https://github.com/medcl/elasticsearch-analysis-ik/releases

放在elasticsearch的plugin(插件)下

重启观察ES

关于elasticsearch中的命令 如elasticsearch-plugin:

命令行输入:

elasticsearch-plugin list

在kibana中测分词器:

我们输入 超级喜欢狂神或java

发现问题:狂神说被拆开了!

这种自己需要的词,需要自己加到我们的分词器字典中!

向ik分词器增加自己的配置

重启es、kibana

再次测试一下狂神说,看下效果!ik_max_word最细粒度划分

以后自定义dic、导入即可!

索引引擎里面最重要的首先就是分词

Rest风格说明

一种软件架构风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制!

基础测试

创建一个索引!也是在kibana终端中试用版PUT命令 PUT /test1/type1/1{ "name": "狂神说", "age": "3" }

完成了自动增加索引!数据也成功的添加了,这就是可以当做数据库看的原因。。

那么name字段用不用指定类型呢?毕竟我们关系型数据库 是需要指定类型的啊!

字符串类型 text、keyword数值类型 long、integer、short、byte、double、float、scaled float日期类型datete布尔值类型boolean二进制类型binary等等。。。

指定字段的类型——创建规则

GET命令得到库的信息:

查看默认的信息

通过命令get _cat/可以获得es当前的很多信息!

修改 提交还是使用PUT即可!然后覆盖!最新办法

曾经的办法:

现在的方法 使用POST:

删除索引——DELETE

通过DELETE命令实现删除、根据你的请求来判断是删除索引还是删除文档记录!

使用RESTFUL风格是我们ES推荐大家使用的!

关于文档的基本操作(重点):

基本操作:

添加数据

更新数据,将小明改成小红

PUT更新数据

version代表被改变的次数

Post,_update自由度更高,PUT必须一次性修改一个个体的全部内容,但是Post可以选择部分修改!

这个和PUT无异,要在后加_update

简单的搜索:

GET Kuangshen/user/_search?q=name:狂神说

简单的条件查询,可以根据默认的映射规则,产生基本的查询!

复杂操作搜索 select(排序,分页,高亮,模糊查询,精准查询)

GET kuangshen/_search

输出:

{ "took" : 0, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 5, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "kuangshen", "_type" : "user", "_id" : "1", "_score" : 1.0, "_source" : { "name" : "狂神说", "age" : 23, "desc" : "一顿操作猛如虎,一看工资2500", "tags" : [ "技术宅", "温暖", "直男" ] } }, { "_index" : "kuangshen", "_type" : "user", "_id" : "2", "_score" : 1.0, "_source" : { "name" : "张三", "age" : 3, "desc" : "法外狂徒", "tags" : [ "交友", "旅游", "渣男" ] } }, { "_index" : "kuangshen", "_type" : "user", "_id" : "3", "_score" : 1.0, "_source" : { "name" : "李四", "age" : 30, "desc" : "不知道如何形容", "tags" : [ "篮球", "IT", "型男" ] } }, { "_index" : "kuangshen", "_type" : "user", "_id" : "4", "_score" : 1.0, "_source" : { "name" : "王五", "age" : 32, "desc" : "就是一个屌丝", "tags" : [ "羽毛球", "钢琴", "渣男" ] } }, { "_index" : "kuangshen", "_type" : "user", "_id" : "5", "_score" : 1.0, "_source" : { "name" : "狂神说Java8", "age" : 34, "desc" : "就是一个大帅哥", "tags" : [ "围棋", "小提琴", "暖男" ] } } ] } } GET kuangshen/_search { "query": { "match": { "name": "狂神" } } }

输出:

{ "took" : 9, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 2, "relation" : "eq" }, "max_score" : 1.9034984, "hits" : [ { "_index" : "kuangshen", "_type" : "user", "_id" : "1", "_score" : 1.9034984, "_source" : { "name" : "狂神说", "age" : 23, "desc" : "一顿操作猛如虎,一看工资2500", "tags" : [ "技术宅", "温暖", "直男" ] } }, { "_index" : "kuangshen", "_type" : "user", "_id" : "5", "_score" : 1.6534033, "_source" : { "name" : "狂神说Java8", "age" : 34, "desc" : "就是一个大帅哥", "tags" : [ "围棋", "小提琴", "暖男" ] } } ] } }

hit: 索引和文档信息

查询的结果总数

然后就是查询出来的具体文档

数据中的东西都可以遍历出来

分数:通过score判断谁更加符合结果

指定字段查询:

GET kuangshen/_search { "query": { "match": { "name": "狂神" } }, "_source": ["name","desc"] }

之后使用java操作es,所有的方法和对象就是这里面的key!

复杂操作:

排序

order中的desc降序、asc升序;按照age

GET kuangshen/_search { "query": { "match": { "name": "狂神" } } ,"sort": [ { "age": { "order": "desc" } } ] }

分页

GET kuangshen/_search { "query": { "match": { "name": "狂神" } } ,"sort": [ { "age": { "order": "desc" } } ], "from": 0, "size": 1 }

From:从第几个数据开始,返回多少条数据(单页面的数据)

数据下标还是从0开始的,和学的所有数据结构是一样的

/search/{current}/{pagesize}

布尔值查询

通过布尔值进行更加精确的查询:多条件精确查询

must命令(相当于mysql的and),即所有条件要同时符合;如果将must改为should(相当于or),则只要满足其一即可;

类似的 must not 查询不是。。

GET kuangshen/user/_search { "query": { "bool": { "must": [ { "match": { "name": "狂神说" } }, { "match": { "age": 23 } } ] } } }

过滤器(filter)

筛选age范围

GET kuangshen/user/_search { "query": { "bool": { "must": [ { "match": { "name": "狂神" } } ], "filter": [ { "range": { "age": { "gte": 10, "lte": 40 } } } ] } } } gt 大于gte 大于等于lt 小于lte 小于等于

匹配多个条件

匹配出tags里面只要包含有男的,同时按照上到下分值高到低排列

GET kuangshen/user/_search { "query": { "match": { "tags": "男 技术" } } }

多个条件使用空格隔开

只要满足其中一个结果即可以被查出

这个时候可以通过分值基本的判断

精确查询

term查询是直接通过待排索引指定的词条进行精确的查找的!

关于分词:

term,直接查询精确的

match:会使用分词器解析!(先分析文档,然后再通过分析的文档进行查询!)

两个字段类型text keyword

#新建db PUT testdb { "mappings": { "properties": { "name":{ "type": "text" }, "desc":{ "type": "keyword" } } } } #插入两条数据 PUT testdb/_doc/1 { "name": "狂神说Java name", "desc": "狂神说Java name" } PUT testdb/_doc/2 { "name": "狂神说Java name", "desc": "狂神说Java name2" }

GET _analyze { "analyzer": "keyword", "text": "狂神说Java name" } GET _analyze { "analyzer": "standard", "text": "狂神说Java name" }

由于desc的type是keyword,当做整体去搜索了

总结:keyword字段类型不会被分词器解析!

多个值匹配的精确查询

精确查询多个值

高亮查询

GET kuangshen/user/_search { "query": { "match": { "name": "狂神说" } }, "highlight": { "pre_tags": "<p class='key' style='color:red'>", "post_tags": "</p>", "fields": { "name": {} } } }

默认是<em>标签

也可以是自定义标签:设置pre_tags、post_tags

匹配按照条件匹配精确匹配区间范围匹配匹配字段过滤多条件查询高亮查询

集成Springboot

文档

https://www.elastic.co/guide/index.html

找原生依赖

初始化

配置

新建一个empty project ,再创建普通模块

创建Springboot 模块:

勾上依赖:

由于刚刚建的空project,故要陪JDK环境

问题:一定要保证我们的导入依赖和我们的es版本一致

默认的导入依赖和我们本地的版本不一致!

可以自定义版本依赖,保证一致

新建config、ElasticSearchConfig.java`

package com.kuang.config; import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; //狂神的spring两步骤: //1.找对象 //2.放到spring中用 @Configuration public class ElasticSearchConfig { // @Bean public RestHighLevelClient restHighLevelClient(){ RestHighLevelClient client = new RestHighLevelClient( RestClient.builder( new HttpHost("localhost", 9200, "http"), new HttpHost("localhost", 9201, "http"))); return client; } }

源码

具体测试es api:

package com.kuang; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.client.indices.CreateIndexRequest; import org.elasticsearch.client.indices.CreateIndexResponse; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; import java.io.IOException; //es 高级客户端测试API @SpringBootTest class KuangshenEsApiApplicationTests { //面向对象来操作 @Autowired @Qualifier("restHighLevelClient") //这里的qualifier用来指定下面的client为原始的restHighLevelClient private RestHighLevelClient client; // 测试索引的创建 Request @Test void testCreateIndex() throws IOException { // 1.创建索引请求 相当于kibana中的PUT CreateIndexRequest request = new CreateIndexRequest("kuang_index"); // 2.执行创建请求IndicesClient ,请求后获得响应 CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT); System.out.println(createIndexResponse); } //测试获取索引 判断是否存在某索引 @Test void testExistIndex() throws IOException { GetIndexRequest request = new GetIndexRequest("kuang_index"); boolean exists = client.indices().exists(request, RequestOptions.DEFAULT); System.out.println(exists); } // 测试删除索引 @Test void testDeleteIndex() throws IOException { DeleteIndexRequest request = new DeleteIndexRequest("testdb2"); AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT); System.out.println(delete.isAcknowledged()); } }

本来应该是private RestHighLevelClient restHighLevelClient;这里为了简便,所以用Qualifier来限定client为restHighLevelClient;

创建索引判断索引是否存在删除索引创建文档crud文档

创建文档

新建一个pojo,放入User.java

package com.kuang.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.stereotype.Component; @Data @AllArgsConstructor @NoArgsConstructor @Component public class User { private String name; private int age; }

由于要将我们的数据放入请求 json,故在pom中导入阿里巴巴fastjson

这里是将对象编写为Json,再放入es的request中

编写test类:

@Test void testAddDocument(){ //创建对象 User user = new User("狂神说",3); IndexRequest request = new IndexRequest("kuang_index"); // 规则 put /kuang_index/_doc/1 request.id("1"); request.timeout(TimeValue.timeValueSeconds(1)); request.timeout("1s"); //将我们的数据放入请求 json request.source(JSON.toJSONString(user), XContentType.JSON); //客户端发送请求 IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT); System.out.println(indexResponse.toString());// System.out.println(indexResponse.status());//对应我们命令返回的状态 }

获取文档

//获取文档的信息 @Test void testGetDocument() throws IOException { GetRequest getRequest = new GetRequest("kuang_index", "1"); GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT); System.out.println(getResponse.getSourceAsString());//打印文档的内容 System.out.println(getResponse);//返回的全部内容和命令是一样的 }

更新文档信息

//更新文档的信息 @Test void testUpdateDocument() throws IOException { UpdateRequest updateRequest = new UpdateRequest("kuang_index","1"); updateRequest.timeout("1s"); User user = new User("狂神说Java", 18); updateRequest.doc(JSON.toJSONString(user),XContentType.JSON); UpdateResponse updateResponse = client.update(updateRequest, RequestOptions.DEFAULT); System.out.println(updateResponse.status()); }

删除文档信息

//删除文档记录 @Test void testDeleteRequest() throws IOException { DeleteRequest request = new DeleteRequest("kuang_index", "1"); request.timeout("1s"); DeleteResponse deleteResponse = client.delete(request, RequestOptions.DEFAULT); System.out.println(deleteResponse.status()); }

批量插入

//批量插入数据 @Test void testBulkRequest() throws IOException{ BulkRequest bulkRequest = new BulkRequest(); bulkRequest.timeout("10s");//数据量大的时候,秒数可以增加 ArrayList<User> userList = new ArrayList<>(); userList.add(new User("psz",11)); userList.add(new User("psz2",12)); userList.add(new User("psz3",13)); userList.add(new User("psz4",14)); userList.add(new User("psz5",15)); //批处理请求 for (int i = 0; i < userList.size(); i++) { bulkRequest.add( new IndexRequest("kuang_index") .id(""+(i+1)) .source(JSON.toJSONString(userList.get(i)),XContentType.JSON)); } //请求+获得响应 BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT); System.out.println(bulkResponse.hasFailures());//返回false:成功 }

查询

小技巧:

一般企业中,会把index名存在utils里面的ESconst.java文件中:

package com.kuang.utils; public class ESconst { public static final String ES_INDEX = "kuang_index"; } // 查询 // SearchRequest 搜索请求 // SearchSourceBuilder 条件构造 // HighlightBuilder 构建高亮 // TermQueryBuilder 精确查询 // MatchAllQueryBuilder // xxx QueryBuilder 对应我们刚才看到的命令 @Test void testSearch() throws IOException { SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX); // 构建搜索的条件 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); // 查询条件,可以使用querybuilders工具类实现 // QueryBuilders.termQuery精确匹配 // QueryBuilders.matchAllQuery匹配所有 TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "qinjiang1"); // MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery(); sourceBuilder.query(termQueryBuilder); //分页 // sourceBuilder.from(); // sourceBuilder.size(); // 设置查询的时间 希望在60s内查出 sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS)); searchRequest.source(sourceBuilder); SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); System.out.println(JSON.toJSONString(searchResponse.getHits())); System.out.println("--------------------------------------"); for (SearchHit documentFields : searchResponse.getHits().getHits()) { System.out.println(documentFields.getSourceAsMap()); } }

JD商城实战

新建Springboot initializr项目

导入es、fastjson等pom下的依赖

爬虫

数据问题?数据库获取,消息队列中获取,都可以成为数据源,或者爬虫

爬取数据:(获取请求返回的页面信息,筛选出我们想要的数据就可以了)

jsoup包:用于解析网页,不能爬电影

新建一个utils包放网页解析的工具类

本质的请求是:

https://search.jd.com/Search?keyword=java

所有在Js中的方法这里都可以使用

package com.kun.utils; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; public class HtmlParseUtil { public static void main(String[] args) throws IOException { // 获取请求 https://search.jd.com/Search?keyword=java String url = "https://search.jd.com/Search?keyword=java"; //解析网页 Jsoup返回的就是浏览器Document对象 Document document = Jsoup.parse(new URL(url), 30000); Element element = document.getElementById("J_goodsList"); System.out.println(element.html()); //获取所有的li元素/标签 Elements elements = element.getElementsByTag("li"); //获取元素中的内容 eq获取当前第一个元素,获取src属性 for (Element el : elements) { //关于这种图片特别多的网站,所有的图片都是延迟加载的! String img = el.getElementsByTag("img").eq(0).attr("src"); String price = el.getElementsByClass("p-price").eq(0).text(); String title = el.getElementsByClass("p-name").eq(0).text(); System.out.println("==============================="); System.out.println(img); System.out.println(price); System.out.println(title); } }

输出结果

注意:

在图片较多的网站中,图片往往是延迟加载的,注意看图片的属性:

将获取到的元素 封装成对象,新建pojo,Content.java

package com.kun.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor public class Content { private String title; private String img; private String price; //可以自己添加属性 }

再次封装工具类:

package com.kun.utils; import com.kun.pojo.Content; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; @Component //丢进Springboot中 public class HtmlParseUtil { public static void main(String[] args) throws Exception { new HtmlParseUtil().parseJD("java").forEach(System.out::println); } public List<Content> parseJD(String keywords) throws Exception { // 获取请求 https://search.jd.com/Search?keyword=java String url = "https://search.jd.com/Search?keyword=" + keywords; //解析网页 Jsoup返回的就是浏览器Document对象 Document document = Jsoup.parse(new URL(url), 30000); //所有你在js中可以使用的方法,这里都可以使用 Element element = document.getElementById("J_goodsList"); // System.out.println(element.html()); //获取所有的li元素/标签 Elements elements = element.getElementsByTag("li"); //封装对象 ArrayList<Content> goodsList = new ArrayList<Content>(); //获取元素中的内容 eq获取当前第一个元素,获取src属性 for (Element el : elements) { //关于这种图片特别多的网站,所有的图片都是延迟加载的! String img = el.getElementsByTag("img").eq(0).attr("src"); String price = el.getElementsByClass("p-price").eq(0).text(); String title = el.getElementsByClass("p-name").eq(0).text(); Content content = new Content(); content.setImg(img); content.setPrice(price); content.setTitle(title); goodsList.add(content); // System.out.println("==============================="); // System.out.println(img); // System.out.println(price); // System.out.println(title); } return goodsList; } }

编写业务层service:

package com.kun.service; import com.alibaba.fastjson.JSON; import com.kun.pojo.Content; import com.kun.utils.HtmlParseUtil; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.xcontent.XContentType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Service; import java.util.List; //业务编写 @Service public class ContentService { @Autowired private RestHighLevelClient restHighLevelClient; //1.解析数据放入es索引中 public Boolean parseContent(String keywords) throws Exception { List<Content> contents = new HtmlParseUtil().parseJD(keywords); //把查询的数据放入我们的es中 BulkRequest bulkRequest = new BulkRequest(); bulkRequest.timeout("2m"); //批量插入 for (int i = 0; i < contents.size(); i++) { bulkRequest.add( new IndexRequest("jd_goods") .source(JSON.toJSONString(contents.get(i)), XContentType.JSON)); } BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT); return !bulk.hasFailures(); } }

测试:由于这个文件中又Autowire,所以就算建了主函数psvm,也不能测,必须启动服务;

直接用controller来测:

package com.kun.controller; import com.kun.service.ContentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController public class ContentController { @Autowired private ContentService contentService; @GetMapping("/parse/{keyword}") public Boolean parse(@PathVariable("keyword") String keywords) throws Exception { return contentService.parseContent(keywords); } }

再在业务层中实现搜索功能:

// 2. 获取数据实现搜索功能 public List<Map<String,Object>> searchPage(String keyword,int pageNo,int pageSize) throws IOException { if(pageNo<=1){ pageNo = 1; } //条件搜索 SearchRequest searchRequest = new SearchRequest("jd_goods"); SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); //分页 sourceBuilder.from(pageNo); sourceBuilder.size(pageSize); //精准匹配 TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword); sourceBuilder.query(termQueryBuilder); sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS)); //执行搜索 searchRequest.source(sourceBuilder); SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); //解析结果 ArrayList<Map<String,Object>> list = new ArrayList<>(); for (SearchHit documentFields : searchResponse.getHits().getHits()) { list.add(documentFields.getSourceAsMap()); } return list; }

用Controller来测:

@GetMapping("/parse/{keyword}/{pageNo}/{pageSize}") public List<Map<String,Object>> search(@PathVariable("keyword") String keyword, @PathVariable("pageNo")int pageNo, @PathVariable("pageSize") int pageSize) throws IOException { return contentService.searchPage(keyword, pageNo, pageSize); }

前后端分离

先在一个任意包下npm install vue生成vue文件,将内部一些js包导入Springboot项目中;axios.min.js;vue.min.js

在前端每个商品中得到result值

搜索高亮

修改业务层ContentService.java

//3. 新增高亮功能 public List<Map<String,Object>> searchPageHighlightBuilder(String keyword,int pageNo,int pageSize) throws Exception { parseContent(keyword); if (pageNo <= 1) { pageNo = 1; } //条件搜索 SearchRequest searchRequest = new SearchRequest("jd_goods"); SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); //分页 sourceBuilder.from(pageNo); sourceBuilder.size(pageSize); //精准匹配 // TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword); // sourceBuilder.query(termQueryBuilder); // sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS)); //match匹配 可以支持中文搜索 MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder("title", keyword); sourceBuilder.query(matchQueryBuilder); sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));//超时 //高亮 HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.field("title"); //高亮的字段 highlightBuilder.requireFieldMatch(false);//如果一句里面有多个关键词高亮,则只显示第一个 highlightBuilder.preTags("<span style='color:red'>"); highlightBuilder.postTags("</span>"); sourceBuilder.highlighter(highlightBuilder); //执行搜索 searchRequest.source(sourceBuilder); SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); //解析结果 ArrayList<Map<String, Object>> list = new ArrayList<>(); for (SearchHit hit : searchResponse.getHits().getHits()) { Map<String, HighlightField> highlightFields = hit.getHighlightFields(); //获取到高亮字段 HighlightField title = highlightFields.get("title"); Map<String, Object> sourceAsMap = hit.getSourceAsMap(); //原来的结果!要在结果里面将高亮置换一下 //解析高亮的字段 将原来的字段换为我们高亮的字段即可 if (title != null) { Text[] fragments = title.fragments(); String n_title = ""; for (Text text : fragments) { n_title += text; } sourceAsMap.put("title", n_title);//高亮字段替换掉原来的内容即可! } list.add(sourceAsMap); } return list; }

效果

最新回复(0)