Springboot 整合Elasticsearch

Elasticsearch的安装和使用

下载Elasticsearch6.2.2的zip包,并解压到指定目录,下载地址:
https://www.elastic.co/cn/downloads/past-releases/elasticsearch-6-2-2
安装中文分词插件,在elasticsearch-6.2.2\bin目录下执行以下命令:
elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.2.2/elasticsearch-analysis-ik-6.2.2.zip


运行bin目录下的elasticsearch.bat启动Elasticsearch
下载Kibana,作为访问Elasticsearch的客户端,请下载6.2.2版本的zip包,并解压到指定目录,下载地址:https://artifacts.elastic.co/downloads/kibana/kibana-6.2.2-windows-x86_64.zip
运行bin目录下的kibana.bat,启动Kibana的用户界面


访问http://localhost:5601 即可打开Kibana的用户界面

Get Put命令学习参考
https://www.xugj520.cn/archives/exploring_cluster.html

Springboot 整合Elasticsearch

版本参考
版本对应很重要 我的是

springboot 2.1.3.RELEASE
es 6.2.2
spring data es 3.1.16.RELEASE

在pom.xml中添加相关依赖

        <!--Elasticsearch相关依赖-->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-elasticsearch</artifactId>
            <version>3.1.16.RELEASE</version>
        </dependency>

修改SpringBoot配置文件

修改application.yml文件,在spring节点下添加Elasticsearch相关配置。

# elasticsearch相关配置  .yml全局只能有一个spring注意
spring:
  data:
    elasticsearch:
      cluster-name: elasticsearch # es集群的名称
      cluster-nodes: 127.0.0.1:9300 # 程序连接es的端口号是9300

Model

先写一个的商品实体类,借助这个实体类来完成基础的CRUD功能

package com.wg.biye.wgcore.entity;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.format.annotation.DateTimeFormat;

import java.io.Serializable;
import java.util.Date;

//@Accessors @Data 是lombok的注解
//6.0版本以后,一个index下,只允许创建一个type,不允许存在多个type 并且在官网提供信息,7.0以后不再使用type。
@Data
@Accessors(chain = true)
@Document(indexName = "wgaituwang", type = "product",shards = 1,replicas = 0)//必须小写
public class WgProduct implements Serializable {
    /*
    不需要中文分词的字段设置成@Field(type = FieldType.Keyword)类型,需要中文分词的设置成@Field(analyzer = "ik_max_word",type = FieldType.Text)类型。
    * */
    private static final long serialVersionUID = -1L;

    @Id
    private String id;//必须添加@Id注解,最好为String类型
    @Field(analyzer = "ik_max_word",type = FieldType.Text)//IK分词器
    private String name;//商品名称
    private String productAddress;//商品出产地
    private String keywords;//商品关键字
    @Field(analyzer = "ik_max_word",type = FieldType.Text)
    private String title;//商品标题
    private Double price;//价格
//    private String time;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    private Date time;
    /*
    {
    "id" : "1",
    "name" : "火龙果",
    "productAddress" : "北京天安门",
    "keywords" : "水果",
    "title" : "香甜可口的火龙果",
    "price" : "100",
    "time" : "2020-03-27"
    }
    */
}

常用注解学习

@Document

属性名 类型 含义
indexName String 索引库名字,相当于mysql中数据库的概念
type String 文档类型,mysql中表的概念
shards short 默认分片数 默认值5
replicas short 默认副本数量 默认值1

@Id
可以认为是mysql中表一行的Id概念
@Field

public @interface Field {
  //文档中字段的类型
    FieldType type() default FieldType.Auto;
  //是否建立倒排索引
    boolean index() default true;
  //是否进行存储
    boolean store() default false;
  //分词器名次
    String analyzer() default "";
}

其中字段类型的选项有
//为文档自动指定元数据类型
public enum FieldType {
    Text,//会进行分词并建了索引的字符类型
    Integer,
    Long,
    Date,
    Float,
    Double,
    Boolean,
    Object,
    Auto,//自动判断字段类型
    Nested,//嵌套对象类型
    Ip,
    Attachment,
    Keyword//不会进行分词建立索引的类型
}

