侧边栏壁纸
博主头像
这就是之谦博主等级

我们的征途是星辰大海

  • 累计撰写 182 篇文章
  • 累计创建 3 个标签
  • 累计收到 16 条评论
标签搜索

目 录CONTENT

文章目录

Elasticsearch

这就是之谦
2021-08-31 / 0 评论 / 0 点赞 / 857 阅读 / 24,784 字
温馨提示:
本文最后更新于 2021-11-14,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

Elasticsearch

版本7.8.0

项目源码

链接:https://pan.baidu.com/s/1TY1KzuVa9sA_8n57BkdA-Q
提取码:j0kh

1、Elasticsearch安装

1、下载Elasticsearch,解压

image-20210830152504799

bin:启动文件
config:配置文件
	log4j2.properties:日志配置文件
	jvm.options:java虚拟机的配置
	elasticsearch.yml:es的配置文件 默认9200端口 跨域
data:索引数据目录
lib:相关类库Jar包
logs:日志目录
modules:功能模块
plugins:插件

2、双击ElasticSearch下的bin目录中的elasticsearch.bat启动,控制台显示的日志(等待启动完
毕!):

3、然后在浏览器访问:http://localhost:9200 得到如下信息,说明安装成功了:

image-20210830160229249

注意:需要NodeJS的环境,我们讲解大前端进阶已经安装过了,没安装的需要安装!
Head是elasticsearch的集群管理工具,可以用于数据的浏览查询!被托管在github上面!
地址: https://github.com/mobz/elasticsearch-head/

1、下载 elasticsearch-head-master.zip
2、解压之后安装依赖!

npm install
npm run start

3、连接测试http://localhost:9100/发现,存在跨域问题:配置es,elasticsearch.yml

# 跨域配置:
http.cors.enabled: true
http.cors.allow-origin: "*"

4、启动ElasticSearch,使用head工具进行连接测试!http://localhost:9100/

image-20210830160601645

2、Kibana安装

Kibana是一个针对Elasticsearch的开源分析及可视化平台,用来搜索、查看交互存储在Elasticsearch索
引中的数据。使用Kibana,可以通过各种图表进行高级数据分析及展示。Kibana让海量数据更容易理
解。它操作简单,基于浏览器的用户界面可以快速创建仪表板(dashboard)实时显示Elasticsearch查
询动态。设置Kibana非常简单。无需编码或者额外的基础架构,几分钟内就可以完成Kibana安装并启动
Elasticsearch索引监测。
官网:https://www.elastic.co/cn/kibana
1、下载Kibana https://www.elastic.co/cn/downloads/kibana (注意版本对应关系)

2、将压缩包解压即可(需要一些时间)!

3、安装依赖【好像不需要】

npm install

3、然后进入到bin目录下,启动服务就可以了(需要等待启动完成),ELK基本上都是拆箱即用的

4、汉化Kibana:修改Kibana为中文config目录下的kibana.yml文件,添加

i18n.locale: "zh-CN"

访问http://localhost:5601/

image-20210830203838184

3、ES核心概念

1、索引

2、字段类型(mapping)

3、文档(documents)

elasticsearch是面向文档,关系行数据库 和 elasticsearch 客观的对比!

image-20210831085914598

物理设计:
elasticsearch 在后台把每个索引划分成多个分片,每分分片可以在集群中的不同服务器间迁移

倒排索引:

elasticsearch使用的是一种称为倒排索引的结构,采用Lucene倒排索作为底层。这种结构适用于快速的
全文搜索, 一个索引由文档中所有不重复的列表构成,对于每一个词,都有一个包含它的文档列表。

4、IK分词器

1、下载ik分词器的包,Github地址:https://github.com/medcl/elasticsearch-analysis-ik/ (版本要对
应)

2、下载后解压,并将目录拷贝到ElasticSearch根目录下的 plugins 目录中。

3、重新启动 ElasticSearch 服务,在启动过程中,你可以看到正在加载"analysis-ik"插件的提示信息,
服务启动后,在命令行运行 elasticsearch-plugin list命令,确认 ik 插件安装成功。

image-20210831091824819

4、使用kibana测试

1、查看不同的分词器效果

ik_smart最少切分

ik_max_word最细粒度划分

ik_smart最少切分

image-20210831092344166

ik_max_word最细粒度划分,穷尽词库

image-20210831092411570

2、问题:我们自己的词未被识别,被拆分了

我们测试发现“岩弟弟”被拆分了,我们不想“岩弟弟”被拆分,岩弟弟是一个词,那我们需要配置分词器

image-20210831093050437

