正题
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