编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

学成在线-第11天-讲义-搜索服务(学成在线是什么项目)

wxchong 2024-07-06 23:59:23 开源技术 14 ℃ 0 评论

1课程搜索需求分析

1.1需求分析

1、根据分类搜索课程信息。

2、根据关键字搜索课程信息,搜索方式为全文检索,关键字需要匹配课程的名称、 课程内容。

3、根据难度等级搜索课程。

4、搜索结点分页显示。

1.2搜索流程

1、课程管理服务将数据写到MySQL数据库

2、使用Logstash将MySQL数据库中的数据写到ES的索引库。

3、用户在前端搜索课程信息,请求到搜索服务。

4、搜索服务请求ES搜索课程信息。

2全文检索技术研究

参考:elasticsearch研究.md

研究ElasticSearch搜索方法。

3课程索引

3.1技术方案

如何维护课程索引信息?

1、当课程向MySQL添加后同时将课程信息添加到索引库。

采用Logstach实现,Logstach会从MySQL中将数据采集到ES索引库。

2、当课程在MySQL更新信息后同时更新该课程在索引库的信息。采用Logstach实现。

3、当课程在MySQL删除后同时将该课程从索引库删除。

手工写程序实现,在删除课程后将索引库中该课程信息删除。

3.2准备课程索引信息

课程发布成功在MySQL数据库存储课程发布信息,此信息作为课程索引信息。

3.2.1创建课程发布表

课程信息分布在course_base、course_pic等不同的表中。

课程发布成功为了方便进行索引将这几张表的数据合并在一张表中,作为课程发布信息。 创建course_pub表

3.2.2创建课程发布表模型

在课程管理服务创建模型:

@Data @ToString @Entity
@Table(name="course_pub")
@GenericGenerator(name = "jpa‐assigned", strategy = "assigned") public class CoursePub implements Serializable {
private static final long serialVersionUID = ‐916357110051689487L; @Id
@GeneratedValue(generator = "jpa‐assigned") @Column(length = 32)
private String id;
private String name;
private String users; private String mt; private String st; private String grade;
private String studymodel; private String teachmode; private String description;
private String pic;//图片
private Date timestamp;//时间戳
private String charge; private String valid; private String qq; private Float price; private Float price_old; private String expires;
private String teachplan;//课程计划
@Column(name="pub_time")
private String pubTime;//课程发布时间
}

3.2.3修改课程发布

在课程管理服务定义dao:

1)创建course_pub表的dao

public interface CoursePubRepository extends JpaRepository<CoursePub, String> {
}
  1. 修改课程发布service

//保存CoursePub

public CoursePub saveCoursePub(String id, CoursePub coursePub){ if(StringUtils.isNotEmpty(id)){

ExceptionCast.cast(CourseCode.COURSE_PUBLISH_COURSEIDISNULL);

}

CoursePub coursePubNew = null;

Optional<CoursePub> coursePubOptional = coursePubRepository.findById(id); if(coursePubOptional.isPresent()){

coursePubNew = coursePubOptional.get();

}

if(coursePubNew == null){ coursePubNew = new CoursePub();

}

BeanUtils.copyProperties(coursePub,coursePubNew);

//设置主键coursePubNew.setId(id);

//更新时间戳为最新时间

coursePub.setTimestamp(new Date());

//发布时间

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY‐MM‐dd HH:mm:ss"); String date = simpleDateFormat.format(new Date());

coursePub.setPubTime(date); coursePubRepository.save(coursePub); return coursePub;

}//创建coursePub对象

private CoursePub createCoursePub(String id){ CoursePub coursePub = new CoursePub(); coursePub.setId(id);

//基础信息

Optional<CourseBase> courseBaseOptional = courseBaseRepository.findById(id); if(courseBaseOptional == null){

CourseBase courseBase = courseBaseOptional.get(); BeanUtils.copyProperties(courseBase, coursePub);

}

//查询课程图片

Optional<CoursePic> picOptional = coursePicRepository.findById(id); if(picOptional.isPresent()){

CoursePic coursePic = picOptional.get(); BeanUtils.copyProperties(coursePic, coursePub);

}

//课程营销信息

Optional<CourseMarket> marketOptional = courseMarketRepository.findById(id); if(marketOptional.isPresent()){

CourseMarket courseMarket = marketOptional.get(); BeanUtils.copyProperties(courseMarket, coursePub);

}

//课程计划

TeachplanNode teachplanNode = teachplanMapper.selectList(id);

//将课程计划转成json

String teachplanString = JSON.toJSONString(teachplanNode); coursePub.setTeachplan(teachplanString);

return coursePub;

}

