• Elasticsearch在springcloud项目中同步数据的运用


    一,ES的基本概念

    1.什么是全文搜索引擎:

    我们搜索时按结构化的拼音搜到读音,然后按其指向的页数,便可找到我们的非结构化数据——也即对字的解释。这种先建立索引,再对索引进行搜索的过程就叫全文检索(Full-text Search)。

    代表就是lucence。Lucene是根据关健字来搜索的文本搜索工具,只能在某个网站内部搜索文本内容,不能跨网站搜索。

    对lucence进行简化可以采用ES,ES是面向文档的(document oriented)的,对文档(注意不是成行成列的数据)进行索引,搜索,排序,过滤。

    对比着传统mysql的概念理解

    database对应indexes索引,

    table对应types类型,

    rows对应doucment文档,

    column对应field字段。

    创建,删除索引,创建映射,增删改查文档。

    查文档分为带分词器的query string查询和不带索引的term查询。

    二,前期准备

    安装Elasticsearch,头信息,ik分词器。

    创建索引库xccourse

    创建映射

    三,logstash将mysql数据库中的内容同步到ES索引库中的

    课程系统远程通过feign调用CMS内容管理系统,并在课程系统中完成发布,并页面保存到本地,,同时将信息保存在coursepub中,完成课程发布。

    基于logstash同步mysql数据库中coursepub表的信息到es后台,可以在ES后台“数据浏览”看到与coursepub完全一致的内容。

    配置文件mysql.config

     1 input {
     2   stdin {
     3   }
     4   jdbc {
     5   jdbc_connection_string => "jdbc:mysql://localhost:3306/xc_course?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC"
     6   # the user we wish to excute our statement as
     7   jdbc_user => "root"
     8   jdbc_password => root
     9   # the path to our downloaded jdbc driver  
    10   jdbc_driver_library => "E:/soft/apache-maven-3.3.9/repository/mysql/mysql-connector-java/5.1.36/mysql-connector-java-5.1.36.jar"
    11   # the name of the driver class for mysql
    12   jdbc_driver_class => "com.mysql.jdbc.Driver"
    13   jdbc_paging_enabled => "true"
    14   jdbc_page_size => "50000"
    15   #要执行的sql文件
    16   #statement_filepath => "/conf/course.sql"
    17   statement => "select * from course_pub where timestamp > date_add(:sql_last_value,INTERVAL 8 HOUR)"
    18   #定时配置
    19   schedule => "* * * * *"
    20   record_last_run => true
    21   last_run_metadata_path => "‪E:/xuecheng/es/logstash-6.2.1/config/logstash_metadata"
    22   }
    23 }
    24 
    25 
    26 output {
    27   elasticsearch {
    28   #ES的ip地址和端口
    29   hosts => "localhost:9200"
    30   #hosts => ["localhost:9200","localhost:9202","localhost:9203"]
    31   #ES索引库名称
    32   index => "xc_course"
    33   document_id => "%{id}"
    34   document_type => "doc"
    35   template =>"E:/xuecheng/es/logstash-6.2.1/config/xc_course_template.json"
    36   template_name =>"xc_course"
    37   template_overwrite =>"true"
    38   }
    39   stdout {
    40  #日志输出
    41   codec => json_lines
    42   }
    43 }
    21行的logstash_metadata文件
    --- 2018-06-30 11:26:00.150000000 Z

    启动logstash

    数据浏览显示mysql的数据。

    四,搜索微服务普通分级搜索和按照关键字查询,以及按照分类等级查询,按照分页查询

    配置类

     ElasticsearchConfig
     1 import org.apache.http.HttpHost;
     2 import org.elasticsearch.client.RestClient;
     3 import org.elasticsearch.client.RestHighLevelClient;
     4 import org.springframework.beans.factory.annotation.Value;
     5 import org.springframework.context.annotation.Bean;
     6 import org.springframework.context.annotation.Configuration;
     7 
     8 /**
     9  * @author Administrator
    10  * @version 1.0
    11  **/
    12 @Configuration
    13 public class ElasticsearchConfig {
    14 
    15     @Value("${xuecheng.elasticsearch.hostlist}")
    16     private String hostlist;
    17 
    18     @Bean
    19     public RestHighLevelClient restHighLevelClient(){
    20         //解析hostlist配置信息
    21         String[] split = hostlist.split(",");
    22         //创建HttpHost数组,其中存放es主机和端口的配置信息
    23         HttpHost[] httpHostArray = new HttpHost[split.length];
    24         for(int i=0;i<split.length;i++){
    25             String item = split[i];
    26             httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), "http");
    27         }
    28         //创建RestHighLevelClient客户端
    29         return new RestHighLevelClient(RestClient.builder(httpHostArray));
    30     }
    31 
    32     //项目主要使用RestHighLevelClient,对于低级的客户端暂时不用
    33     @Bean
    34     public RestClient restClient(){
    35         //解析hostlist配置信息
    36         String[] split = hostlist.split(",");
    37         //创建HttpHost数组,其中存放es主机和端口的配置信息
    38         HttpHost[] httpHostArray = new HttpHost[split.length];
    39         for(int i=0;i<split.length;i++){
    40             String item = split[i];
    41             httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), "http");
    42         }
    43         return RestClient.builder(httpHostArray).build();
    44     }
    45 
    46 }

    api

     8 @Api(value = "课程搜索",description = "课程搜索",tags = {"课程搜索"})
     9 public interface EsCourseControllerApi {
    10 
    11     @ApiOperation("课程搜索")
    12    QueryResponseResult<CoursePub> searchCourse(int page, int size, CourseSearchParam courseSearchParam);
    13 
    14 }

    controller

     1 @RestController
     2 @RequestMapping("/search/course")
     3 public class EsCourseController implements EsCourseControllerApi {
     4 
     5     @Autowired
     6     private CourseSearchService courseSearchService;
     7 
     8 
     9     @Override
    10     @GetMapping("/list/{page}/{size}")
    11     public QueryResponseResult<CoursePub> searchCourse(@PathVariable("page") int page, @PathVariable("size")int size, CourseSearchParam courseSearchParam) {
    12         return courseSearchService.searchCourse(page,size,courseSearchParam);
    13     }
    14 }

    yml

     1 server:
     2   port: ${port:40100}
     3 spring:
     4   application:
     5     name: xc-search-service
     6 xc:
     7   elasticsearch:
     8     hostlist: ${eshostlist:127.0.0.1:9200} #多个结点中间用逗号分隔
     9     course:
    10       index: xc_course
    11       type: doc

    service

      1 import com.xuecheng.filesystem.framework.domain.course.response.CoursePub;
      2 import com.xuecheng.filesystem.framework.domain.search.CourseSearchParam;
      3 import com.xuecheng.filesystem.framework.model.response.CommonCode;
      4 import com.xuecheng.filesystem.framework.model.response.QueryResponseResult;
      5 import com.xuecheng.filesystem.framework.model.response.QueryResult;
      6 import org.apache.commons.lang3.StringUtils;
      7 import org.elasticsearch.action.search.SearchRequest;
      8 import org.elasticsearch.action.search.SearchResponse;
      9 import org.elasticsearch.client.RestHighLevelClient;
     10 import org.elasticsearch.common.text.Text;
     11 import org.elasticsearch.index.query.BoolQueryBuilder;
     12 import org.elasticsearch.index.query.MultiMatchQueryBuilder;
     13 import org.elasticsearch.index.query.QueryBuilders;
     14 import org.elasticsearch.search.SearchHit;
     15 import org.elasticsearch.search.SearchHits;
     16 import org.elasticsearch.search.builder.SearchSourceBuilder;
     17 import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
     18 import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
     19 import org.springframework.beans.factory.annotation.Autowired;
     20 import org.springframework.beans.factory.annotation.Value;
     21 import org.springframework.stereotype.Service;
     22 
     23 import java.io.IOException;
     24 import java.util.ArrayList;
     25 import java.util.List;
     26 import java.util.Map;
     27 
     28 @Service
     29 public class CourseSearchService {
     30 
     31     @Autowired
     32     private RestHighLevelClient restHighLevelClient;
     33 
     34     @Value("${xuecheng.elasticsearch.course.index}")
     35     private String index;
     36 
     37     @Value("${xuecheng.elasticsearch.course.type}")
     38     private String type;
     39 
     40     /**
     41      * 课程搜索
     42      * 关键字查询
     43      * 一级分类,二级分类,难度等级
     44      * 分页查询
     45      * 高亮查询
     46      * @param page
     47      * @param size
     48      * @param courseSearchParam
     49      * @return
     50      */
     51     public QueryResponseResult<CoursePub> searchCourse(int page, int size, CourseSearchParam courseSearchParam) {
     52 
     53         SearchRequest searchRequest = new SearchRequest(index);
     54         searchRequest.types(type);
     55 
     56         SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
     57 
     58         //boolQueryBuilder  must  C1  C2 C1 AND C2        or  C1 OR C2
     59         BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
     60 
     61         //按照关键字查询
     62         if (StringUtils.isNotEmpty(courseSearchParam.getKeyword())){
     63 
     64             MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(courseSearchParam.getKeyword(), "name", "description", "teachplan");
     65             //查询权重
     66             multiMatchQueryBuilder.field("name",10);
     67             multiMatchQueryBuilder.minimumShouldMatch("70%");
     68 
     69             boolQueryBuilder.must(multiMatchQueryBuilder);
     70         }
     71 
     72         //过滤查询&等值查询
     73         //一级分类查询
     74         if (StringUtils.isNotEmpty(courseSearchParam.getMt())){
     75             boolQueryBuilder.filter(QueryBuilders.termQuery("mt",courseSearchParam.getMt()));
     76         }
     77 
     78         //二级分类查询
     79         if (StringUtils.isNotEmpty(courseSearchParam.getSt())){
     80             boolQueryBuilder.filter(QueryBuilders.termQuery("st",courseSearchParam.getSt()));
     81         }
     82 
     83         //难度等级查询
     84         if (StringUtils.isNotEmpty(courseSearchParam.getGrade())){
     85             boolQueryBuilder.filter(QueryBuilders.termQuery("grade",courseSearchParam.getGrade()));
     86         }
     87 
     88         //分页查询
     89         if (page <=0){ //当前页
     90             page =1;
     91         }
     92         if (size <= 0 ){
     93             size = 10;
     94         }
     95 
     96         int start = (page-1)*size;
     97         //从哪开始查
     98         sourceBuilder.from(start);
     99         //每页显示多少
    100         sourceBuilder.size(size);
    101 
    102         //高亮查询
    103         HighlightBuilder highlightBuilder = new HighlightBuilder();
    104         //高亮前缀
    105         highlightBuilder.preTags("<font class='eslight'>");
    106         //高亮后缀
    107         highlightBuilder.postTags("</font>");
    108         //高亮域
    109         highlightBuilder.fields().add(new HighlightBuilder.Field("name"));
    110         sourceBuilder.highlighter(highlightBuilder);
    111 
    112 
    113         sourceBuilder.query(boolQueryBuilder);
    114 
    115         searchRequest.source(sourceBuilder);
    116 
    117         SearchResponse searchResponse = null;
    118         try {
    119             searchResponse = restHighLevelClient.search(searchRequest);
    120         } catch (IOException e) {
    121             e.printStackTrace();
    122         }
    123         //获取查询结果
    124         SearchHits hits = searchResponse.getHits();
    125         SearchHit[] searchHits = hits.getHits();
    126 
    127         List<CoursePub> coursePubList = new ArrayList<>();
    128 
    129         for (SearchHit searchHit : searchHits) {
    130 
    131             Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
    132             CoursePub coursePub = new CoursePub();
    133 
    134             String id = (String) sourceAsMap.get("id");
    135             coursePub.setId(id);
    136 
    137             //名称
    138             String name = (String) sourceAsMap.get("name");
    139             //获取高亮
    140             Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
    141             if (highlightFields != null){
    142                 HighlightField highlightField = highlightFields.get("name");
    143                 if (highlightField != null){
    144                     Text[] fragments = highlightField.fragments();
    145                     if (fragments !=null){
    146                         StringBuffer stringBuffer = new StringBuffer();
    147                         for (Text fragment : fragments) {
    148                             stringBuffer.append(fragment);
    149                         }
    150                         name = stringBuffer.toString();
    151                     }
    152                 }
    153                 coursePub.setName(name);
    154             }
    155 
    156 
    157             //图片
    158             String pic = (String) sourceAsMap.get("pic");
    159             coursePub.setPic(pic);
    160 
    161             //价格
    162             Float price = null;
    163             if (sourceAsMap.get("price") != null){
    164                 price = Float.parseFloat(String.valueOf(sourceAsMap.get("price")));
    165             }
    166             coursePub.setPrice(price);
    167 
    168             //原价
    169             Float price_old = null;
    170             if (sourceAsMap.get("price_old")!=null){
    171                 price_old = Float.parseFloat(String.valueOf(sourceAsMap.get("price_old")));
    172             }
    173             coursePub.setPrice_old(price_old);
    174 
    175             coursePubList.add(coursePub);
    176 
    177         }
    178 
    179         //数据封装
    180         QueryResult queryResult = new QueryResult();
    181         queryResult.setTotal(hits.getTotalHits());
    182         queryResult.setList(coursePubList);
    183         return new QueryResponseResult<CoursePub>(CommonCode.SUCCESS,queryResult);
    184     }
    185 }

    nginx代理转发,用户请求/course/search的nginx将请求转发给nuxt。js服务。nginx在转发时根据每台nuxt服务器的负载情况进行转发,实现负载均衡

    最后实现走进‘’‘课程搜索’可以进行关键字查询并对关键字实现高亮显示,并采用二级联动实现分级。

    当一个男人不再对你啰嗦,不再缠着你,不再没事找你,对你说话也客气了,也不再气你了。那么恭喜你,你已经成功的失去了他。别嫌弃男人幼稚,那是他喜欢你,爱你。女人说男人像小孩子一样不成熟,可又有谁知道,男人在自己喜欢的女人面前才像小孩子,如果不喜欢你了,不爱你了,他比你爸还成熟。
  • 相关阅读:
    依赖倒置原则(Dependency Inversion Principle)
    里氏替换原则(Liskov Substitution Principle)
    vue.js如何在标签属性中插入变量参数
    SpringBoot解决ajax跨域问题
    WebBrowser(IE) 与 JS 相互调用
    WebBrowser引用IE版本问题,更改使用高版本IE
    win10下端口被占用解决办法
    vim撤销undo与反撤销redo
    centos 安装sbt
    idea中使用scala运行spark出现Exception in thread "main" java.lang.NoClassDefFoundError: scala/collection/GenTraversableOnce$class
  • 原文地址:https://www.cnblogs.com/fengtangjiang/p/11127606.html
Copyright © 2020-2023  润新知