配置分词器识别自己需要的词为一个词,而不拆分,修改D:\es\elasticsearch-7.8.0\plugins\elasticsearch-analysis-ik-7.8.0\config\IKAnalyzer.cfg.xml

在config目录下新建lxw.dic,输入岩弟弟

image-20210831093251103

IKAnalyzer.cfg.xml中添加lxw.dic

image-20210831093337873

重启ES,重新测试“岩弟弟”,发现岩弟弟变成了一个完整的词

image-20210831093642203

5、Rest风格

5.1、Rest风格

image-20210831093919225

1、在控制台输入以下命令:

// 命令解释
// PUT 创建命令 test1 索引 type1 类型 1 id
PUT /test1/type1/1
{
"name":"岩弟弟", // 属性
"age":3 // 属性
}

返回结果 (是以REST ful 风格返回的 ):

#! Deprecation: [types removal] Specifying types in document index requests is deprecated, use the typeless endpoints instead (/{index}/_doc/{id}, /{index}/_doc, or /{index}/_create/{id}).
// 警告信息:不支持在文档索引请求中指定类型
// 而是使用无类型的端点(/{index}/_doc/{id}, /{index}/_doc,或/{index}/_create/{id})。
{
  "_index" : "test1", 	//索引
  "_type" : "type1",	//类型
  "_id" : "1",			//id
  "_version" : 1,		//版本
  "result" : "created",	//操作类型
  "_shards" : {			//分片信息
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

2、查看

image-20210831094800869

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

  • 字符串类型
    text 、 keyword
  • 数值类型
    long, integer, short, byte, double, float, half_float, scaled_float
  • 日期类型
    date
  • te布尔值类型
    boolean
  • 二进制类型
    binary
  • 等等......

4、指定字段类型

PUT /test2
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "age": {
        "type": "long"
      },
      "birthday":{
        "type": "date"
      }
    }
  }
}

image-20210831095944328

查看GET命令

image-20210831100027193

5、查看默认的信息

控制台输入

image-20210831100212989

head查看

image-20210831100248565

GET查看,发现自动匹配类型

image-20210831100333054

拓展:通过GET _cat/indices?v等命令可以获取默认信息

image-20210831100739645

5.2、索引【增删改查Rest风格简单使用】

PUT增

PUT /test3/_doc/1
{
  "name": "岩弟弟",
  "age": 15,
  "borthday": "2000-03-03"
}

PUT改(有数据的情况下,版本号+1)

PUT /test3/_doc/1
{
  "name": "岩鸽鸽",
  "age": 15,
  "borthday": "2000-03-03"
}

POST进行修改

POST /test3/_doc/1/_update
{
  "doc":{
    "name": "张三"
  }
}

删除索引

DELETE test1

GET查

GET test3/_doc/1

6、文档的操作【增删改查】【重点】

6.1、增

PUT /lxw/user/1
{
  "name": "岩弟弟",
  "age": 23,
  "desc": "牛牛牛",
  "tags": ["k1","k2","k3"]
}

6.2、删

DELETE /lxw/user/4

6.3、改

PUT 【如果不传递值,会被置空】

PUT /lxw/user/1
{
  "name": "岩弟弟",
  "age": 23,
  "desc": "牛牛牛222",
  "tags": ["k1","k2","k3"]
}

改POST【提倡用这个】_update

POST /lxw/user/1/_update
{
  "doc":{
    "name": "岩弟弟POST"
  }
}

6.4、查【重点】

操作:

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

1、简单的搜索

GET lxw/user/1

2、简单的条件查询询_search?q=

GET lxw/user/_search?q=name:岩弟弟

3、复杂查询

GET lxw/user/_search
{
  "query":{
    "match": {
      "name": "岩"
    }
  }
}

结果

image-20210831143302966

4、限制显示字段

输出结果不需要那么多

GET lxw/user/_search
{
  "query":{
    "match": {
      "name": "岩"
    }
  },
  "_source":["name","desc"]
}

结果

image-20210831144412246

5、排序asc和desc

GET lxw/user/_search
{
  "query":{
    "match": {
      "name": "岩"
    }
  },
  "sort":{
    "age":{
      "order": "desc"
    }
  }
}

结果

image-20210831144559484

6、分页查询

from 从第几个数据开始

size 返回多少条数据

GET lxw/user/_search
{
  "query":{
    "match": {
      "name": "岩"
    }
  },
  "sort":{
    "age":{
      "order": "desc"
    }
  },
  "from":0,
  "size":1
}

结果:

image-20210831144854540

7、布尔值查询