修改课程发布方法,添加调用saveCoursePub方法的代码,添加部分的代码如下:

//课程发布
@Transactional
public CoursePublishResult publish(String courseId){
....
//创建课程索引
//创建课程索引信息
CoursePub coursePub = createCoursePub(courseId);
//向数据库保存课程索引信息
CoursePub newCoursePub = saveCoursePub(courseId, coursePub);
if(newCoursePub==null){
//创建课程索引信息失败ExceptionCast.cast(CourseCode.COURSE_PUBLISH_CREATE_INDEX_ERROR);
}
....
}

3.3搭建ES环境

3.3.1ES安装

开发环境使用ES单机环境,启动ES服务端。

注意:旧的ES环境,可以删除elasticsearch-6.2.1\data\nodes目录以完全清除ES环境。 安装elasticsearch-head并启动。

3.3.2创建索引库

创建索引库

创建xc_course索引库,一个分片,0个副本。

3.3.3创建映射

Post http://localhost:9200/xc_course/doc/_mapping

{
"properties" : {
"description" : {
"analyzer" : "ik_max_word", "search_analyzer": "ik_smart",
"type" : "text"
},
"grade" : {
"type" : "keyword"
},
"id" : {
"type" : "keyword"
},
"mt" : {
"type" : "keyword"
},
"name" : {
"analyzer" : "ik_max_word", "search_analyzer": "ik_smart",
"type" : "text"
},
"users" : {
"index" : false, "type" : "text"
},
"charge" : {
"type" : "keyword"
},
"valid" : {
"type" : "keyword"
},
"pic" : {
"index" : false, "type" : "keyword"
},
"qq" : {
"index" : false, "type" : "keyword"
},
"price" : {
"type" : "float"
},
"price_old" : {
"type" : "float"
},
"st" : {
"type" : "keyword"
},
"status" : {
"type" : "keyword"
},
"studymodel" : { "type" : "keyword"
},
"teachmode" : {
"type" : "keyword"
},
"teachplan" : {
"analyzer" : "ik_max_word", "search_analyzer": "ik_smart",
"type" : "text"
},
"expires" : {
"type" : "date", "format": "yyyy‐MM‐dd HH:mm:ss"
},
"pub_time" : {
"type" : "date", "format": "yyyy‐MM‐dd HH:mm:ss"
},
"start_time" : {
"type" : "date", "format": "yyyy‐MM‐dd HH:mm:ss"
},
"end_time" : {
"type" : "date", "format": "yyyy‐MM‐dd HH:mm:ss"
}
}
}

3.4Logstash创建索引

Logstash是ES下的一款开源软件,它能够同时 从多个来源采集数据、转换数据,然后将数据发送到Eleasticsearch 中创建索引。

本项目使用Logstash将MySQL中的数据采用到ES索引中。

3.4.1下载Logstash

下载Logstash6.2.1版本,和本项目使用的Elasticsearch6.2.1版本一致。

解压:

3.4.2安装logstash-input-jdbc

logstash-input-jdbc 是ruby开发的,先下载ruby并安装下载地址: https://rubyinstaller.org/downloads/

下载2.5版本即可。

安装完成查看是否安装成功

Logstash5.x以上版本本身自带有logstash-input-jdbc,6.x版本本身不带logstash-input-jdbc插件,需要手动安装

安装成功后我们可以在logstash根目录下的以下目录查看对应的插件版本

解压老师提供的logstash-6.2.1.zip,此logstash中已集成了logstash-input-jdbc插件。

3.4.3创建模板文件

Logstash的工作是从MySQL中读取数据,向ES中创建索引,这里需要提前创建mapping的模板文件以便logstash

使用。

在logstach的con?g目录创建xc_course_template.json,内容如下:

本教程的xc_course_template.json目录是:D:/ElasticSearch/logstash-6.2.1/con?g/xc_course_template.json

