谷粒学院项目 完善增加搜索模块 门户个人中心
后端代码:https://gitee.com/wodful/edu_admin.git
前端代码:
门户:https://gitee.com/wodful/edu_front.git
后台管理:https://gitee.com/wodful/edu_parent.git
项目视频教程
B站 谷粒学院-2020版微服务-全栈在线教育实战项目地址:https://b23.tv/hteMbT
后端技术
需要的工具: ElasticSearch-1 和logstash-6.21
链接:https://pan.baidu.com/s/1y4frSse1FXv-El83IfxQuQ
提取码:0gcs
复制这段内容后打开百度网盘手机App,操作更方便哦
使用postMan创建索引和映射:
put: http://localhost:9200/edu_course
put:http://localhost:9200/edu_course/CourseSearchEntity/_mapping
{
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word"
},
"teacher_name": {
"type": "text",
"analyzer": "ik_max_word"
},
"course_description": {
"type": "text",
"analyzer": "ik_max_word"
},
"price": {
"type": "float"
},
"cover": {
"type": "keyword"
},
"view_count": {
"type": "long"
},
"buy_count": {
"type": "long"
},
"subject_parent_id" : {
"type" : "keyword"
},
"subject_id" : {
"type" : "keyword"
},
"gmt_create" : {
"type" : "date"
},
"teacher_id" : {
"index" : false,
"type" : "text"
}
}
}
``搜索关键代码块
public Result list(Long page, Long limit, 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(), "title",
"teacher_name","course_description");
//设置匹配占比
multiMatchQueryBuilder.minimumShouldMatch("70%");
//提升另个字段的Boost值
multiMatchQueryBuilder.field("title",10);
boolQueryBuilder.must(multiMatchQueryBuilder);
}
//过虑
if(StringUtils.isNotEmpty(courseSearchParam.getSubjectParentId()))
{
boolQueryBuilder.filter(QueryBuilders.termQuery("subject_parent_id",courseSearchParam.getSubjectParentId()));
}
if(StringUtils.isNotEmpty(courseSearchParam.getSubjectId()))
{
boolQueryBuilder.filter(QueryBuilders.termQuery("subject_id",courseSearchParam.getSubjectId()));
}
if (StringUtils.isNotEmpty(courseSearchParam.getBuyCountSort())) {
searchSourceBuilder.sort(new FieldSortBuilder("buy_count").order(SortOrder.DESC));
}
if (StringUtils.isNotEmpty(courseSearchParam.getGmtCreateSort())) {
searchSourceBuilder.sort(new FieldSortBuilder("gmt_create").order(SortOrder.DESC));
}
if (StringUtils.isNotEmpty(courseSearchParam.getPriceSort())) {
searchSourceBuilder.sort(new FieldSortBuilder("price").order(SortOrder.DESC));
}
//布尔查询
searchSourceBuilder.query(boolQueryBuilder);
//请求搜索
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = null;
try {
searchResponse = restHighLevelClient.search(searchRequest);
// searchResponse = restClient.sea(searchRequest);
} catch (IOException e) {
e.printStackTrace();
// LOGGER.error("xuecheng search error..{}",e.getMessage());
return Result.error().message("搜索相应失败");
}
//结果集处理
SearchHits hits = searchResponse.getHits();
SearchHit[] searchHits = hits.getHits();
//记录总数
long totalHits = hits.getTotalHits();
List<EduCourseReponse> list = new ArrayList<>();
for (SearchHit hit : searchHits) {
if(MapUtils.isNotEmpty(hit.getSourceAsMap())){
EduCourseReponse coursePub = new EduCourseReponse();
//取出source
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
//取出名称
String title = (String) sourceAsMap.get("title");
coursePub.setTitle(title);
//图片
String cover = (String) sourceAsMap.get("cover");
coursePub.setCover(cover);
//价格
BigDecimal price = null;
try {
if(sourceAsMap.get("price")!=null ){
price = new BigDecimal(Double.valueOf((Double) sourceAsMap.get("price")).toString());
}
} catch (Exception e) {
e.printStackTrace();
}
coursePub.setPrice(price);
Long buyCount = Long.valueOf(sourceAsMap.get("buy_count").toString());
Long viewCount = Long.valueOf(sourceAsMap.get("view_count").toString());
coursePub.setBuyCount(buyCount);
coursePub.setViewCount(viewCount);
coursePub.setId(sourceAsMap.get("id").toString());
list.add(coursePub);
}
}
Page<EduCourseReponse> pageParam = new Page<>();
pageParam.setTotal(totalHits);
pageParam.setRecords(list);
pageParam.setCurrent(page);
pageParam.setSize(limit);
long current = pageParam.getCurrent();
long pages = pageParam.getPages();
long size = pageParam.getSize();
long total = pageParam.getTotal();
boolean hasNext = pageParam.hasNext();
boolean hasPrevious = pageParam.hasPrevious();
Map<String, Object> map = new HashMap<String, Object>();
map.put("items", list);
map.put("current", current);
map.put("pages", pages);
map.put("size", size);
map.put("total", total);
map.put("hasNext", hasNext);
map.put("hasPrevious", hasPrevious);
return Result.ok().data(map);
}```
使用logstash-6.2.1采集数据
edu_course.sql
SELECT
ec.id,
ec.title,
ec.price,
ec.cover,
ec.buy_count,
ec.view_count,
ecd.description as course_description,
et.`name` as teacher_name,
ec.subject_parent_id,
ec.subject_id,
ec.gmt_create,
ec.teacher_id
FROM
edu_course ec,
edu_course_description ecd,
edu_teacher et
WHERE
ec.id = ecd.id
AND ec.teacher_id = et.id and ec.gmt_modified > date_add(:sql_last_value,INTERVAL 8 HOUR)
模板:edu_course.json
{
"mappings":{
"CourseSearchEntity": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word"
},
"teacher_name": {
"type": "text",
"analyzer": "ik_max_word"
},
"course_description": {
"type": "text",
"analyzer": "ik_max_word"
},
"price": {
"type": "float"
},
"cover": {
"type": "keyword"
},
"view_count": {
"type": "long"
},
"buy_count": {
"type": "long"
},
"subject_parent_id" : {
"type" : "keyword"
},
"subject_id" : {
"type" : "keyword"
},
"gmt_create" : {
"type" : "date"
},
"teacher_id" : {
"index" : false,
"type" : "text"
},
}
}
},
"settings" : {
"number_of_shards": 1
"number_of_replicas": 0
},
"template" : "edu_course"
}
mysql.conf 启动logstash 加载此配置文件
input {
stdin {
}
jdbc {
jdbc_connection_string => "jdbc:mysql://localhost:3306/edu?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC"
# the user we wish to excute our statement as
jdbc_user => "root"
jdbc_password => "123456"
# the path to our downloaded jdbc driver
jdbc_driver_library => "E:/mavenjar/repository/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 => "G:/ElasticSearch/logstash-6.2.1/config/edu_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 => "G:/ElasticSearch/logstash-6.2.1/config/logstash_metadata"
}
}
output {
elasticsearch {
#ES的ip地址和端口
hosts => "localhost:9200"
#hosts => ["localhost:9200","localhost:9202","localhost:9203"]
#ES索引库名称
index => "edu_course"
document_id => "%{id}"
document_type => "CourseSearchEntity"
template =>"G:/ElasticSearch/logstash-6.2.1/config/edu_course.json"
template_name =>"edu_course"
template_overwrite =>"true"
}
stdout {
#日志输出
codec => json_lines
}
}