學成在線(第11天)

 課程搜索需求分析

 需求分析

一、根據分類搜索課程信息。
二、根據關鍵字搜索課程信息,搜索方式爲全文檢索,關鍵字須要匹配課程的名稱、 課程內容。
三、根據難度等級搜索課程。
四、搜索結點分頁顯示。前端

 搜索流程

一、課程管理服務將數據寫到MySQL數據庫
二、使用Logstash將MySQL數據庫中的數據寫到ES的索引庫。
三、用戶在前端搜索課程信息,請求到搜索服務。
四、搜索服務請求ES搜索課程信息。java

課程索引

如何維護課程索引信息?
一、當課程向MySQL添加後同時將課程信息添加到索引庫。
採用Logstach實現,Logstach會從MySQL中將數據採集到ES索引庫。
二、當課程在MySQL更新信息後同時更新該課程在索引庫的信息。
採用Logstach實現。
三、當課程在MySQL刪除後同時將該課程從索引庫刪除。
手工寫程序實現,在刪除課程後將索引庫中該課程信息刪除。node

準備課程索引信息

課程發佈成功在MySQL數據庫存儲課程發佈信息,此信息做爲課程索引信息。mysql

建立課程發佈表

課程信息分佈在course_base、course_pic等不一樣的表中。
課程發佈成功爲了方便進行索引將這幾張表的數據合併在一張表中,做爲課程發佈信息。
建立course_pub表sql

建立課程發佈表模型

在課程管理服務建立模型:數據庫

@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;//課程發佈時間
}
View Code

 修改課程發佈

在課程管理服務定義dao:
1)建立course_pub表的daojson

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

2) 修改課程發佈serviceapp

 //保存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;
    }
View Code

修改課程發佈方法,添加調用saveCoursePub方法的代碼,添加部分的代碼以下:elasticsearch

//課程發佈
    @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並啓動。ide

建立索引庫

建立索引庫
建立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
  }
}

說明:
一、ES採用UTC時區問題
ES採用UTC 時區,比北京時間早8小時,因此ES讀取數據時讓最後更新時間加8小時
where timestamp > date_add(:sql_last_value,INTERVAL 8 HOUR)
二、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的能力。

相關文章
相關標籤/搜索