mysql数据迁移到elasticsearch以及elasticsearch的使用

目录

随着物联网平台的不断发展,平台要求接入的模块会越来越多,对应的数据存储也会有不同的变化,对应的架构也会不断地变化。

  • 存在问题,数据量大后,性能很慢
  • 单表 表字段过多

根据数据不断调整架构

第一版:

数据量不大,采用mysql单表,所有的数据都存放到一个表中,操作简单

第二版:

随着业务的发展,单个表可能达到几个百字段,某个通讯模块解析的时候,实际上只有十几个字段,但是,因为表有几百个字段,会造成空间的一个浪费。查询的性能能明显下降。

  • 采用shardingsphere分表方式, 1个月一个表,减少单表的大小
  • 实际上,空间浪费的问题还没有解决

第三版:

第二个版本运行1年后,增加的不同的物联网通讯模块(解析的场景)越来越多,例如,解析天气,解析大气、解析充电桩、解析气候、解析环保等等,导致我们不得不直面空间浪费的问题。

  • 当前版本的缺陷: 空间浪费过多,如果需要增加字段,所有的按月分的表,都需要新增对应模块的新增字段,因为数据偏多,导致新增字段的花费时长过多,再一个就是,无法达到我们物联网设计的最初的一个初衷,就是想尽量少的改动的前提下,兼容所有的通讯数据的接入。

遇到问题,那我们就要解决问题

  • 1、mysql行转列,逻辑太复杂,没有什么用,排除
  • 2、mysql只存基本的数据,设备id、时间、动态的字段都用json存储(mysql也支持按这里面的数据过滤),好像是5.7以后的版本才支持,经过测试,因为存储的是json数据,导致空间比正常的存储,还大个10倍左右,剔除
  • 3、 还有一个同事提议,不同的通讯模块定义一个表,这样就可以减少表的一个浪费,首先,多表数据查询就是一个问题,不同模块不同表分表也是一个问题,随着模块的越来越多,表维护也是一个问题,给用户的权限太大,会影响历史数据的结构,风险过大。所有该方案剔除
  • 4、mysql只存基础数据,其他的详细数据存es, 我身边认识的大部分人同样类似的业务都是采取该方案,下面就得测试一下

安装elasticsearch 版本8.12.2

下载es

D:\system\es\8.12.2\elasticsearch-8.12.2\config\jvm.options

增加一句,解决控制台打印乱码的问题

java 复制代码
-Dfile.encoding=GBK
  • 记住这个账号和密码后面有用 账号elastic 密码6*X_gLqvJ3sK=Wbx=bsd

修改D:\system\es\8.12.2\elasticsearch-8.12.2\config\elasticsearch.yml

  • 设置为false

/bin/elasticsearch.bat 双击这个文件启动,启动后最后这个是账户和密码。

输入https://127.0.0.1:9200/

  • 设置为false后,需要去掉https的s进行访问

kibana安装

kibana下载

  • 注意需要跟es的版本一样,不然会有奇奇怪怪的问题

创建kibana用户

java 复制代码
elasticsearch-reset-password -u kibana_system
  • 因为elastic是 超级用户,无法用这个用户来启动,所以得新创建一个用户
  • 账号kibana_system 密码c2zJWwm20-0TxiiHAsEG

配置

修改配置文件"D:\env\kibana-8.15.0\config\kibana.yml"

将下面对应几个注释取消掉,如果修改的话就顺便改一下~

java 复制代码
server.port: 5601  
server.host: "0.0.0.0"
# 国际化中文
i18n.locale: "zh-CN"
# 配置es集群url
elasticsearch.hosts: ["http://localhost:9200"] 
# 创建连接用户的账号和密码
elasticsearch.username: "kibana_system"
elasticsearch.password: "c2zJWwm20-0TxiiHAsEG"

启动bin下面的kibana.bat脚本

访问localhost:5601

  • 输入上面设置的账号elastic 密码6*X_gLqvJ3sK=Wbx=bsd登录,用新创建的用户会提示权限不够



  • 写DSL发请求

ik分词

8.12.2下载

  • 在es的plugins目录下 ,新创建一个ik目录,把ik分词的压缩包放到该目录下面

进入Kibana界面

java 复制代码
POST _analyze
{
  "text":"华为手机",
  "analyzer":"ik_smart"
}
  • 不用分词,会一个汉字一个词,不太友好
java 复制代码
普通
im_smart
最小颗粒
ik_max_word