创建repository包


创建实体类的接口继承ElasticsearchRepository这样就有基本的CRUD(用过Jpa的就很清楚)

package com.wg.biye.wgcore.repository;

import com.wg.biye.wgcore.entity.WgProduct;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import org.springframework.stereotype.Repository;

@Repository
public interface WgProductRepository extends ElasticsearchRepository<WgProduct, String> {
}

我们就直接实现控制类吧

package com.wg.biye.wgcore.controller;

import com.wg.biye.common.util.ResultUtil;
import com.wg.biye.wgcore.entity.WgProduct;
import com.wg.biye.wgcore.repository.WgProductRepository;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.*;
//需要一个工具将MySQL的数据导入Elasticsearch
//@RestController = @Controller + @ResponseBody组成
@RestController
@RequestMapping("/wgproduct")
public class WgProductController {
    @Autowired
    private WgProductRepository wgProductRepository;

    //@RequestBody学习 : https://blog.csdn.net/justry_deng/article/details/80972817
    @PostMapping("/add")
    public Map<String, Object> add(@RequestBody WgProduct wgProduct) {
        System.out.println(wgProduct.toString());
        System.out.println(wgProduct instanceof  WgProduct);//true
        wgProductRepository.save(wgProduct);
        return ResultUtil.resultCode(200,"添加商品成功"); ResultUtil工具换成自己的就行
    }
    //根据Id查询
    @GetMapping("/get/{id}")
    public Map<String, Object> getById(@PathVariable String id) {
        Map<String,Object> result = new HashMap<>();
        if (StringUtils.isEmpty(id))
            return ResultUtil.resultCode(500,"Id为空");
        //【java8新特性】Optional详解 https://www.jianshu.com/p/d81a5f7c9c4e
        Optional<WgProduct> wgProductOptional = wgProductRepository.findById(id);
        if (wgProductOptional.isPresent()) {//isPresent()方法用于判断包装对象的值是否非空
            WgProduct wgProduct = wgProductOptional.get();
            result.put("商品信息",wgProduct);
            return ResultUtil.resultSuccess(result);
        }
        return ResultUtil.resultError(result);
    }
    //查询所有
    @GetMapping("/getall")
    public Map<String, Object> getAll() {
        Map<String,Object> result = new HashMap<>();
        Iterable<WgProduct> iterable = wgProductRepository.findAll();
        List<WgProduct> list = new ArrayList<>();
        iterable.forEach(list::add);
        result.put("所有商品",list);
        return ResultUtil.resultSuccess(result);
    }
//    根据ID修改
    @PostMapping("/update")
    public Map<String, Object> updateById(@RequestBody WgProduct wgProduct) {
        String id = wgProduct.getId();
        if (StringUtils.isEmpty(id))
            return ResultUtil.resultCode(500,"Id为空");
        wgProductRepository.save(wgProduct);
        return ResultUtil.resultCode(200,"修改商品成功");
    }
//    根据ID删除
    @DeleteMapping("/delete/{id}")
    public Map<String, Object> deleteById(@PathVariable String id) {
        if (StringUtils.isEmpty(id))
            return ResultUtil.resultCode(500,"Id为空");
        wgProductRepository.deleteById(id);
        return ResultUtil.resultCode(200,"删除商品成功");
    }
}

POSTMAN测试

增加


查看

删除

搜索

构造数据 在测试类胡乱写

package com.wg.biye;

import com.wg.biye.wgcore.entity.*;
import com.wg.biye.wgcore.repository.WgProductRepository;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Date;