多条件查询bool +must +should +must_not+filter

  • must( and ) 所有条件都要符合 where id =1 and name = xxx

  • should( or ) 所有条件都要符合 where id =1 or name = xxx

使用must,等价and

GET lxw/user/_search
{
  "query":{
    "bool": {
      "must": [
        {
          "match": {
            "name": "岩"
          }
        },
        {
          "match": {
            "age": 28
        }
        }
      ]
    }
  }
}

结果:

image-20210831145652164

使用should,等价or

GET lxw/user/_search
{
  "query":{
    "bool": {
      "should": [
        {
          "match": {
            "name": "岩"
          }
        },
        {
          "match": {
            "age": 28
        }
        }
      ]
    }
  }
}

结果:查询出两个数据

image-20210831145902219

使用must_not(not)

GET lxw/user/_search
{
  "query":{
    "bool": {
      "must_not": [
        {
          "match": {
            "name": "岩"
          }
        }
      ]
    }
  }
}

结果

image-20210831150243934

使用filter进行数据过滤

GET lxw/user/_search
{
  "query":{
    "bool": {
      "must": [
        {
          "match": {
            "name": "岩"
          }
        }
      ],
      "filter": [
        {
          "range": {
            "age": {
              "gte": 10,
              "lte": 25
            }
          }
        }
      ]
    }
  }
}

gt,gte,lt,lte缩写的含义

  • gt: greater than 大于

  • gte: greater than or equal 大于等于

  • lt: less than 小于

  • lte: less than or equal 小于等于

结果:

image-20210831150735772

8、关于分词:

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

  • 精确查询term,直接通过倒排索引精确查询【效率高】

使用match

GET lxw/user/_search
{
  "query":{
    "match": {
      "tags": "男 老"
    }
  }
}

结果:

image-20210831152312279

term精确查询多个值

GET testdb/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "term": {
            "t1": "22"
          }
        },
        {
          "term": {
            "t1": "33"
          }
        }
      ]
    }
  }
}

image-20210831160049727

9、两个类型 text keyword

  • text会被分词器解析

  • keyword不会被分词器解析

创建表,插入三条数据

PUT testdb
{
  "mappings": {
    "properties": {
      "name":{
        "type": "text"
      },
      "desc":{
        "type": "keyword"
      }
    }
  }
}


PUT testdb/_doc/1
{
  "name": "岩弟弟name",
  "desc": "岩弟弟desc"

}

PUT testdb/_doc/2
{
  "name": "岩弟弟name",
  "desc": "岩弟弟desc2"

}
PUT testdb/_doc/3
{
  "name": "岩弟弟name",
  "desc": "岩弟弟desc3"

}

GET【keyword】,整体,没有被分词,没有被分析

GET _analyze
{
  "analyzer": "keyword",
  "text": "岩弟弟name"
}

image-20210831153848176

GET【standard】,被拆分

GET _analyze
{
  "analyzer": "standard",
  "text": "岩弟弟name"
}

image-20210831153901603

GET 对text字段

GET testdb/_search
{
  "query":{
    "term":{
      "name": "岩"
    }
  }
}

image-20210831155409841

GET 对keyword字段

GET testdb/_search
{
  "query":{
    "term":{
      "desc": "岩弟弟desc"
    }
  }
}

image-20210831155424476

10、高亮查询

高亮显示

GET lxw/user/_search
{
  "query":{
    "match": {
      "name": "岩弟弟"
    }
  },
  "highlight": {
    "fields": {
      "name": {}
    }
  }
}

自动生成高亮前缀

image-20210831160613645

自定义高亮

GET lxw/user/_search
{
  "query":{
    "match": {
      "name": "岩弟弟"
    }
  },
  "highlight": {
    "pre_tags": "<p class='key' style='color:red'> ", 
    "post_tags": "</p>", 
    "fields": {
      "name": {}
    }
  }
}

效果

image-20210831160846414

7、集成SpringBoot

官方文档Elasticsearch Clients

https://www.elastic.co/guide/en/elasticsearch/client/index.html

1、找到原生的依赖

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.8.1</version>
</dependency>

2、找对象

image-20210831162544626

3、分析这个类中的方法

配置基本的项目

image-20210831163350335

在properties里面更改版本依赖,与本地版本一致

<!--自定义es版本依赖,保证和本地版本一致-->
<elasticsearch.version>7.8.1</elasticsearch.version>

image-20210831165104036

新建配置类

package com.badwei.esapi.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中待用
// 3.springboot,分析源码

@Configuration //xml
public class ESClientConfig {

    // spring
    @Bean
    public RestHighLevelClient restHighLevelClient(){
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("localhost", 9200, "http")));
        return client;
    }

}