分词的拓展以及停用

  • 分词的过程中,会存在一些词汇,例如"的",这个无意义,考虑剔除,可以用来做黑名单,防止一些敏感词出现
  • "欧力给"因为是新的词汇,无法失败,得自己添加
  • D:\system\es\8.12.2\elasticsearch-8.12.2\plugins\ik\config 分词插件目录下IKAnalyzer.cfg.xml
  • ext.dic直接输入"欧力给" 如果存在多个,一直按回车
  • stopword.dic 是停用词的文件,增加一个的

    记得重启es的服务,不然不生效
  • 欧力给变成一个词汇,"得"也被剔除

springboot实战

pom.xml

java 复制代码
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>

application.yml

java 复制代码
elasticsearch:
  port: 9200
  ip: 127.0.0.1
  username: elastic
  password: 6*X_gLqvJ3sK=Wbx=bsd
  • 注意使用自己的es的账号和密码

相关配置

java 复制代码
package com.zyee.iopace.web.entity.es;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
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;

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Document(indexName = "shopping", shards = 3, replicas = 1)
public class Product {
    //必须有 id,这里的 id 是全局唯一的标识,等同于 es 中的"_id"
    @Id
    private Long id;//商品唯一标识

    /**
     * type : 字段数据类型
     * analyzer : 分词器类型
     * index : 是否索引(默认:true)
     * Keyword : 短语,不进行分词
     */
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String title;//商品名称

    @Field(type = FieldType.Keyword)
    private String category;//分类名称

    @Field(type = FieldType.Double)
    private Double price;//商品价格

    @Field(type = FieldType.Keyword, index = false)
    private String images;//图片地址
}



package com.zyee.iopace.web.config.es;

import lombok.Data;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration;

@ConfigurationProperties(prefix = "elasticsearch")
@Configuration
@Data
public class ElasticsearchConfig extends AbstractElasticsearchConfiguration{

    private String ip ;
    private Integer port ;

    private String username;
    private String password;

    //重写父类方法
    @Override
    public RestHighLevelClient elasticsearchClient() {
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));

        RestClientBuilder builder = RestClient.builder(new HttpHost(ip, port));
        builder.setHttpClientConfigCallback(httpClientBuilder -> {
            httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
            return httpClientBuilder;
        });

        RestHighLevelClient restHighLevelClient = new
                RestHighLevelClient(builder);
        return restHighLevelClient;
    }
}


//controller类
    @ApiOperation(value = "测试")
    @GetMapping("/test123")
    public ResponseResult test123() {
        Product product = new Product();
        product.setId(3L);
        product.setTitle("华为手机");
        product.setCategory("手机");
        product.setPrice(2999.0);
        product.setImages("http://www.atguigu/hw.jpg");
        productDao.save(product);
        return ResponseResult.SUCCESS();
    }
  • 插入成功,但是控制台打印报错


    注意重启项目后,再去搜Version,能看到我们部署的版本是8.12.2,但是java引入的是7.12.1所以报错,注意不要直接再外面try catch来判断,这样代码不太友好,要从根本上解决问题,大概率是版本的问题,考虑升级版本

  • 再次确定,注意版本一致性,不然有各种各样的问题
    有点尴尬这里版本不一致,只能降到7.12.1版本

###降低版本7.12.1

java 复制代码
下载7.12.1 es kibara ik
###D:\system\es\7.12.1\elasticsearch-7.12.1\config\elasticsearch.yml 增加如下
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: false

###es得bin下面执行 修改elastic的初始化密码为123456,一直输入123456
/elasticsearch-setup-passwords interactive 
###新增kibana用户kibana_system c2zJWwm20-0TxiiHAsEG

###修改D:\system\es\7.12.1\kibana-7.12.1\config
server.port: 5601  
server.host: "0.0.0.0"
# 国际化中文
i18n.locale: "zh-CN"
# 配置es集群url
elasticsearch.hosts: ["http://localhost:9200"] 
# 创建连接用户的账号和密码
elasticsearch.username: "elastic"
elasticsearch.password: "123456"

#####项目的application.yml配置
elasticsearch:
  port: 9200
  ip: 127.0.0.1
  username: elastic
  password: 123456

框架集成-SpringData-集成测试-文档操作

