学成在线(第11天)

课程搜索需求分析

需求分析

1、根据分类搜索课程信息。
2、根据关键字搜索课程信息,搜索方式为全文检索,关键字需要匹配课程的名称、 课程内容。
3、根据难度等级搜索课程。
4、搜索结点分页显示。

搜索流程

1、课程管理服务将数据写到MySQL数据库
2、使用Logstash将MySQL数据库中的数据写到ES的索引库。
3、用户在前端搜索课程信息,请求到搜索服务。
4、搜索服务请求ES搜索课程信息。

课程索引

如何维护课程索引信息?
1、当课程向MySQL添加后同时将课程信息添加到索引库。
采用Logstach实现,Logstach会从MySQL中将数据采集到ES索引库。
2、当课程在MySQL更新信息后同时更新该课程在索引库的信息。
采用Logstach实现。
3、当课程在MySQL删除后同时将该课程从索引库删除。
手工写程序实现,在删除课程后将索引库中该课程信息删除。

准备课程索引信息

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

创建课程发布表

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

创建课程发布表模型

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

@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;//课程发布时间
}

修改课程发布

在课程管理服务定义dao:
1)创建course_pub表的dao

public interface CoursePubRepository extends JpaRepository<CoursePub, String> {
}

2) 修改课程发布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);
        }
       ....
    }

搭建ES环境

开发环境使用ES单机环境,启动ES服务端。
注意:旧的ES环境,可以删除elasticsearch-6.2.1\data\nodes目录以完全清除ES环境。
安装elasticsearch-head并启动。

创建索引库

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

创建映射

在postman里添加映射

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"
            }
        }
    }

Logstash 创建索引

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

这里资料给的配套文件有很多坑,我把坑都踩了一遍,下面分享解决方法。

下载Logstash

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

安装logstash-input-jdbc

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

创建模板文件

Logstash的工作是从MySQL中读取数据,向ES中创建索引,这里需要提前创建mapping的模板文件以便logstash
使用。
在logstach的config目录创建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"
}

配置mysql.conf

在logstash的config目录下配置mysql.conf文件供logstash使用,logstash会根据mysql.conf文件的配置的地址从
MySQL中读取数据向ES中写入索引。

配置输入数据源和输出数据源。

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 => ""
  # the path to our downloaded jdbc driver
  #配置本地仓库的mysql数据源jar的路径
  jdbc_driver_library => "D:/Maven/m2/repository/mysql/mysql-connector-java/5.1.40/mysql-connector-java-5.1.40.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
  #配置本地logstash_metadata存放路径,上一次检索数据的时间点
  last_run_metadata_path => "D:/ElasticSearch01/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"
  #覆盖本地的conf的json数据,同上
  template =>"D:/ElasticSearch01/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:/ElasticSearch01/logstash-6.2.1/config/logstash_metadata记录执行时间下次以此
时间为基准进行增量同步数据到索引库。

测试

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

启动测试前,要把D:\ElasticSearch01\logstash-6.2.1\bin下的logstash.bat的最后一行的classpath加双冒号,不然启动不了,报找不到启动类。

改好后重新启动

只查到一个数据,这里也有坑。要把logstash_metadata里的上一次记录的时间改比数据库所有的时间都要小!!

statement => "select * from course_pub where timestamp > date_add(:sql_last_value,INTERVAL 8 HOUR)"

改了后,可以看到可以查到所有数据了!

再去查看Elasticsearch,但是数据获取不到,显示不出来??数据已经在更新了啊!

有延时?无论我怎么重启,重装都是这样。。。

最后各种翻博客,卸载重装,查看Elasticsearch的日志文件,不断摸索才发现问题所在。

这里说的是xc_course_template.json的pub_time中的日期格式和postman里添加映射的日期格式两次不一致导致的!

这是PDF复制过去的锅,原先日期格式的"-"为中文格式,要改成英文格式!!

照着上面步骤再重新弄一遍,把坑避免,可以看到终于成功了!!!

最后总结一下出现的bug:

1.mysql.conf配置文件中的数据库密码加双引号

2.bin下的logstash.bat的最后一行的classpath加双冒号

3.要把logstash_metadata里的上一次记录的时间改比数据库所有的时间都要小

4.xc_course_template.json的pub_time中的日期格式和postman里添加映射的日期格式中的"-"为中文格式,要改成英文格式

遇到bug的时候不要急躁,要有耐心,一次不行就卸载重装再试。可以先做其他事分散注意力,一定找问题出在哪里,通过他人的博客寻求思路。

不断摸索,一定可以迎刃而解,可以提升自己解决bug的能力。

原文地址:https://www.cnblogs.com/anan-java/p/12268307.html

时间: 2024-08-30 08:20:49

学成在线(第11天)的相关文章

学成在线(第21天)项目总结

