SpringBoot整合ElasticSearch起步Demo

正题

 

1.docker部署es

1.1.修改max_map_count

#查看max_map_count的值 默认是65530
cat /proc/sys/vm/max_map_count
#重新设置max_map_count的值
sysctl -w vm.max_map_count=262144

1.2.下载镜像并安装es

#拉取镜像
docker pull elasticsearch:7.7.0

#启动镜像
docker run --name docker_elasticsearch -d -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -e "discovery.type=single-node" -p 9200:9200 -p 9300:9300 elasticsearch:7.7.0

#参数说明
--name表示镜像启动后的容器名称  
-d: 后台运行容器,并返回容器ID;
-e: 指定容器内的环境变量
-p: 指定端口映射,格式为:主机(宿主)端口:容器端口

1.3.访问 http://ip地址:9200,测试能否访问成功,如果出现以下画面则表示访问成功

1.4.安装elasticsearch-head

#拉取镜像
docker pull mobz/elasticsearch-head:5

#创建容器
docker create --name docker_elasticsearch-head -p 9100:9100 mobz/elasticsearch-head:5

#启动容器
docker start docker_elasticsearch-head

1.5.由于elasticsearch-head是访问9100端口后,跳转至9300访问elasticsearch,因此形成跨域请求,所以需要在配置文件中进行配置允许跨域请求

进入docker_elasticsearch容器内部,修改配置文件

docker exec -it docker_elasticsearch /bin/bash

vi config/elasticsearch.yml

#调整配置内容如下

#退出重启
exit
docker restart docker_elasticsearch
cluster.name: "docker-cluster" #设置集群名称,如果要部署es集群,则cluster.name需要一致
network.host: 0.0.0.0 #默认的ip
node.name: node-01 #设置节点名称

#启动允许跨域请求
http.cors.enabled: true
http.cors.allow-origin: "*"

1.6.另外,由于es7增加了请求头严格校验的原因,即使在es创建了index库,输入数据后,但也无法显示出数据,因此需要进入elasticsearch-head容器中进行修改代码

进入elasticsearch-head容器修改vendor.js文件代码如下

docker exec -it docker_elasticsearch-head /bin/bash

vi /usr/src/app/_site/vendor.js

修改js文件中第6886行与7574行,均是将原代码中"application/x-www-form-unlencoded",修改为"application/json;charset=UTF-8"

改完后,退出重启容器

exit()

docker restart docker_elasticsearch-head

1.7.安装ik分词器

由于es中标准的分词器对中文并不友好,每次进行分词查询时,只能基于单个中文进行分词查询;因此一般多为采用ik分词器来进行中文分词查询;

(1)下载ik分词器地址:https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.7.0/elasticsearch-analysis-ik-7.7.0.zip

(2)将ik分词器上传到/tmp目录中

(3)安装ik分词器插件到elasticsearch容器中

#将压缩包移动到容器中
docker cp /tmp/elasticsearch-analysis-ik-7.7.0.zip docker_elasticsearch:/usr/share/elasticsearch/plugins

#进入容器
docker exec -it docker_elasticsearch /bin/bash  

#创建目录
mkdir /usr/share/elasticsearch/plugins/ik

#将文件压缩包移动到ik中
mv /usr/share/elasticsearch/plugins/elasticsearch-analysis-ik-7.7.0.zip /usr/share/elasticsearch/plugins/ik

#进入目录
cd /usr/share/elasticsearch/plugins/ik

#解压
unzip elasticsearch-analysis-ik-7.7.0.zip

#删除压缩包
rm -rf elasticsearch-analysis-ik-7.7.0.zip

#退出重启
exit

docker restart docker_elasticsearch

2.Springboot集成ES的测试Demo

2.1.启动依赖


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.3.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

 2.2.编写配置文件application.yml

spring:
  application:
    name: springboot-es
  elasticsearch:
    rest:
      uris: http://ip:9200  #es服务器地址
server:
  port: 8080

 2.3.编写Bean对象

package com.es.document;

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;

@Data
@Accessors(chain = true)
@Document(indexName = "springboot_es", type = "blogs", shards = 1, replicas = 0, createIndex = true)
public class Blog {

    @Id
    private String id;

    @Field(type = FieldType.Text , analyzer = "ik_smart")
    private String title;

