springBoot+Window下的Elasticsearch实现查询

Posted autonomy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springBoot+Window下的Elasticsearch实现查询相关的知识,希望对你有一定的参考价值。

1.准备好Elasticsearch环境,这里使用的是window版本。

1.从官网下载安装包:https://www.elastic.co/cn/downloads/past-releases/elasticsearch-5-6-16

2.分词器 elasticsearch-analysis-ik:https://github.com/medcl/elasticsearch-analysis-ik/releases/tag/v5.6.16

3.head插件 地址:https://github.com/mobz/elasticsearch-head

  其他环境:node.js环境(可视化运行界面运行需要),jdk8

4. 将下载好的安装包解压,进入bin目录运行elasticsearch.bat即可。(需要jdk8的环境)

  技术图片

 

 

 成功启动后访问:http://localhost:9200/,返回信息:

  技术图片

 

5. 可以通过head插件查看可视化页面。

6. 将head解压到(建议解压到Elasticsearch的统计目录,好找),进入到elasticsearch-head-master即可(需要node.js环境)。

  技术图片

 

 

 7.在此页面数据 grunt server,即可运行。如果提示无法启动。运行命令:npm install -g grunt-cli。

技术图片

 

 

 8.使用可是化界面连接 Elasticsearch 时 需要在Elasticsearch 的配置文件下配置跨域。配置文件位置:elasticsearch-5.6.16configelasticsearch.yml。

  配置内容: http.cors.enabled: true
        http.cors.allow-origin: "*"

  注意:“:” 号后需要加空格

9.访问 http://localhost:9100/.

技术图片

 

 

 

 10,现在的 Elasticsearch 就是一个服务器,并且已有了视化界面,我们可以在可视化界面对他进行操作,但在elasticsearch-head-master上操作它时太过于麻烦。

这里选择postman对他进行操作。在操作之前,先看一下数据库(使用mysql)和索引库之间的关系。深入了解概念可参考:

https://blog.csdn.net/achang07/article/details/79713245

对应关系:

 技术图片

 

 

 11. 首先创建一个索引库,然后在创建一个mapping,或者在创建索引库的同时创建mapping。

  11.1创建索引库

技术图片

 

 

 

   11.2 创建映射

技术图片

 

  查看以下效果

  技术图片

 

 11.3创建索引的同时创建映射

  技术图片

 

 12. 对于elasticsearch的概念暂结束。接下来看后端代码。创建springBoot项目。引入以下依赖。数据库文件

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.57</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

 

13. application.yml配置 

server:
  port: 8888
spring:
  data:
    elasticsearch:
      cluster-nodes: 127.0.0.1:9300
#在这配置数库连接是因为,我会从数据库读取数据到索引库中。
  #如果有其他方式读取数据,一下配配置可以不用写
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/jpa
    username: root
    password: sasa
    driver-class-name: com.mysql.jdbc.Driver
    jpa:
      hibernate:
        ddl-auto: update
      show-sql: true

 

14.在后端使用创建索引库,首先创建相对应过的实体类。

package com.los.es.pojo;

import lombok.Data;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

/**
 * 用于创建索引库,ES
 */

@Data
//indexName 索引库名称,类型名字:goods
@Document(indexName = "tb",type = "goods")
public class Rgoods {

    @Id
    private int cid;

    @Field(type = FieldType.Keyword,index = true,analyzer = "ik_max_word")
    private String name;
    //其他文档数据默认
    private  int isParent;
    private int parentId;
    private int level;
    private String pathId;
    private String path;
}

 

14.创建索引库并存储数据

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.los.es.EsApplication;
import com.los.es.config.ResponseResult;
import com.los.es.pojo.Rgoods;
import com.los.es.repository.GoodsRepository;
import com.los.es.repository.RgoodsRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;

import java.util.List;


@SpringBootTest(classes = EsApplication.class)
public class Init {

    //在导入spring-boot-starter-data-elasticsearch启动器时
    // springboot已经默认配置了这个类
    @Autowired
    private ElasticsearchTemplate template;
    
    //用于调用elasticsearch索引库的接口,如新增,查询,相关代码在后面会贴出来
    @Autowired
    private GoodsRepository goodsRepository;

    //用于操作数据库的接口,相关代码在后面会贴出来
    @Autowired
    private RgoodsRepository rgoodsRepository;

    //创建索引库
    @Test
    public void createIndex(){
        template.createIndex(Rgoods.class);
    }

    //向索引库中填充数据
    @Test
    public void fullData(){
        //使用了Ali的fastJson,将两个类名不一样,但其中的字段名和类型一样的类相互直接赋值
        //因为我需要从数据库将数据读出来,需要建一个实体类对应数据库
        rgoodsRepository.saveAll(JSONObject.parseArray
                (JSON.toJSONString(goodsRepository.findAll()),Rgoods.class));
    }

15.项目结构,该案例使用jpa操作数据库。

技术图片

 

 