{
"mappings" : {
"doc" : {
"properties" : { "charge" : {
"type" : "keyword"
},
"description" : {
"analyzer" : "ik_max_word", "search_analyzer" : "ik_smart", "type" : "text"
},
"end_time" : {
"format" : "yyyy‐MM‐dd HH:mm:ss", "type" : "date"
},
"expires" : {
"format" : "yyyy‐MM‐dd HH:mm:ss", "type" : "date"
},
"grade" : {
"type" : "keyword"
},
"id" : {
"type" : "keyword"
},
"mt" : {
"type" : "keyword"
},
"name" : {
"analyzer" : "ik_max_word", "search_analyzer" : "ik_smart", "type" : "text"
},
"pic" : {
"index" : false, "type" : "keyword"
},
"price" : {
"type" : "float"
},
"price_old" : {
"type" : "float"
},
"pub_time" : {
"format" : "yyyy‐MM‐dd HH:mm:ss", "type" : "date"
},
"qq" : {
"index" : false, "type" : "keyword"
},
"st" : {
"type" : "keyword"
},
"start_time" : {
"format" : "yyyy‐MM‐dd HH:mm:ss", "type" : "date"
},
"status" : {
"type" : "keyword"
},
"studymodel" : { "type" : "keyword"
},
"teachmode" : {
"type" : "keyword"
},
"teachplan" : {
"analyzer" : "ik_max_word", "search_analyzer" : "ik_smart", "type" : "text"
},
"users" : {
"index" : false, "type" : "text"
},
"valid" : {
"type" : "keyword"
}
}
}
},
"template" : "xc_course"
}

3.4.4配置mysql.conf

在logstash的con?g目录下配置mysql.conf文件供logstash使用,logstash会根据mysql.conf文件的配置的地址从

MySQL中读取数据向ES中写入索引。

参 考 https://www.elastic.co/guide/en/logstash/current/plugins-inputs-jdbc.html 配置输入数据源和输出数据源。

input {
stdin {
}
jdbc {
jdbc_connection_string => "jdbc:mysql://localhost:3306/xc_course? useUnicode=true&characterEncoding=utf‐8&useSSL=true&serverTimezone=UTC"
# the user we wish to excute our statement as jdbc_user => "root"
jdbc_password => mysql
# the path to our downloaded jdbc driver
jdbc_driver_library => "F:/develop/maven/repository3/mysql/mysql‐connector‐java/5.1.41/mysql‐ connector‐java‐5.1.41.jar"
# the name of the driver class for mysql jdbc_driver_class => "com.mysql.jdbc.Driver" jdbc_paging_enabled => "true"
jdbc_page_size => "50000" #要执行的sql文件
#statement_filepath => "/conf/course.sql"
statement => "select * from course_pub where timestamp > date_add(:sql_last_value,INTERVAL 8 HOUR)"
#定时配置
schedule => "* * * * *" record_last_run => true
last_run_metadata_path => "D:/ElasticSearch/logstash‐6.2.1/config/logstash_metadata"
}
}
output {
elasticsearch { #ES的ip地址和端口
hosts => "localhost:9200"
#hosts => ["localhost:9200","localhost:9202","localhost:9203"] #ES索引库名称
index => "xc_course"
document_id => "%{id}"
document_type => "doc"
template =>"D:/ElasticSearch/logstash‐6.2.1/config/xc_course_template.json" template_name =>"xc_course"
template_overwrite =>"true"
}
stdout { #日志输出
codec => json_lines
}
}

说明:

1、ES采用UTC时区问题

ES采用UTC 时区,比北京时间早8小时,所以ES读取数据时让最后更新时间加8小时

where timestamp > date_add(:sql_last_value,INTERVAL 8 HOUR)

2、logstash每个执行完成会在D:/ElasticSearch/logstash-6.2.1/con?g/logstash_metadata记录执行时间下次以此时间为基准进行增量同步数据到索引库。

3.4.5测试

启动logstash.bat:

.\logstash.bat ‐f ..\config\mysql.conf

修改course_pub中的数据,并且修改timestamp为当前时间,观察Logstash日志是否读取到要索引的数据。

4课程搜索

4.1需求分析

1、根据分类搜索课程信息。

2、根据关键字搜索课程信息,搜索方式为全文检索,关键字需要匹配课程的名称、 课程内容。

3、根据难度等级搜索课程。

4、搜索结点分页显示。技术分析:

1、根据关键字搜索,采用MultiMatchQuery,搜索name、description、teachplan 2、根据分类、课程等级搜索采用过虑器实现。

3、分页查询。

4、高亮显示。

4.2创建搜索服务工程

1)创建xc-service-search工程

2)配置

1、配置appliction.yml

server:
port: 40100 spring:
application:
name: xc‐search‐service elasticsearch:
hostlist: 127.0.0.1:9200 #多个结点中间用逗号分隔
course:
index: xc_course type: doc

2、配置RestHighLevelClient和RestClient