    @Field(type = FieldType.Text , analyzer = "ik_smart")
    private String content;

    @Field(type = FieldType.Text , analyzer = "ik_smart")
    private String author;

    @Field(type = FieldType.Text , analyzer = "ik_smart")
    private String tags;

}

2.4.编写ElasticsearchRepository接口

Repository需要继承ElasticsearchRepository接口,参数<映射对象,主键ID的数据类型>。之后Repository类就可以使用类似JPA的方法操作ElasticSearch数据。

package com.es.repository;

import com.vincent.document.UserDoc;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Component;

/**
 * @author: Vincent
 * @date: 2021/8/12 18:43
 */
@Component
public interface UserRepository extends ElasticsearchRepository<UserDoc , String> {
}

2.5.编写controller

package com.es.controller;

import com.alibaba.fastjson.JSON;
import com.es.document.Blog;
import com.es.repository.BlogRepository;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
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.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class BlogESController {

    private static final String BLOG_INDEX = "springboot_es";
    private static final String BLOG_TYPE = "blogs";

    @Autowired
    private ElasticsearchRestTemplate restTemplate;

    @Autowired
    private BlogRepository blogRepository;

    public boolean isIndexExisted() {
        return restTemplate.indexExists(Blog.class);
    }

    public boolean isIndexExisted(String indexName) {
        return restTemplate.indexExists(indexName);
    }

    public boolean createIndex() {
        return restTemplate.createIndex(Blog.class);
    }

    public boolean deleteIndex() {
        return restTemplate.deleteIndex(Blog.class);
    }

    public String save(Blog blog) {
        blogRepository.save(blog);
        return "Data has bean saved..";
    }

    public String save(List<Blog> blogs) {
        blogRepository.saveAll(blogs);
        return "Data has bean saved..";
    }

    public List<Blog> queryBlogs(String field, String value) {
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(field , value);
        SearchQuery searchQuery = new NativeSearchQuery(matchQueryBuilder);
        return restTemplate.queryForList(searchQuery, Blog.class);
    }

    public AggregatedPage<Blog> queryBlogsPage(String field, String value) {
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(field , value);
        SearchQuery searchQuery = new NativeSearchQuery(matchQueryBuilder).setPageable(PageRequest.of(0,100));

        return restTemplate.queryForPage(searchQuery , Blog.class);
    }

    public void deleteData(String id) {
        blogRepository.deleteById(id);
    }

    public void deleteData(Blog blog) {
        blogRepository.delete(blog);
    }

    /**
     * 根据对象集合,批量删除
     * @param beanList 对象集合
     */
    public void deleteAll(List<Blog> beanList) {
        blogRepository.deleteAll(beanList);
    }

    /**
     * 删除所有
     */
    public void deleteAll() {
        blogRepository.deleteAll();
    }

    /**
     * 根据条件,自定义删除(在setQuery中的条件,可以根据需求自由拼接各种参数,与查询方法一样)
     */
    public void delete(String field, String value) {
        DeleteQuery deleteQuery = new DeleteQuery();
        deleteQuery.setIndex(BLOG_INDEX);
        deleteQuery.setType(BLOG_TYPE);//建index没配置就是类名全小写
        deleteQuery.setQuery(new BoolQueryBuilder().must(QueryBuilders.termQuery(field,value)));
        restTemplate.delete(deleteQuery);
    }
    /**
     * 修改数据
     */
    public void update(Blog blog) {
        UpdateRequest updateRequest = new UpdateRequest();
        updateRequest.retryOnConflict(1);//冲突重试
        updateRequest.doc(JSON.toJSONString(blog), XContentType.JSON);
        updateRequest.routing(blog.getId());//默认是_id来路由的,用来路由到不同的shard,会对这个值做hash,然后映射到shard。所以分片
        UpdateQuery query = new UpdateQueryBuilder().withIndexName(BLOG_INDEX).withType(BLOG_TYPE).withId(blog.getId())
                .withDoUpsert(false)//不加默认false。true表示更新时不存在就插入
                .withClass(Blog.class).withUpdateRequest(updateRequest).build();
        UpdateResponse updateResponse = restTemplate.update(query);
    }

}

2.6.编写测试代码

package com.es.controller;

import com.es.document.Blog;
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.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.test.context.junit4.SpringRunner;

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