 16,Goods实体类

package com.los.es.pojo;

import javax.persistence.*;

@Entity
@Table(name = "wp_ex_source_goods_tb_cat_copy")
public class Goods {

    @Id
    @Column(name = "cid",insertable = false,updatable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int cid;

    @Column(name = "name")
    private String name;

    @Column(name = "is_parent")
    private  int isParent;

    @Column(name = "parent_id")
    private int parentId;

    @Column(name = "level")
    private int level;

    @Column(name = "pathid")
    private String pathId;

    @Column(name = "path")
    private String path;

    public int getCid() {
        return cid;
    }

    public void setCid(int cid) {
        this.cid = cid;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getIsParent() {
        return isParent;
    }

    public void setIsParent(int isParent) {
        this.isParent = isParent;
    }

    public int getParentId() {
        return parentId;
    }

    public void setParentId(int parentId) {
        this.parentId = parentId;
    }

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public String getPathId() {
        return pathId;
    }

    public void setPathId(String pathId) {
        this.pathId = pathId;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

}

 

17.Rgoods

package com.los.es.pojo;

import lombok.Data;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

/**
 * 用于创建索引库,ES
 */

@Data
//indexName 索引库名称,类型名字:goods
@Document(indexName = "tb",type = "goods")
public class Rgoods {

    @Id
    private int cid;

    @Field(type = FieldType.Keyword,index = true,analyzer = "ik_max_word")
    private String name;
    //其他文档数据默认
    private  int isParent;
    private int parentId;
    private int level;
    private String pathId;
    private String path;
}

 

18

.技术图片

 

 19.

技术图片

 

 

20.CorsConfig 配置类

package com.los.es.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {
    // 初始化 CorsConfiguration 对象并设置允许的域名、请求头部信息和请求方式
    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*"); // 1 允许任何域名使用
        corsConfiguration.addAllowedHeader("*"); // 2 允许任何头
        corsConfiguration.addAllowedMethod("*"); // 3 允许任何方法(post、get 等)
        return corsConfiguration;
    }
    /**
     * 创建 CorsFilter 对象
     * @return CorsFilter
     */
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new
                UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig()); //拦截所有请求
        return new CorsFilter(source);
    }
}

21. RequestResult

package com.los.es.config;

public class RequestResult {
    //查询条件
    private String searchKey;
    //当前页
    private Integer page;

    //当前页显示条数
    private Integer size;

    private static final Integer DEFAULT_SIZE = 20;// 每页大小,不从页面接收,而是固定大小
    private static final Integer DEFAULT_PAGE = 1;// 默认页

    public String getSearchKey() {
        return searchKey;
    }

    public void setSearchKey(String searchKey) {
        this.searchKey = searchKey;
    }

    public Integer getPage() {
        if(page == null){
            return DEFAULT_PAGE;
        }
        // 获取页码时做一些校验,不能小于1
        return Math.max(DEFAULT_PAGE, page);
    }

    public void setPage(Integer page) {
        this.page = page;
    }

    public Integer getSize() {
        if(size == null){
            return DEFAULT_SIZE;
        }
        return size;
    }

    public void setSize(Integer size) {
        this.size = size;
    }
}

22. ResponseResult

package com.los.es.config;

import com.los.es.pojo.Rgoods;

import java.util.List;

/**
 * 返回结果
 */
public class ResponseResult {
    private int currentPage;
    private int pageSize;
    private int total;
    private List<Rgoods> rgoods;

    public int getCurrentPage() {
        return currentPage;
    }

    public void setCurrentPage(int currentPage) {
        this.currentPage = currentPage;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }

    public List<Rgoods> getRgoods() {
        return rgoods;
    }

    public void setRgoods(List<Rgoods> rgoods) {
        this.rgoods = rgoods;
    }
    /**
     *
     */
}

23. GoodsService 服务层

package com.los.es.service;

import com.los.es.config.RequestResult;
import com.los.es.config.ResponseResult;
import com.los.es.pojo.Rgoods;
import com.los.es.repository.RgoodsRepository;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

@Service
@Transactional
public class GoodsService {

    @Autowired
    private RgoodsRepository rgoodsRepository;

    @Autowired
    private ElasticsearchTemplate template;


    public ResponseResult findByKey(RequestResult request){
        int page = request.getPage() - 1;
        int size = request.getSize();
        ResponseResult rs = new ResponseResult();
        //自定义查询方法
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //分页
        queryBuilder.withPageable(PageRequest.of(page, size));
        //过滤
        if(!StringUtils.isEmpty(request.getSearchKey())){//条件为空时
            queryBuilder.withQuery(QueryBuilders.matchQuery("name", request.getSearchKey()));
        }
        //查询
        AggregatedPage<Rgoods> rgoods = template.queryForPage(queryBuilder.build(), Rgoods.class);
        //需要显示的数据
        rs.setRgoods( rgoods.getContent());
        rs.setCurrentPage(rgoods.getNumber());
        rs.setTotal((int)rgoods.getTotalElements());
        rs.setPageSize(rgoods.getSize());
        return rs;
    }
}

24. web

package com.los.es.web;

import com.los.es.config.RequestResult;
import com.los.es.config.ResponseResult;
import com.los.es.service.GoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RgoodsController {

    @Autowired
    private GoodsService goodsService;

    @GetMapping("find")
    public ResponseResult find(RequestResult requestResult){
        return goodsService.findByKey(requestResult);
    }
}

 