package com.xuecheng.search.config;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ElasticsearchConfig {
@Value("${xuecheng.elasticsearch.hostlist}") private String hostlist;
@Bean
public RestHighLevelClient restHighLevelClient(){
//解析hostlist配置信息
String[] split = hostlist.split(",");
//创建HttpHost数组,其中存放es主机和端口的配置信息HttpHost[] httpHostArray = new HttpHost[split.length]; for(int i=0;i<split.length;i++){
String item = split[i];
httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":") [1]), "http");
}
//创建RestHighLevelClient客户端
return new RestHighLevelClient(RestClient.builder(httpHostArray));
}
@Bean
public RestClient restClient(){
//解析hostlist配置信息
String[] split = hostlist.split(",");
//创建HttpHost数组,其中存放es主机和端口的配置信息HttpHost[] httpHostArray = new HttpHost[split.length]; for(int i=0;i<split.length;i++){
String item = split[i];
httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":") [1]), "http");
}
return RestClient.builder(httpHostArray).build();
}
}

4.3API

@Api(value = "课程搜索",description = "课程搜索",tags = {"课程搜索"}) public interface EsCourseControllerApi {
@ApiOperation("课程搜索")
public QueryResponseResult<CoursePub> list(int page,int size,
CourseSearchParam courseSearchParam) throws IOException;
}

4.4Service

Service方法代码复杂,这里分三步完成。

4.4.1按关键字搜索

1)在appliction.yml中配置source_?eld

elasticsearch:
hostlist: 127.0.0.1:9200 #多个结点中间用逗号分隔course:
index: xc_course type: doc source_field:
id,name,grade,mt,st,charge,valid,pic,qq,price,price_old,status,studymodel,teachmode,expires,pub_ time,start_time,end_time

2)service完整代码如下

@Service

public class EsCourseService {

private static final Logger LOGGER = LoggerFactory.getLogger(EsCourseService.class);

@Value("${xuecheng.elasticsearch.course.index}") private String es_index; @Value("${xuecheng.elasticsearch.course.type}") private String es_type;

@Value("${xuecheng.elasticsearch.course.source_field}") private String source_field;

@Autowired

RestHighLevelClient restHighLevelClient;

public QueryResponseResult<CoursePub> list(int page,int size,CourseSearchParam

courseSearchParam) {

//设置索引

SearchRequest searchRequest = new SearchRequest(es_index);

//设置类型searchRequest.types(es_type);

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

//source源字段过虑

String[] source_fields = source_field.split(","); searchSourceBuilder.fetchSource(source_fields, new String[]{});

//关键字

if(StringUtils.isNotEmpty(courseSearchParam.getKeyword())){

//匹配关键字

MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(courseSearchParam.getKeyword(), "name", "teachplan","description");

//设置匹配占比

multiMatchQueryBuilder.minimumShouldMatch("70%");

//提升另个字段的Boost值multiMatchQueryBuilder.field("name",10); boolQueryBuilder.must(multiMatchQueryBuilder);

}

//布尔查询searchSourceBuilder.query(boolQueryBuilder);

//请求搜索searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = null;

try {

searchResponse = restHighLevelClient.search(searchRequest);

} catch (IOException e) { e.printStackTrace();

LOGGER.error("xuecheng search error..{}",e.getMessage());

return new QueryResponseResult(CommonCode.SUCCESS,new QueryResult<CoursePub>());

}

//结果集处理

SearchHits hits = searchResponse.getHits(); SearchHit[] searchHits = hits.getHits();

//记录总数

long totalHits = hits.getTotalHits();

//数据列表

List<CoursePub> list = new ArrayList<>();

for (SearchHit hit : searchHits) { CoursePub coursePub = new CoursePub();

//取出source

Map<String, Object> sourceAsMap = hit.getSourceAsMap();

//取出名称

String name = (String) sourceAsMap.get("name"); coursePub.setName(name);

//图片

String pic = (String) sourceAsMap.get("pic"); coursePub.setPic(pic);

//价格

Float price = null; try {

if(sourceAsMap.get("price")!=null ){

price = Float.parseFloat((String) sourceAsMap.get("price"));

}

} catch (Exception e) { e.printStackTrace();

}

coursePub.setPrice(price); Float price_old = null; try {

if(sourceAsMap.get("price_old")!=null ){

price_old = Float.parseFloat((String) sourceAsMap.get("price_old"));

}

} catch (Exception e) { e.printStackTrace();

}

coursePub.setPrice_old(price_old); list.add(coursePub);

}

QueryResult<CoursePub> queryResult = new QueryResult<>(); queryResult.setList(list); queryResult.setTotal(totalHits);

QueryResponseResult<CoursePub> coursePubQueryResponseResult = new QueryResponseResult<CoursePub>(CommonCode.SUCCESS,queryResult);

return coursePubQueryResponseResult;

}

}