java 复制代码
import com.lun.dao.ProductDao;
import com.lun.model.Product;
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.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.ArrayList;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringDataESProductDaoTest {

    @Autowired
    private ProductDao productDao;
    /**
     * 新增
     */
    @Test
    public void save(){
        Product product = new Product();
        product.setId(2L);
        product.setTitle("华为手机");
        product.setCategory("手机");
        product.setPrice(2999.0);
        product.setImages("http://www.atguigu/hw.jpg");
        productDao.save(product);
    }
    //POSTMAN, GET http://localhost:9200/product/_doc/2

    //修改
    @Test
    public void update(){
        Product product = new Product();
        product.setId(2L);
        product.setTitle("小米 2 手机");
        product.setCategory("手机");
        product.setPrice(9999.0);
        product.setImages("http://www.atguigu/xm.jpg");
        productDao.save(product);
    }
    //POSTMAN, GET http://localhost:9200/product/_doc/2


    //根据 id 查询
    @Test
    public void findById(){
        Product product = productDao.findById(2L).get();
        System.out.println(product);
    }

    @Test
    public void findAll(){
        Iterable<Product> products = productDao.findAll();
        for (Product product : products) {
            System.out.println(product);
        }
    }

    //删除
    @Test
    public void delete(){
        Product product = new Product();
        product.setId(2L);
        productDao.delete(product);
    }
    //POSTMAN, GET http://localhost:9200/product/_doc/2

    //批量新增
    @Test
    public void saveAll(){
        List<Product> productList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Product product = new Product();
            product.setId(Long.valueOf(i));
            product.setTitle("["+i+"]小米手机");
            product.setCategory("手机");
            product.setPrice(1999.0 + i);
            product.setImages("http://www.atguigu/xm.jpg");
            productList.add(product);
        }
        productDao.saveAll(productList);
    }

    //分页查询
    @Test
    public void findByPageable(){
        //设置排序(排序方式,正序还是倒序,排序的 id)
        Sort sort = Sort.by(Sort.Direction.DESC,"id");
        int currentPage=0;//当前页,第一页从 0 开始, 1 表示第二页
        int pageSize = 5;//每页显示多少条
        //设置查询分页
        PageRequest pageRequest = PageRequest.of(currentPage, pageSize,sort);
        //分页查询
        Page<Product> productPage = productDao.findAll(pageRequest);
        for (Product Product : productPage.getContent()) {
            System.out.println(Product);
        }
    }
}
java 复制代码
import com.lun.dao.ProductDao;
import com.lun.model.Product;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
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.data.domain.PageRequest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringDataESSearchTest {

    @Autowired
    private ProductDao productDao;
    /**
     * term 查询
     * search(termQueryBuilder) 调用搜索方法,参数查询构建器对象
     */
    @Test
    public void termQuery(){
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", "小米");
                Iterable<Product> products = productDao.search(termQueryBuilder);
        for (Product product : products) {
            System.out.println(product);
        }
    }
    /**
     * term 查询加分页
     */
    @Test
    public void termQueryByPage(){
        int currentPage= 0 ;
        int pageSize = 5;
        //设置查询分页
        PageRequest pageRequest = PageRequest.of(currentPage, pageSize);
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", "小米");
                Iterable<Product> products =
                        productDao.search(termQueryBuilder,pageRequest);
        for (Product product : products) {
            System.out.println(product);
        }
    }

}

相关代码调整

java 复制代码
package com.zyee.iopace.web.entity.es;

import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
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 java.io.IOException;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Document(indexName = "test", shards = 3, replicas = 1)
public class Product {
    //必须有 id,这里的 id 是全局唯一的标识,等同于 es 中的"_id"
    @JsonSerialize(using = ToStringSerializer.class)
    @Id
    private Long id;//商品唯一标识

    @Field(type = FieldType.Integer)
    private Integer stationInfoId;

    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
    @Field(type = FieldType.Date)
    private Date reportTime;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    @Field(type = FieldType.Date)
    private Date createTime;

    //里面是json格式 动态的
    @Field(type =  FieldType.Keyword,index = false)
    private String detail;
}
  • 之前mysql的数据以json格式存到detail字段中

  • 经过分析,mysql存6w多条数据大约是60M左右,约大了4倍

到目前为止,已经实现了es动态列的功能

相关推荐
SilentSamsara7 分钟前
RAG 系统入门:LangChain/LlamaIndex + Chroma 向量数据库的检索增强实战
数据库·人工智能·python·青少年编程·langchain
RoboWizard10 分钟前
一块硬盘上架前要闯多少关?
java·服务器·数据库
oyyanghh11 分钟前
从Cursor到TRAE的三周vibe coding体验对比
数据库·oracle
Bert.Cai16 分钟前
Oracle CONCAT函数详解
数据库·oracle
豆豆23 分钟前
2026年如何选择适合自己的网站管理系统?
数据库·cms·wordpress·建站系统·网站管理系统·建站软件·织梦
xuefuhe28 分钟前
MySQL8.4 tar.xz安装
mysql
吴声子夜歌1 小时前
SQL经典实例——检索记录
数据库·sql
黄焖鸡能干四碗1 小时前
软件系统概要设计说明书模版(Word)
大数据·运维·数据库·架构·需求分析
dust_and_stars1 小时前
为什么ubuntu24 snap install code-server 不需要--classic?
网络·数据库
BomanGe21 小时前
NSK W1406FA系列长行程高速精密丝杠技术指南
运维·服务器·数据库·经验分享·规格说明书