1  学成在线是个什么样的项目? 1.1  项目背景 学成在线借鉴了MOOC(大型开放式网络课程,即MOOC(massive open online courses))的设计思想,是一个提供IT职业课程在线学习的平台,它为即将和已经加入IT领域的技术人才提供在线学习服务,用户通过在线学习.在线练习.在线考试等学习内容,最终掌握所学的IT技能,并能在工作中熟练应用.当前市场的在线教育模式多种多样,包括:B2C.C2C.B2B2C等业务模式,学成在线采用B2B2C业务模式,即向企业或个人提供在线教育

学成在线(第1天)

第一次用博客,笔者大学毕业即将走向社会,从事Java开发,有个博客是很有必要的.博客用于记录学习工作中遇到的问题,可以很好的总结经验.同时我在遇到bug的时候也是通过他人博客解决的,我也想通过博客帮助到遇到同样问题的人. 年前面试过几家,现在企业都要求分布式,微服务springcloud的项目经验,为了能找到更好的工作,我选择了自学黑马<学成在线>这个微服务项目,这个博客就用于记录每天看视频做这个项目遇到的问题和总结吧! 1.项目的功能架构 1.1  项目背景 学成在线借鉴了MOOC(大型开放

学成在线(第15天)

学习页面查询课程计划 到目前为止,我们已可以编辑课程计划信息并上传课程视频,下一步我们要实现在线学习页面动态读取章节对应的视频并进行播放.在线学习页面所需要的信息有两类:一类是课程计划信息.一类是课程学习信息(视频地址.学习进度等),如下图: 在线学习集成媒资管理的需求如下:1.在线学习页面显示课程计划2.点击课程计划播放该课程计划对应的视频 Api 接口 课程计划信息从哪里获取?目前课程计划信息在课程管理数据库和ES索引库中存在,考虑性能要求,课程发布后对课程的查询统一从ES索引库中查询.前端

学成在线(第3天)

新增页面 新增页面接口定义 1.定义响应模型 @Data public class CmsPageResult extends ResponseResult {     CmsPage cmsPage;     public CmsPageResult(ResultCode resultCode,CmsPage cmsPage) {         super(resultCode);         this.cmsPage = cmsPage;     } } 2.定义添加Api @ApiO

学成在线(第4天)

页面静态化需求 1.为什么要进行页面管理?本项目cms系统的功能就是根据运营需要,对门户等子系统的部分页面进行管理,从而实现快速根据用户需求修改页面内容并上线的需求. 2.如何修改页面的内容?在开发中修改页面内容是需要人工编写html及JS文件,CMS系统是通过程序自动化的对页面内容进行修改,通过页面静态化技术生成html页面. 3.如何对页面进行静态化? 采用页面模板+数据 = 输出html页面的技术实现静态化. 4.静态化的html页面存放在哪里? 生成对的静态化的页面,由cms程序自动发布

学成在线(第8天)

FastDFS 研究 什么是分布式文件系统 什么是文件系统 文件系统是负责管理和存储文件的系统软件,它是操作系统和硬件驱动之间的桥梁,操作系统通过文件系统提供的接口去存取文件,用户通过操作系统访问磁盘上的文件.如下图: 什么是分布式文件系统 为什么会有分布文件系统呢?分布式文件系统是面对互联网的需求而产生,互联网时代对海量数据如何存储?靠简单的增加硬盘的个数已经满足不了我们的要求,因为硬盘传输速度有限但是数据在急剧增长,另外我们还要要做好数据备份.数据安全等.采用分布式文件系统可以将多个地点的文

学成在线(第14天)

视频处理 需求分析 原始视频通常需要经过编码处理,生成m3u8和ts文件方可基于HLS协议播放视频.通常用户上传原始视频,系统自动处理成标准格式,系统对用户上传的视频自动编码.转换,最终生成m3u8文件和ts文件,处理流程如下:1.用户上传视频成功2.系统对上传成功的视频自动开始编码处理3.用户查看视频处理结果,没有处理成功的视频用户可在管理界面再次触发处理4.视频处理完成将视频地址及处理结果保存到数据库 视频处理流程如下: 视频处理进程的任务是接收视频处理消息进行视频处理,业务流程如下:1.监

学成在线_nginx遇到的问题

下载nginx:http://nginx.org/en/download.html 下载了最新的稳定版本 安装目录内运行nginx.exe 一直运行不起来.进程里面也没有这个进程.我把本机的IIS的80端口关闭了也起作用. 后来查询,发现可以在logs文件夹下面看错误日志. An attempt was made to access a socket in a way forbidden by its access permissions https://www.cnblogs.com/hope

学成在线(第6天)

页面发布课程管理 技术方案 本项目使用MQ实现页面发布的技术方案如下: 技术方案说明:1.平台包括多个站点,页面归属不同的站点.2.发布一个页面应将该页面发布到所属站点的服务器上.3.每个站点服务部署cms client程序,并与交换机绑定,绑定时指定站点Id为routingKey.指定站点id为routingKey就可以实现cms client只能接收到所属站点的页面发布消息.4.页面发布程序向MQ发布消息时指定页面所属站点Id为routingKey,将该页面发布到它所在服务器上的cmscli