4.4.2按分类和难度等级搜索

按分类和难度等级搜索代码如下:

@Service
public class EsCourseService {
private static final Logger LOGGER = LoggerFactory.getLogger(EsCourseService.class);
@Value("${xuecheng.elasticsearch.course.index}") private String es_index; @Value("${xuecheng.elasticsearch.course.type}")
private String es_type;
@Value("${xuecheng.elasticsearch.course.source_field}") private String source_field;
@Autowired
RestHighLevelClient restHighLevelClient;
public QueryResponseResult<CoursePub> list(int page,int size,CourseSearchParam courseSearchParam) {
//设置索引
SearchRequest searchRequest = new SearchRequest(es_index);
//设置类型searchRequest.types(es_type);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//source源字段过虑
String[] source_fields = source_field.split(","); searchSourceBuilder.fetchSource(source_fields, new String[]{});
//关键字
if(StringUtils.isNotEmpty(courseSearchParam.getKeyword())){
//匹配关键字
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(courseSearchParam.getKeyword(), "name", "teachplan","description");
//设置匹配占比
multiMatchQueryBuilder.minimumShouldMatch("70%");
//提升另个字段的Boost值multiMatchQueryBuilder.field("name",10); boolQueryBuilder.must(multiMatchQueryBuilder);
}
//过虑if(StringUtils.isNotEmpty(courseSearchParam.getMt())){
boolQueryBuilder.filter(QueryBuilders.termQuery("mt",courseSearchParam.getMt()));
}
if(StringUtils.isNotEmpty(courseSearchParam.getSt())){ boolQueryBuilder.filter(QueryBuilders.termQuery("st",courseSearchParam.getSt()));
}
if(StringUtils.isNotEmpty(courseSearchParam.getGrade())){
boolQueryBuilder.filter(QueryBuilders.termQuery("grade",courseSearchParam.getGrade()));
}
//布尔查询searchSourceBuilder.query(boolQueryBuilder);
//请求搜索searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = null;
try {
searchResponse = restHighLevelClient.search(searchRequest);
} catch (IOException e) { e.printStackTrace();
LOGGER.error("xuecheng search error..{}",e.getMessage());
return new QueryResponseResult(CommonCode.SUCCESS,new QueryResult<CoursePub>());
}
//结果集处理
SearchHits hits = searchResponse.getHits(); SearchHit[] searchHits = hits.getHits();
//记录总数
long totalHits = hits.getTotalHits();
//数据列表
List<CoursePub> list = new ArrayList<>();
for (SearchHit hit : searchHits) { CoursePub coursePub = new CoursePub();
//取出source
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
//取出名称
String name = (String) sourceAsMap.get("name");
coursePub.setName(name);
//图片
String pic = (String) sourceAsMap.get("pic"); coursePub.setPic(pic);
//价格
Float price = null; try {
if(sourceAsMap.get("price")!=null ){
price = Float.parseFloat((String) sourceAsMap.get("price"));
}
} catch (Exception e) { e.printStackTrace();
}
coursePub.setPrice(price); Float price_old = null; try {
if(sourceAsMap.get("price_old")!=null ){
price_old = Float.parseFloat((String) sourceAsMap.get("price_old"));
}
} catch (Exception e) { e.printStackTrace();
}
coursePub.setPrice_old(price_old); list.add(coursePub);
}
QueryResult<CoursePub> queryResult = new QueryResult<>(); queryResult.setList(list); queryResult.setTotal(totalHits);
QueryResponseResult<CoursePub> coursePubQueryResponseResult = new QueryResponseResult<CoursePub>(CommonCode.SUCCESS,queryResult);
return coursePubQueryResponseResult;
}
}

4.4.3分页与高亮

@Service