7.1、关于索引的API操作

@Autowired
@Qualifier("restHighLevelClient")
private RestHighLevelClient client;


// 测试索引的创建
@Test
void testCreateIndex() throws IOException {
    //1.创建索引请求
    CreateIndexRequest request = new CreateIndexRequest("lxw_index");
    //2.执行
    CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);

    System.out.println(createIndexResponse);

}

//测试获取索引
@Test
void testExistIndex() throws IOException {
    GetIndexRequest request = new GetIndexRequest("lxw_index");
    boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
    System.out.println(exists);
}

//测试删除索引
@Test
void testDeleteIndex() throws IOException {
    DeleteIndexRequest request = new DeleteIndexRequest("lxw_index");

    AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
    System.out.println(delete.isAcknowledged());


}

7.2、关于文档的API操作

引入fastjson

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.78</version>
</dependency>
//测试添加文档
@Test
void testAddDocument() throws IOException {
    User user = new User("岩弟弟", 3);
    //创建请求
    IndexRequest request = new IndexRequest("lxw_index");

    //规则 put /lxw_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());


}

//测试获取文档,判断是否存在get /index/doc/1
@Test
void testIsExists() throws IOException {
    GetRequest getRequest = new GetRequest("lxw_index", "1");
    //不获取返回的 _source 的上下文
    getRequest.fetchSourceContext(new FetchSourceContext(false));
    getRequest.storedFields("_none_");

    boolean exists = client.exists(getRequest, RequestOptions.DEFAULT);
    System.out.println(exists);


}

//获取文档的信息
@Test
void testGetDocument() throws IOException{
    GetRequest getRequest = new GetRequest("lxw_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("lxw_index", "1");
    updateRequest.timeout("1s");

    User user = new User("岩弟弟2号", 110);

    updateRequest.doc(JSON.toJSONString(user),XContentType.JSON);

    UpdateResponse update = client.update(updateRequest, RequestOptions.DEFAULT);

    System.out.println(update.status());

}

//删除文档记录
@Test
void testDeleteDocument() throws IOException {

    DeleteRequest deleteRequest = new DeleteRequest("lxw_index","1");
    deleteRequest.timeout("3s");

    DeleteResponse delete = client.delete(deleteRequest, RequestOptions.DEFAULT);
    System.out.println(delete.status());

}


//特殊的:真的项目一般会批量插入数据
@Test
void testBulkDocument() throws IOException{

    BulkRequest bulkRequest = new BulkRequest();
    bulkRequest.timeout("10s");

    ArrayList<User> userList = new ArrayList<>();

    userList.add(new User("lxw1",31));
    userList.add(new User("lxw2",32));
    userList.add(new User("lxw3",33));
    userList.add(new User("lxw4",34));
    userList.add(new User("lxw5",35));
    userList.add(new User("lxw6",36));

    for (int i = 0; i < userList.size(); i++) {
        //批量更新,删除,修改这里就行了
        bulkRequest.add(new IndexRequest("lxw_index")
                        .id(""+(i+1)) //这里不设置id的话,会随机id
                        .source(JSON.toJSONString(userList.get(i)),XContentType.JSON));

    }
    BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);

    System.out.println(bulkResponse.hasFailures());


}

/*
    SearchRequest 搜索请求
    SearchSourceBuilder 条件构造
    HighlightBuilder 构建高亮
    TermQueryBuilder 精确查询
    MathAllQueryBuilder
    xxx QueryBuilder 对应我们刚才看到的所有命令
     */
//查询
@Test
void testSearchDocument() throws IOException{
    SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX);
    //public static final String ES_INDEX = "lxw_index";

    //构建搜索的条件
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

    TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "lxw1");//精确
    //        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();//匹配所有

    SearchSourceBuilder query = searchSourceBuilder.query(termQueryBuilder);

    //分页
    //        searchSourceBuilder.from();
    //        searchSourceBuilder.size();

    searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
    searchRequest.source(searchSourceBuilder);

    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());
    }


}

8、京东搜索实战

8.1、环境

新建springboot项目,导入默认,web,ES,Thymeleaf依赖

修改ES版本依赖,导入fastjson依赖

<!-- 自定义es版本依赖,保证和本地版本一致-->
<elasticsearch.version>7.8.0</elasticsearch.version>

导入静态资源,

新建IndexController,用来访问index.html

启动springboot项目。

8.2、爬虫

导入jsoup依赖

<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.10.2</version>
</dependency>

爬虫

//获得请求
//前提,需要联网
String url = "https://search.jd.com/Search?keyword=java";