 25.前端使用比较简陋,使用vue实现。首先创建vue项目,引入ElementUi和axios。单页面就直接贴代码了

<template>
  <div class="hello">
    <input v-on:input="inputFun" placeholder="搜索" type="text" @keyup.enter="searchEnterFun" size="mini" v-model="search">
  
    <el-select
    v-model="value"
    multiple
    filterable
    remote
    reserve-keyword
    placeholder="请输入关键词"
    :remote-method="remoteMethod"
    :loading="loading">
    <el-option
      v-for="item in options"
      :key="item.value"
      :label="item.label"
      :value="item.value">
    </el-option>
  </el-select>
    <el-table v-loading="loading" :data = "tableData" style="width: 100%">
    <el-table-column
      label="level"
      prop="date">
    </el-table-column>
    <el-table-column
      label="Name"
      prop="name">
    </el-table-column>
    <el-table-column
      align="right">
      <template slot="header" slot-scope="scope">
      </template>
    </el-table-column>
  </el-table>
  <!-- 分页 -->
   <el-pagination
            background
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
            :current-page="currentPage"
            :page-sizes="[20, 30, 40, 50]"
            :page-size="pageSize"
            layout="total, sizes, prev, pager, next, jumper"
            :total="total">
    </el-pagination>
  </div>
</template>

<script>
const axios = require("axios");
export default {
  name: ‘HelloWorld‘,
  data () {
    return {
        options: [],
        value: [],
        list: [],
       states: [],
      tishiloading:false,
      loading:false,
       currentPage:0,// 当前页码
       pageSize:0,// 每页大小
       total:0, //总条数  ,以上值在初始化时赋予
       tableData: [],
       search: ‘‘
      }
    },
    created() {
      this.init()
    },
     methods: {
       init: function(h) {
        //alert("初始化信息")
        var app=this;
        var a=h==undefined?app:h
        console.log(‘init‘)
        axios
          .get("http://localhost:8888/find")
          .then(function(response) {
            a.states = response.data.rgoods
            a.list = a.states.map(item => {
            return {
               value: item.name, label: item.name
            };
            });
              a.tableData = response.data.rgoods
              a.total = response.data.total
              a.pageSize = response.data.pageSize
              a.currentPage = response.data.currentPage
            })
          .catch(function(error) {
            console.log(error);
            });
        },

    //但用户输入时触发函数
    inputFun(){
         var vm = this 
          vm.loading = true
    },

       //回车事件
      searchEnterFun(){
        var vm = this 
         axios
           .get("http://localhost:8888/find",{
             params:{
              size:vm.pageSize,
              page:vm.pageNumber,
              searchKey:vm.search
             }
           }).then(function(response){
              vm.tableData = response.data.rgoods
              vm.total = response.data.total
              vm.pageSize = response.data.pageSize
              vm.pageNumber = response.data.pageNumber
              vm.loading =false
           }).catch(function(error){
                console.log(error)
           })
      },

      //长度改变----改变每页显示的条数的时候  自动触发
       handleSizeChange(val){
         var vm = this 
           console.log("长度改变:"+val+"--当前页"+vm.currentPage)
           axios
           .get("http://localhost:8888/find",{
             params:{
              size:val,
              page:vm.pageNumber,
              searchKey:vm.search
             }
           }).then(function(response){
              vm.tableData = response.data.rgoods
              vm.total = response.data.total
              vm.pageSize = response.data.pageSize
           }).catch(function(error){
                console.log(error)
           })
       },

        // 当前改变----当前页码改变之后(上下页),触发这个函数
       handleCurrentChange(val){
           var vm = this
           console.log("当前改变:"+val+"每页显示条数"+vm.pageSize)
            axios
          .get("http://localhost:8888/find",{
            params:{
              page:val,
              size:vm.pageSize,
              searchKey:vm.search
            }
          })
          .then(function(response) { 
              vm.tableData = response.data.rgoods
              vm.total = response.data.pageInfo.total
              vm.pageSize = response.data.pageInfo.pageSize
              vm.currentPage = response.data.currentPage
          })
          .catch(function(error) {
            console.log(error);
            });
        },
       },

}
</script>


<style scoped>

</style>

 

 

以上是关于springBoot+Window下的Elasticsearch实现查询的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot2.x集成分布式搜索引擎Elasticsearch

Elasticsearch7.8.0版本入门——JavaAPI操作(环境准备)

Elasticsearch7.8.0版本入门——JavaAPI操作(环境准备)

SpringBoot目录结构

您可以连接到亚马逊以外的 Amazon ElastiСache Redis 吗?

ElasticSearchRepository和ElasticSearchTemplate的使用