spirngboot集成elasticsearch

这篇文章同样可以在我自搭的小博客里看到:https://spzgczyj.top/blog/article.html?articleId=310

准备环节

第一步:在pom.xml中引入elasticsearch的依赖

<dependency>
     <groupId>org.elasticsearch.client</groupId>
     <artifactId>transport</artifactId>
     <version>${elasticsearch.version}</version>
</dependency>

<!--elasticsearch依赖log4j,这里版本需要小于等于2.7-->
<dependency>
     <groupId>org.apache.logging.log4j</groupId>
     <artifactId>log4j-core</artifactId>
     <version>2.7</version>
</dependency>

第二步:覆盖springboot给我们提供的默认版本的es,我这里用的es是6.3.2,所以这里的es版本我指定成6.3.2

<properties>
   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
   <java.version>1.8</java.version>
   <!--覆盖springboot默认版本的elasticsearch-->
   <elasticsearch.version>6.3.2</elasticsearch.version>
   <!--<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
   <thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>-->
</properties>

第三步:编写配置类:

package com.gkd.blog.config;

import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @author :zhaoyijie(Aquarius_genius)水瓶座鬼才
 * @create :2020/1/25 13:01
 * @Email   : 747897928@qq.com
 */
@Configuration
public class ESConfig {
    @Bean
    public TransportClient client() throws UnknownHostException {
        TransportAddress node=new TransportAddress(InetAddress.getByName("localhost"),9300);
        //集群名blog
        Settings settings = Settings.builder().put("cluster.name","blog").build();
        TransportClient client=new PreBuiltTransportClient(settings);
        //这里可以addTransportAddress(node)多个节点
        client.addTransportAddress(node);
        System.out.println(client);
        return client;
    }
}