//解析网页
Document document = Jsoup.parse(new URL(url),30000);

//所有在js中使用的方法在这都可以用
Element element = document.getElementById("J_goodsList");
//        System.out.println(element.html());

//获取所有的li元素
Elements elementsByTag = element.getElementsByTag("li");

for (Element element1 : elementsByTag) {
    String img = element1.getElementsByTag("img").eq(0).attr("data-lazy-img");
    String price = element1.getElementsByClass("p-price").eq(0).text();
    String title = element1.getElementsByClass("p-name").eq(0).text();

    System.out.println("=========================");
    System.out.println(img);
    System.out.println(price);
    System.out.println(title);


}

8.3、导入到ES

编写过程中的html修改未体现在文档中

编写Pojo

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Content {
    private String title;
    private String img;
    private String price;
}

把爬虫封装成一个方法

@Component
public class HtmlParseUtil {
//    public static void main(String[] args) throws IOException {
//
//        new HtmlParseUtil().parseJD("java").forEach(System.out::println);
//
//    }

    public List<Content> parseJD(String keyword) throws IOException {
        String url = "https://search.jd.com/Search?keyword="+keyword;
        Document document = Jsoup.parse(new URL(url),30000);
        Element element = document.getElementById("J_goodsList");
        Elements elementsByTag = element.getElementsByTag("li");

        ArrayList<Content> contentList = new ArrayList<>();
        for (Element element1 : elementsByTag) {
            String img = element1.getElementsByTag("img").eq(0).attr("data-lazy-img");
            String price = element1.getElementsByClass("p-price").eq(0).text();
            String title = element1.getElementsByClass("p-name").eq(0).text();

            Content content = new Content(title, img, price);
            contentList.add(content);


        }
        return contentList;
    }
}

编写ESConfig

package com.badwei.esjd.config;
// spring 两步骤
// 1.找对象
// 2.放到spring中待用
// 3.springboot,分析源码

@Configuration //xml
public class ESClientConfig {

    // spring
    @Bean
    public RestHighLevelClient restHighLevelClient(){
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("localhost", 9200, "http")));
        return client;
    }

}

编写Service,调用爬虫方法, 将爬取的数据导入ES中

//业务编写
@Service
public class ContentService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;


    //解析数据放入es索引中
    public Boolean parseContext(String keyword) throws IOException {
        List<Content> contents = new HtmlParseUtil().parseJD(keyword);

        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();
    }


}

编写Controller调用这个service方法

@RestController
public class ContentController {

    @Autowired
    private ContentService contentService;

    @GetMapping("/parse/{keyword}")
    public Boolean parse(@PathVariable("keyword") String keyword) throws IOException {
        return contentService.parseContext(keyword);
    }
}

这样就把爬取出来的数据导入到ES中了

8.4、ES数据获取

然后编写service数据获取

//获取数据
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 searchSourceBuilder = new SearchSourceBuilder();

    //分页
    searchSourceBuilder.from(pageNo);
    searchSourceBuilder.size(pageSize);

    //精准匹配
    TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword);
    searchSourceBuilder.query(termQueryBuilder);
    searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

    //执行搜索
    searchRequest.source(searchSourceBuilder);
    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("/search/{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.searchHighlightPage(keyword, pageNo, pageSize);
}

然后访问测试

8.5、关键字高亮

编写service

//实现搜索高亮
public List<Map<String,Object>> searchHighlightPage(String keyword,int pageNo,int pageSize) throws IOException {
    if (pageNo<=1){
        pageNo=1;
    }

    //条件搜索
    SearchRequest searchRequest = new SearchRequest("jd_goods");
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

    //分页
    searchSourceBuilder.from(pageNo);
    searchSourceBuilder.size(pageSize);

    //精准匹配
    TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword);
    searchSourceBuilder.query(termQueryBuilder);
    searchSourceBuilder.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>");
    searchSourceBuilder.highlighter(highlightBuilder);

    //执行搜索
    searchRequest.source(searchSourceBuilder);
    SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

    ArrayList<Map<String,Object>> list = new ArrayList<>();
    //结果解析
    for (SearchHit documentFields : searchResponse.getHits().getHits()) {

        //解析高亮的字段
        Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
        HighlightField title = highlightFields.get("title");
        Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();
        if (title!=null){
            Text[] fragments = title.fragments();
            String n_title = "";
            for (Text fragment : fragments) {
                n_title+=fragment;
            }
            sourceAsMap.put("title",n_title);//高亮的字段替换原来的内容
        }

        list.add(sourceAsMap);
    }

    return list;


}

测试实现高亮展示

image-20210831225107734

完成

0

评论区