public class EsCourseService {

private static final Logger LOGGER = LoggerFactory.getLogger(EsCourseService.class);

@Value("${xuecheng.elasticsearch.course.index}") private String es_index; @Value("${xuecheng.elasticsearch.course.type}") private String es_type;

@Value("${xuecheng.elasticsearch.course.source_field}") private String source_field;

@Autowired

RestHighLevelClient restHighLevelClient;

public QueryResponseResult<CoursePub> list(int page,int size,CourseSearchParam courseSearchParam) {

//设置索引

SearchRequest searchRequest = new SearchRequest(es_index);

//设置类型searchRequest.types(es_type);

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

//source源字段过虑

String[] source_fields = source_field.split(","); searchSourceBuilder.fetchSource(source_fields, new String[]{});

//关键字

if(StringUtils.isNotEmpty(courseSearchParam.getKeyword())){

//匹配关键字

MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(courseSearchParam.getKeyword(), "name", "teachplan","description");

//设置匹配占比

multiMatchQueryBuilder.minimumShouldMatch("70%");

//提升另个字段的Boost值multiMatchQueryBuilder.field("name",10); boolQueryBuilder.must(multiMatchQueryBuilder);

}

//过虑if(StringUtils.isNotEmpty(courseSearchParam.getMt())){

boolQueryBuilder.filter(QueryBuilders.termQuery("mt",courseSearchParam.getMt()));

}

if(StringUtils.isNotEmpty(courseSearchParam.getSt())){

boolQueryBuilder.filter(QueryBuilders.termQuery("st",courseSearchParam.getSt()));

}

if(StringUtils.isNotEmpty(courseSearchParam.getGrade())){

boolQueryBuilder.filter(QueryBuilders.termQuery("grade",courseSearchParam.getGrade()));

}

//分页if(page<=0){

page = 1;

}

if(size<=0){

size = 20;

}

int start = (page‐1)*size; searchSourceBuilder.from(start); searchSourceBuilder.size(size);

//布尔查询

searchSourceBuilder.query(boolQueryBuilder);

//高亮设置

HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.preTags("<font class='eslight'>"); highlightBuilder.postTags("</font>");

//设置高亮字段

highlightBuilder.fields().add(new HighlightBuilder.Field("name")); searchSourceBuilder.highlighter(highlightBuilder);

//请求搜索

searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = null;

try {

searchResponse = restHighLevelClient.search(searchRequest);

} catch (IOException e) { e.printStackTrace();

LOGGER.error("xuecheng search error..{}",e.getMessage());

return new QueryResponseResult(CommonCode.SUCCESS,new QueryResult<CoursePub>());

}

//结果集处理

SearchHits hits = searchResponse.getHits(); SearchHit[] searchHits = hits.getHits();

//记录总数

long totalHits = hits.getTotalHits();

//数据列表

List<CoursePub> list = new ArrayList<>();

for (SearchHit hit : searchHits) { CoursePub coursePub = new CoursePub();

//取出source

Map<String, Object> sourceAsMap = hit.getSourceAsMap();

//取出名称

String name = (String) sourceAsMap.get("name");

//取出高亮字段内容

Map<String, HighlightField> highlightFields = hit.getHighlightFields(); if(highlightFields!=null){

HighlightField nameField = highlightFields.get("name"); if(nameField!=null){

Text[] fragments = nameField.getFragments(); StringBuffer stringBuffer = new StringBuffer(); for (Text str : fragments) {

stringBuffer.append(str.string());

}

name = stringBuffer.toString();

}

}

coursePub.setName(name);

//图片

String pic = (String) sourceAsMap.get("pic"); coursePub.setPic(pic);

//价格

Float price = null; try {

if(sourceAsMap.get("price")!=null ){

price = Float.parseFloat((String) sourceAsMap.get("price"));

}

} catch (Exception e) { e.printStackTrace();

}

coursePub.setPrice(price); Float price_old = null; try {

if(sourceAsMap.get("price_old")!=null ){

price_old = Float.parseFloat((String) sourceAsMap.get("price_old"));

}

} catch (Exception e) { e.printStackTrace();

}

coursePub.setPrice_old(price_old); list.add(coursePub);

}

QueryResult<CoursePub> queryResult = new QueryResult<>(); queryResult.setList(list); queryResult.setTotal(totalHits);

QueryResponseResult<CoursePub> coursePubQueryResponseResult = new QueryResponseResult<CoursePub>(CommonCode.SUCCESS,queryResult);

return coursePubQueryResponseResult;

}

}

4.5Controller

@RestController @RequestMapping("/search/course")
public class EsCourseController implements EsCourseControllerApi { @Autowired
EsCourseService esCourseService;
@Override @GetMapping(value="/list/{page}/{size}")
public QueryResponseResult<CoursePub> list(@PathVariable("page") int page, @PathVariable("size") int size, CourseSearchParam courseSearchParam) throws IOException {
return esCourseService.list(page,size,courseSearchParam);
}
}

4.5 测试

使用postman测试/search/course

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表