说明:不同版本的可能会不同:5.5.2版本用InetSocketTransportAddress,6.3.2版本用TransportAddress。这里端口用9300,ES Rest API端口9200,项目需要用tcp协议去和es通信 ,ES默认tcp端口9300,默认cluster-name my-application。这里要特别说明,实际开发不是这样子写的,因为这样子写配置文件需要改es的yml文件,详情看我的另外一篇文章:elasticsearch报错解决办法:NoNodeAvailableException[None of the configured nodes are available。但是我们只是简单实现,简单写也是可以的,因为我们的目的就一个,快速查询出匹配的文章就行了,我这里做的是快速查询出匹配的文章。

 

第四步:编写实体类

package com.gkd.blog.entity;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.lang.NonNull;

import java.util.Date;

/**
 * @author :zhaoyijie(Aquarius_genius)水瓶座鬼才
 * @create :2020/1/5 15:12
 * @Email   : 747897928@qq.com
 */
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Article {
    private Integer id;//文章id
    @NonNull
    private String title;//文章标题
    @NonNull
    private String content;//文章内容
    @NonNull
    private String articleClassify;//文章类别
    //写成long时间戳,避免ios里的js日期格式不兼容的情况发生
    @JsonFormat(shape = JsonFormat.Shape.NUMBER)
    private Date addTime;//文章加入时间
    private Integer viewCount;//文章浏览量
    private Integer sumComment;//总评论
    private Integer supportCount;//总点赞数
}

第五步:编写控制器类

package com.gkd.blog.controller;

import com.gkd.blog.util.EsUtils;
import org.elasticsearch.client.transport.TransportClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author :zhaoyijie(Aquarius_genius)水瓶座鬼才
 * @create :2020/1/25 13:27
 * @Email   : 747897928@qq.com
 * @Description :
 */
@RestController
public class elasticsearchController {
    @Autowired
    TransportClient client;

    /**
    * @Description: 跟据关键字查找符合条件的数据,只跟文章标题,内容,文章分类比较
    * @Param: [keyword] 查询关键字
    * @return: org.springframework.http.ResponseEntity
    */
    @PostMapping("query/blog/article")
    @ResponseBody
    public ResponseEntity query(@RequestParam(name = "keyword") String keyword){
        StopWatch watch=new StopWatch();
        watch.start();
        Map<String, Object> map=new HashMap<>();
        List<Map<String, Object>> result = EsUtils.queryShould(keyword, this.client);
        watch.stop();
        map.put("TotalTimeMillis",watch.getTotalTimeMillis());
        map.put("result",result);
        return new ResponseEntity(map, HttpStatus.OK);
    }

}

第六步:编写ESutils类

package com.gkd.blog.util;

import com.gkd.blog.entity.Article;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;

import java.io.IOException;
import java.util.*;

/**
 * @author :zhaoyijie(Aquarius_genius)水瓶座鬼才
 * @create :2020/1/25 14:34
 * @Email   : 747897928@qq.com
 * @Description :
 */
public class EsUtils {

    public static List<Map<String, Object>> queryMust(Article article, TransportClient client) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //must想当于and should相当于or
        boolQuery.must(QueryBuilders.matchQuery("title", article.getTitle()));
        boolQuery.must(QueryBuilders.matchQuery("content", article.getContent()));
        boolQuery.must(QueryBuilders.matchQuery("articleClassify", article.getArticleClassify()));
        SearchRequestBuilder builder = client.prepareSearch("blog").
                setTypes("article").
                setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                .setQuery(boolQuery);
        //System.out.println(builder);
        SearchResponse searchResponse = builder.get();
        List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();

        for (SearchHit hit : searchResponse.getHits()) {
            result.add(hit.getSourceAsMap());
        }
        return result;
    }

    public static List<Map<String, Object>> queryShould(String keyword, TransportClient client) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //must想当于and should相当于or
        boolQuery.should(QueryBuilders.matchQuery("title", keyword));
        boolQuery.should(QueryBuilders.matchQuery("content", keyword));
        boolQuery.should(QueryBuilders.matchQuery("articleClassify", keyword));
        SearchRequestBuilder builder = client.prepareSearch("blog").
                setTypes("article").
                setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                .setQuery(boolQuery);
        //System.out.println(builder);
        SearchResponse searchResponse = builder.get();
        List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();

        for (SearchHit hit : searchResponse.getHits()) {
            result.add(hit.getSourceAsMap());
        }
        return result;
    }

    public static String add(String title, String content, String articleClassify,
                             Date date, TransportClient client) {
        try {
            XContentBuilder xContentBuilder = XContentFactory.
                    jsonBuilder().
                    startObject().
                    field("title", title).
                    field("content", content).
                    field("articleClassify", articleClassify).
                    field("data", date).
                    endObject();
            IndexResponse result = client.prepareIndex("blog", "article").setSource(xContentBuilder).get();
            return result.getId();
        } catch (IOException e) {
            e.printStackTrace();
            return e.getMessage();
        }
    }

    public static String delete(String id, TransportClient client) {
        DeleteResponse deleteResponse = client.prepareDelete("blog", "article", id).get();
        return deleteResponse.getResult().toString();
    }

    public static String update(String id, Article article, TransportClient client) {
        UpdateRequest updateRequest = new UpdateRequest("blog", "article", id);
        try {
            XContentBuilder builder = XContentFactory.jsonBuilder().startObject();
            builder.field("title", article.getTitle());
            builder.field("content", article.getContent());
            builder.field("articleClassify", article.getArticleClassify());
            builder.field("data", article.getAddTime());
            builder.endObject();
            updateRequest.doc(builder);
            UpdateResponse result = client.update(updateRequest).get();
            return result.getResult().toString();
        } catch (Exception e) {
            e.printStackTrace();
            return e.getMessage();
        }
    }
}

说明:虽然上面很多地方写死了,但是我们的需求就是查出索引为blog,type为article下,与搜索关键字匹配的文章,与文章的标题,内容,分类进行匹配,用should,相当于mysql里的or。再次说明一点,如果你要这样子写,你必须去改es里的一个配置文件,详情看我的另外一篇文章:elasticsearch报错解决办法:NoNodeAvailableException[None of the configured nodes are available至于同步嘛,就交给logstash去做,它会每分钟去查mysql然后更新es里的内容,但是这样子坏处也很多,因为一个es部署得1.3G,一个logstash部署得770mb,两个加起来就2G多的运行内存了,所以最后,我们的博客没办法加上es,因为租借的阿里云服务器就2G运行内存.....

最后看看效果,postman查看一下logstash同步后es里的全部数据:

我们通过接口查一下关键词为”恶龙“的文章:

看到TotaltimeMillis,这是我之前在java代码里插入了一个程序执行时间的计时器,看看,我们查询到数据仅仅只需要7ms,这个速度很惊人。

不过这个代码使用了默认的分词器standard,这个分词器会把中文分成一个个单词去匹配,这样子就会出现,你要你文章存在一个与关键字里一个中文字符匹配就会算匹配成功,就是说你本来想要查有关中国人的文章,结果有的文章并没有“中国人”这个词却有“中”或者“国”再或者有"人"这个词,就会算是匹配成功,这显然不是我们想要的结果。但是在这里不做分词器的介绍,如果感兴趣的小伙伴可以去github查看一下es的中文分词插件ik。

下载地址https://github.com/medcl/elasticsearch-analysis-ik/releases?after=v6.4.2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值