import static org.junit.Assert.*;

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

    @Autowired
    private BlogESController blogESController;

    @Test
    public void isIndexExisted() {
        System.out.println(blogESController.isIndexExisted("springboot_es"));
    }

    @Test
    public void createIndex() {
        System.out.println(blogESController.createIndex());
    }

    @Test
    public void deleteIndex() {
        System.out.println(blogESController.deleteIndex());
    }

    @Test
    public void save() {
        Blog blog = new Blog();
        blog.setId("4");
        blog.setTitle("刘德华贼帅!");
        blog.setContent("刘德华演《扫毒2》贼帅!");
        blog.setAuthor("刘德华");
        blog.setTags("扫毒");

        System.out.println(blogESController.save(blog));
    }

    @Test
    public void testBlogs() {
        List<Blog> blogs = new ArrayList<>();

        Blog blog1 = new Blog();
        blog1.setId("1");
        blog1.setTitle("甄子丹贼能打!");
        blog1.setContent("甄子丹演的《叶问》贼能打!");
        blog1.setAuthor("甄子丹");
        blog1.setTags("叶师傅");

        Blog blog2 = new Blog();
        blog2.setId("2");
        blog2.setTitle("谢霆锋贼酷!");
        blog2.setContent("谢霆锋演《怒火》贼酷!");
        blog2.setAuthor("谢霆锋");
        blog2.setTags("怒火");

        Blog blog3 = new Blog();
        blog3.setId("3");
        blog3.setTitle("刘德华唱歌贼好听!");
        blog3.setContent("刘德华唱《17岁》贼好听!");
        blog3.setAuthor("刘德华");
        blog3.setTags("17岁");

        blogs.add(blog1);
        blogs.add(blog2);
        blogs.add(blog3);

        blogESController.save(blogs);

    }

    @Test
    public void queryBlogsByTitle() {
        String field = "title";
        List<Blog> blogs = blogESController.queryBlogs(field, "刘德华");
        System.out.println(blogs);
    }

    @Test
    public void queryBlogsByContext() {
        String field = "content";
        List<Blog> blogs = blogESController.queryBlogs(field, "谢霆锋");
        System.out.println(blogs);
    }
    @Test
    public void queryBlogsPage() {
        String field = "content";
        AggregatedPage<Blog> blogsPage = blogESController.queryBlogsPage(field, "叶师傅");
        System.out.println(blogsPage.getTotalPages());
        System.out.println(blogsPage.getSize());
        System.out.println(blogsPage.toList());
    }

    @Test
    public void deleteDataByID() {
        blogESController.deleteData("RM6dPXsBiYV4G04s3J-4");
    }

    @Test
    public void deleteDataByBean() {

        Blog blog = new Blog();
        blog.setTitle("刘德华贼帅!");
        blog.setId("4");
        //实际上还是需要id:java.lang.IllegalArgumentException: Cannot delete entity with id 'null'.
        blogESController.deleteData(blog);
    }

    @Test
    public void deleteAll() {

        List<Blog> blogs = new ArrayList<>();

        Blog blog1 = new Blog();
        blog1.setId("1");
        blog1.setTitle("甄子丹贼能打!");

        Blog blog2 = new Blog();
        blog2.setId("2");
        blog2.setTitle("谢霆锋贼酷!");

        Blog blog3 = new Blog();
        blog3.setId("3");
        blog3.setTitle("刘德华唱歌贼好听!");

        blogs.add(blog1);
        blogs.add(blog2);
        blogs.add(blog3);

        blogESController.deleteAll(blogs);
    }

    @Test
    public void testDeleteAll() {
        blogESController.deleteAll();
    }

    @Test
    public void delete() {
        String field = "title";
        blogESController.delete(field, "贼");
    }

    @Test
    public void update() {

        Blog blog3 = new Blog();
        blog3.setId("3");
        blog3.setTitle("刘德华唱歌贼好听!");
        blog3.setContent("刘德华唱《中国人》贼好听!");
        blog3.setAuthor("刘德华");
        blog3.setTags("唱歌");

        blogESController.update(blog3);
    }
}

参考资料

docker部署ElasticSearch:https://blog.csdn.net/qq_40942490/article/details/111594267

springboot集成es测试Demo:https://mp.csdn.net/mp_blog/creation/editor

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值