ElasticSearch
一、检索
- 我们的应用经常需要添加检索功能,开源的 ElasticSearch 是目前全文搜索引擎的首选。他可以快速的存储、搜索和分析海量数据。Spring Boot通过整合Spring Data ElasticSearch为我们提供了非常便捷的检索功能支持;
- Elasticsearch是一个分布式搜索服务,提供Restful API,底层基于Lucene,采用多shard(分片)的方式保证数据安全,并且提供自动resharding的功能,github等大型的站点也是采用了ElasticSearch作为其搜索服务,
二、概念
- 以 员工文档 的形式存储为例:一个文档代表一个员工数据。存储数据到 ElasticSearch 的行为叫做 索引 ,但在索引一个文档之前,需要确定将文档存储在哪里。
- 一个 ElasticSearch 集群可以 包含多个 索引 ,相应的每个索引可以包含多个 类型 。 这些不同的类型存储着多个 文档 ,每个文档又有 多个 属性 。
- 类似关系:
索引-数据库
类型-表
文档-表中的记录
属性-列
三、整合 ElasticSearch 测试
3.1 docker 下载 ElasticSearch
- 设置max_map_count不能启动es会启动不起来
# 查看max_map_count的值 默认是65530 cat /proc/sys/vm/max_map_count # 重新设置max_map_count的值 sysctl -w vm.max_map_count=262144
- 下载镜像并运行
docker pull elasticsearch:7.7.0 # 下载 elasticsearch,也可以自定义版本 docker images # 查看下载的镜像 # elasticsearch 默认初始的时候会占用两个G的内存,-e 限制内存的使用,否则会报错, # -d 后台启动,-p 指定端口映射,默认web通信使用的是 9200端口,分布式的情况下是 9300 # 启动镜像 docker run --name elasticsearch -d -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -e "discovery.type=single-node" -p 9200:9200 -p 9300:9300 <IMAGE_ID>
- 浏览器访问 ip:9200
{ "name" : "6ab504425d8f", "cluster_name" : "docker-cluster", "cluster_uuid" : "YYDKqci1TxSLYo--h2Znxg", "version" : { "number" : "7.7.0", "build_flavor" : "default", "build_type" : "docker", "build_hash" : "81a1e9eda8e6183f5237786246f6dced26a10eaf", "build_date" : "2020-05-12T02:01:37.602180Z", "build_snapshot" : false, "lucene_version" : "8.5.1", "minimum_wire_compatibility_version" : "6.8.0", "minimum_index_compatibility_version" : "6.0.0-beta1" }, "tagline" : "You Know, for Search" }
3.2 SpringBoot整合 ES
3.2.1 pom
<!--父模块-->
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>1.5.10.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>utf-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--引入web模块 spring-boot-starter :springboot场景启动器,帮我们导入了web模块正常运行所依赖的 jar包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--单元测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--导入配置文件处理器,配置文件进行绑定就会有提示-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!--es的启动器,SpringBoot默认使用 SpringData ElasticSearch模块进行操作-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
</dependencies>
<!--这个插件,可用将应用打包成一个可执行的 jar包-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
3.2.2 配置原理
- 我们可以在 spring-boot-autoconfigure-1.5.10.RELEASE.jar包中查看
- SpringBoot默认支持两种技术和 ES交互
- Jest(org.springframework.boot.autoconfigure.elasticsearch.jest)
- 默认是不生效了,需要导入 jest的工具包 io.searchbox.client.JestClient)
- SpringData ElasticSearch(org.springframework.boot.autoconfigure.data.elasticsearch)
- Client 节点信息 clusterNodes ;clusterName
- ElasticsearchTemplate 操作 es
- 编写一个 ElasticsearchRepository 的子接口来操作ES
- es版本有可能不合适,如果版本不合适:1. 升级 springboot版本,2. 安装对应的 es
- https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#preface.versions
- Jest(org.springframework.boot.autoconfigure.elasticsearch.jest)
3.3.3 ElasticsearchTemplate 操作 ES
- 这里因为 springBoot的版本过低 1.5.10而spring-data-elasticsearch版本2.1.10
- 需要升级 springboot版本,或者安装对应的 es,这里我们按照对应的 es(2.4.6)
# 在你的 ip:9200 可以看到 cluster_name
spring.data.elasticsearch.cluster-name=elasticsearch
spring.data.elasticsearch.cluster-nodes=ip:9300
@Document(indexName = "atguigu", indexStoreType = "book")
public class Book {
private Integer id;
private String bookName;
private String author;
}
public interface BookRepository extends ElasticsearchRepository<Book, Integer> {
}
@Autowired
BookRepository bookRepository;
@Test
public void testDataES() {
//浏览器访问 ip:9200/atguigu/boot/1
// 官方文档
// https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#repositories.query-methods
bookRepository.index(new Book(1, "大话西游", "jack"));
}
3.3.4 使用 JestClient操作ES
<!--es的启动器,SpringBoot默认使用 SpringData ElasticSearch模块进行操作-->
<!--<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>-->
<!--使用 jest操作 es-->
<!-- https://mvnrepository.com/artifact/io.searchbox/jest -->
<dependency>
<groupId>io.searchbox</groupId>
<artifactId>jest</artifactId>
<version>6.3.1</version>
</dependency>
spring.elasticsearch.jest.uris=http://ip:9200
// 要实现 Serializable 接口
public class Article implements Serializable {
@JestId //标识这是一个 主键
private Integer id;
private String author;
private String title;
private String content;
// 省略 set get 其他
}
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootApplicationESTest {
@Autowired
JestClient jestClient;
@Test
public void testES() {
//1. 给es索引保存一个文档
Article article = new Article(1, "zhangsan", "这是一个好消息", "hellowrod");
// 构建一个索引功能
Index index = new Index.Builder(article).index("atguigu").type("news").build();
try {
// 执行
//浏览器访问 http://ip:9200/atguigu/news/1
//或者 http://ip:9200/_search
jestClient.execute(index);
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void testSearch() {
//{query:{match:{last_name:hello}}}
//查询表达式
String json = "{" + "\"query\"" + ":" + "{" + "\"match\"" + ":" + "{" + "\"author\"" + ":" + "\"zhangsan\"" + "}" + "}" + "}";
//构建搜索功能
Search build = new Search.Builder(json).addIndex("atguigu").addType("news").build();
try {
SearchResult result = jestClient.execute(build);
System.out.println(result.getJsonString());
//{"took":3,"timed_out":false,"_shards":{
// "total":1,"successful":1,"skipped":0,"failed":0},
// "hits":{"total":{"value":1,"relation":"eq"},"max_score":0.2876821,
// "hits":[{"_index":"atguigu","_type":"news","_id":"1","_score":0.2876821,
// "_source":{"id":1,"author":"zhangsan","title":"这是一个好消息","content":"hellowrod"}}]}}
} catch (IOException e) {
e.printStackTrace();
}
}
}