@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class BiyeApplicationTests {

    @Autowired
    private WgProductRepository wgProductRepository;

    @Test
    public void contextLoads() {
        WgProduct wgProduct = new WgProduct();
        wgProduct.setId("100");
        wgProduct.setTitle("好吃的");
        wgProduct.setProductAddress("北京");
        wgProduct.setPrice(20.0);
        wgProduct.setTime(new Date());
        wgProduct.setKeywords("水果");
        wgProduct.setName("梨");
        wgProductRepository.save(wgProduct);

        wgProduct.setId("101");
        wgProduct.setTitle("好玩的");
        wgProduct.setProductAddress("成都");
        wgProduct.setPrice(20.0);
        wgProduct.setTime(new Date());
        wgProduct.setKeywords("水果");
        wgProduct.setName("梨");
        wgProductRepository.save(wgProduct);

        wgProduct.setId("102");
        wgProduct.setTitle("好喝的");
        wgProduct.setProductAddress("成都");
        wgProduct.setPrice(20.0);
        wgProduct.setTime(new Date());
        wgProduct.setKeywords("饮料");
        wgProduct.setName("梨");
        wgProductRepository.save(wgProduct);

        wgProduct.setId("103");
        wgProduct.setTitle("好玩的");
        wgProduct.setProductAddress("北京");
        wgProduct.setPrice(20.0);
        wgProduct.setTime(new Date());
        wgProduct.setKeywords("玩具");
        wgProduct.setName("梨");
        wgProductRepository.save(wgProduct);

        wgProduct.setId("104");
        wgProduct.setTitle("好吃的");
        wgProduct.setProductAddress("北京");
        wgProduct.setPrice(20.0);
        wgProduct.setTime(new Date());
        wgProduct.setKeywords("水果");
        wgProduct.setName("梨");
        wgProductRepository.save(wgProduct);

        wgProduct.setId("105");
        wgProduct.setTitle("好吃的");
        wgProduct.setProductAddress("成都");
        wgProduct.setPrice(20.0);
        wgProduct.setTime(new Date());
        wgProduct.setKeywords("水果");
        wgProduct.setName("梨");
        wgProductRepository.save(wgProduct);

        wgProduct.setId("106");
        wgProduct.setTitle("好吃的");
        wgProduct.setProductAddress("北京");
        wgProduct.setPrice(20.0);
        wgProduct.setTime(new Date());
        wgProduct.setKeywords("水果");
        wgProduct.setName("梨");
        wgProductRepository.save(wgProduct);
    }
}

查询所有数据

搜索标题中以关键字开头的方法

WgProductRepository.class添加方法
List<WgProduct> findAllByTitleLike(String s);

控制器添加

    @GetMapping("/search/title")
    public Map<String, Object> repSearchTitle(String keyword) {
        if (StringUtils.isEmpty(keyword))
            return ResultUtil.resultCode(500,"条件为空");
        Map<String,Object> result = new HashMap<>();
        List<WgProduct> list = new ArrayList<>();
        list = wgProductRepository.findAByTitleLike(keyword);
        result.put("搜索结果",list);
        return ResultUtil.resultSuccess(result);
    }

搜索结果

{
    "code": 200,
    "搜索结果": [
        {
            "id": "100",
            "name": "梨",
            "productAddress": "北京",
            "keywords": "水果",
            "title": "好吃的",
            "price": 20.0,
            "time": "2020-03-27"
        },
        {
            "id": "104",
            "name": "梨",
            "productAddress": "北京",
            "keywords": "水果",
            "title": "好吃的",
            "price": 20.0,
            "time": "2020-03-27"
        },
        {
            "id": "105",
            "name": "梨",
            "productAddress": "成都",
            "keywords": "水果",
            "title": "好吃的",
            "price": 20.0,
            "time": "2020-03-27"
        },
        {
            "id": "106",
            "name": "梨",
            "productAddress": "北京",
            "keywords": "水果",
            "title": "好吃的",
            "price": 20.0,
            "time": "2020-03-27"
        }
    ],
    "message": "操作成功"
}

更多API请参考

https://docs.spring.io/spring-data/elasticsearch/docs/3.1.16.RELEASE/reference/html/#populator.namespace-dao-config

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335

推荐阅读更多精彩内容